Giter VIP home page Giter VIP logo

near-api-js's Introduction

NEAR JavaScript API

Build Status Gitpod Ready-to-Code

NEAR JavaScript API is a complete library to interact with the NEAR blockchain. You can use it in the browser, or in Node.js runtime.

Documentation

Contribute to this library

  1. Install dependencies

    pnpm install
    
  2. Run continuous build with:

    pnpm -r compile -w
    

Publish

Prepare dist version by running:

pnpm dist

Integration Test

Start the node by following instructions from nearcore, then

pnpm test

Tests use sample contract from near-hello npm package, see https://github.com/nearprotocol/near-hello

Update error schema

Follow next steps:

  1. Change hash for the commit with errors in the nearcore
  2. Fetch new schema: node fetch_error_schema.js
  3. pnpm build to update lib/**.js files

Packages

Package Architecture in Onion Diagram

License

This repository is distributed under the terms of both the MIT license and the Apache License (Version 2.0). See LICENSE and LICENSE-APACHE for details.

near-api-js's People

Contributors

ailisp avatar andy-haynes avatar austinabell avatar bowenwang1996 avatar chadoh avatar denbite avatar dependabot-preview[bot] avatar dependabot[bot] avatar erditkurteshisqa avatar esaminu avatar evgenykuzyakov avatar frol avatar github-actions[bot] avatar gtsonevv avatar gutsyphilip avatar hcho112 avatar ilblackdragon avatar itegulov avatar janedegtiareva avatar lexfro avatar marcinbodnar avatar mattlockyer avatar maximushaximus avatar mehtaphysical avatar mikedotexe avatar morgsmccauley avatar thisisjoshford avatar vgrichina avatar vikinatora avatar volovyks avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

near-api-js's Issues

The error surfaced to user contains [object Object]

For example when tx fails, get an error like this:

Uncaught (in promise) Error: [-32000] Server error: [object Object]
    at JsonRpcProvider.sendJsonRpc (nearlib.js:767)
    at async Account.signAndSendTransaction (nearlib.js:83)
    at async Contract.value [as incrementCounter] (nearlib.js:269)

Loading a contract when logged out + handling logged out flow

If the user is logged out:
near.account() won't work with an empty string
nearlib.Contract() won't work without an account

Thus you can't call contract view functions if the user is not logged in, which isn't good UI (i.e. for guestbook you can't see guestbook entries if you're not logged in).

Desired behavior:
Contract view functions should be able to be called when logged out

Discussion:
Potentially creating some sort of 'read-only' account as a placeholder for guest

confusing account experience: shell to wallet

not sure where to document this exactly, here or nearprotocol/near-shell

i started by creating a new account through NEAR Shell

near create_account sherif3 --masterAccount=sherif

and ended up trying to recover the account via NEAR Wallet and getting [this error](https://github.com/nearprotocol/nearlib/blob/d8b0f397fdf6a0729d293660e3c4dda153ea314e/lib/account.js#L34)

Missing public key for sherif3 in default

Error in background action: BadRequestError: Error: Failed to fetch access key for 'sherif3' with public key ed25519:EsjyvmBb2ESGiyjPHMBUnTGCe1P6hPjmxxY2b2hrTBAv

could mean one of:

  • i'm not supposed to do this [!/images/icons/emoticons/warning.png!| /images/icons/emoticons/warning.png]
  • we need clearer message in NEAR Shell about how to "attach" a created account to your wallet
  • we need clearer message in NEAR Wallet about how to recover accounts created via NEAR Shell

also related to this flow, the error only appeared in the console. no SMS was sent while trying to recover and this error did not appear anywhere in the DOM. generally SMS messages were arriving for another accounts while following the same steps to recover it: sherif2. but that account was originally created via the NEAR Wallet interface on another computer.

Create and sign transactions offline

We need to have an easy way to sign transactions when there is no access to the blockchain from the SDK. For example, by providing the last block hash through API.

misleading error message from Signer

the error message reported in the snippet below would be clearer to me if it read "Missing private key ..." since the signer is failing to fetch a private key from the keystore with signer.getPublicKey
https://github.com/nearprotocol/nearlib/blob/d8b0f397fdf6a0729d293660e3c4dda153ea314e/src.ts/account.ts#L56-L60

is this because i'm still confused about how keys work? it's possible ๐Ÿ˜•

or maybe is "Missing public key ..." somehow the canonical way to report that "a private key was not found locally and so no associated public key could be retrieved" or something?

Polish API surface

  • Way too many boilerplate to connect with default settings / using config file.
  • waitForTransactionResult should be built-in in regular API, is too low-level for most use cases
  • Provide ActiveObject-like API similar to ethersjs?
  • Provide Web3 shim?

Better error reporting

Hard to interpret error messages like:

Error: [-32603] Internal error: Tx (00) not found

key_pair.Signature vs transactions.Signature

There are Signature types right now in nearlib, which should be somehow simplified. It makes documentation about offline signing not very consistent (also transactions.Signature is not exported, but is needed for SignedTransaction construction).

Remove deprecation warning from loadContract

We're showing a deprecation warning for the contract wrapper recommended in the docs.

near.loadContract is deprecated. Use `new nearlib.Contract(yourAccount, contractId, { viewMethods, changeMethods })` instead.

We should either change the example in the docs, or remove the deprecation warning from near.loadContract

Clean-up 'make function calls' test in integration.test.js

@vgrichina commented on Fri Feb 15 2019

Test is currently whole wall of code with few unrelated tests jammed together:

    test('make function calls', async () => {
        const args = {
            'name': 'trex'
        };
        const viewFunctionResult = await nearjs.callViewFunction(
            contractName,
            'hello', // this is the function defined in hello.wasm file that we are calling
            args);
        expect(viewFunctionResult).toEqual('hello trex');

        var setCallValue = await generateUniqueString('setCallPrefix');
        const setArgs = {
            'value': setCallValue
        };
        const scheduleResult = await nearjs.scheduleFunctionCall(
            0,
            aliceAccountName,
            contractName,
            'setValue', // this is the function defined in hello.wasm file that we are calling
            setArgs);
        expect(scheduleResult.hash).not.toBeFalsy();
        await nearjs.waitForTransactionResult(scheduleResult);
        const getValueResult = await nearjs.callViewFunction(
            contractName,
            'getValue', // this is the function defined in hello.wasm file that we are calling
            {});
        expect(getValueResult).toEqual(setCallValue);

        // test that load contract works and we can make calls afterwards
        const options = {
            viewMethods: ['hello', 'getValue'],
            changeMethods: ['setValue'],
            sender: aliceAccountName
        };
        const contract = await nearjs.loadContract(contractName, options);
        const helloResult = await contract.hello(args);
        expect(helloResult).toEqual('hello trex');
        var setCallValue2 = await generateUniqueString('setCallPrefix');
        const setArgs2 = {
            'value': setCallValue2
        };
        const setValueResult = await contract.setValue(setArgs2);
        expect(setValueResult.status).toBe('Completed');
        const getValueResult2 = await contract.getValue();
        expect(getValueResult2).toEqual(setCallValue2);
    });

compare to other tests, e.g.:

    test('can get logs from method result', async () => {
        await contract.generateLogs();
        expect(logs).toEqual([`[${contractName}]: LOG: log1`, `[${contractName}]: LOG: log2`]);
    });

@ilblackdragon commented on Tue Mar 26 2019

@janedegtiareva any update here?

interface inconsistency wrt hashes in connection provider interface

question

why to we sometimes call nearlib methods with a hash as string and other times use a hash as UInt8Array?

detail

JsonRpcProvider has several methods for fetching network info including fetching a block by "id" which can be an integer or hash (as string), a chunk by hash (as string) and transaction by hash (as UInt8Array).

class JsonRpcProvider extends Provider {
  async block(blockId: BlockId): Promise<BlockResult> {}
  async chunk(chunkId: ChunkId): Promise<ChunkResult> {}
  async txStatus(txHash: Uint8Array, accountId: string): Promise<FinalExecutionOutcome> {}
}

sample code that exercises these methods require some inconsistent thinking in terms of the interface and this adds friction to learning

for example,

retrieving a block

// using the previous snippet to pull the latest block hash
let chain = (await near.connection.provider.status()).sync_info
let id = chain.latest_block_hash
// let id = chain.latest_block_height // <-- this also works here

// we can pass the results to the provider.block method
await near.connection.provider.block(id)

retrieving a chunk

// assume here we use the block data above to fetch chunks from the block
// and identify this chunk hash as interesting ...
let hash = "6SrBkhwVLAZC2YQJG3YUSef2UGf7UxwpsLZEY3dsZMKb"
await near.connection.provider.chunk(hash)

--> and here's the inconsistency <--

retrieving a transaction

// assume here we find a transaction in the chunk above that we want to inspect
// but we can't use the txHash directly, we have to decode it
let txHash = "3L37n7LowxfpFEJcQvYmoQPo4NpgV2ZUmr4vXSBYhxPL"
let decodedTxHash = nearlib.utils.serialize.base_decode("3L37n7LowxfpFEJcQvYmoQPo4NpgV2ZUmr4vXSBYhxPL")
await near.connection.provider.txStatus(decodedTxHash, '')

this may be my misunderstanding but why can't we just use the transaction hash here directly? seems like we're just encoding it again inside the implementation (and accountId accepts an empty string so i'm not sure why that's even exposed in this interface)

async txStatus(txHash: Uint8Array, accountId: string): Promise<FinalExecutionOutcome> {
    return this.sendJsonRpc('tx', [base_encode(txHash), accountId]).then(adaptTransactionResult);
}

a naive glance (i don't know Rust) at the nearcore JSON RPC client decodes the transaction hash again (and seems to require the accountId parameter)

async fn tx_status(&self, params: Option<Value>) -> Result<Value, RpcError> {
  let (hash, account_id) = parse_params::<(String, String)>(params)?;
 
  /// @amgando --  this line seems to decode the transaction again
  let tx_hash = from_base_or_parse_err(hash).and_then(|bytes| {
    CryptoHash::try_from(bytes).map_err(|err| RpcError::parse_error(err.to_string()))
  })?;
  let result = self
    .client_addr
    .send(NetworkClientMessages::TxStatus {
      tx_hash,
      signer_account_id: account_id.clone(),  /// @amgando -- not sure why account_id isn't just an empty string here
    })
    .compat()
    .map_err(|err| RpcError::server_error(Some(convert_mailbox_error(err))))
    .await?;
  self.tx_polling(result, tx_hash, account_id).await
}

account.nonce getter

get nonce(): number { return this._accessKey.nonce; }

Something as simple as this would allow the nonce to be retreived from the account object, which would allow some more complex "sign then send" functions

NEAR amounts formatting for corner cases

I would like to bring an issue of presenting NEAR amounts that are small or can be rounded incorrectly.

Here are the test cases:

  • 1 yoctoNEAR is currently formatted as 0 NEAR; There are two better ways to format 1yoctoNEAR (I believe both are useful in different contexts):
    • 1 yoctoNEAR / 1 yN
    • <0.00001 N / "less than 0.00001 N"
  • 999999999999999999999999 yN is rounded to 1 N. It is hard to find the best way to present this value, but here is my take:
    • "almost 1 N"
    • "0.999999 .. 1 N"
    • "1 N without 1 yN" ๐Ÿ˜•

Ref near/near-explorer#152

bs58 should be smarter

    /**
     * Encode a buffer as string using bs58
     * @param {Buffer} buffer 
     * @example
     * KeyPair.encodeBufferInBs58(key.publicKey)
     */
    static encodeBufferInBs58(buffer) {
        const bytes = Buffer.from(buffer);
        const encodedValue = bs58.encode(bytes);
        return encodedValue;
    }

Stuff like this should be inside the bs58.encode() function instead of outside, bs58 should auto determine the type is Buffer or Uint8Array. Maybe use a forked bs58 with this update?

Or get a base58 lib that supports uint8array buffers.

Allow the creation of contracts without any changeMethods

If I load a contract that only has view methods:

const contract = await near.loadContract("hello-world", {
  viewMethods: ["helloWorld"]
});

It fails at runtime as follows:

nearlib.js:265 Uncaught (in promise) TypeError: Cannot read property 'forEach' of undefined
    at new Contract (nearlib.js:265)
    at Near.loadContract (nearlib.js:666)
    at main.js:12

I always have to supply an array of change methods, even if there aren't any, to keep nearlib happy:

const contract = await near.loadContract("hello-world", {
  viewMethods: ["helloWorld"],
  changeMethods: []
});

Could changeMethods default to an empty array if not supplied by the user?

Missing functionality checklist & discussion

Nearlib expected to be used by DApps and DWallets and it functionality should cover:

  • Blockchain structure:
    • Block header by (block.number or block.hash)
    • Shard header by (block and shard.index) or shard.hash
    • Transaction header by (shard and transaction.index) or transaction.hash or account.nonce or address.nonce
    • Transaction header by (shard and transaction.index) or transaction.hash
    • Latest block number
    • Main coin balance
    • Merkle proofs of different structures
  • Account management:
    • Transaction internal and external (hardware wallets) signing
    • Custom message signing similar to EIP-712
  • Smart contract interaction:
    • Calling view methods of smart contract without on-chain tx
    • Creating transactions by forming method call arguments

View function does not work when result is null

Throws an error
SyntaxError: Unexpected end of JSON input
at JSON.parse ()

  at Account.viewFunction (node_modules/nearlib/lib/account.js:140:21)

this is reproducible via running unit tests for template 01 in near studio.

Default amount of gas is too small

The default amount of gas for function call is too small and developers often have to set this value manually. Since the unused gas will be returned it seems reasonable to pass in maximum allowed amount of gas for function calls.

Refactor Nearlib

There are few things we want to improve:

Configuration search:

  • For Node.js use cases, search for .near/ folder with config and keys. Main uses cases:
    • local to project (so go up to folder with node_modules / package.json and check for .near). This can be official TestNet and custom network.
    • running node connected to official TestNet (~/.near/ for configs). Want to use it, but need to use contract helper for account creation.
    • running custom network with local node (~/.near/ for configs). Want to use local key pair for account creation.
  • Create various types of transactions functions that support creating and signing transactions (without having connection).
  • ConnectProvider interface that various providers like RPC, RPCv2, Network, WebSockets can implement (e.g. current NearClient is RPC provider). Provides sendTransaction(txBytes, [timeout]) -> Promise<FinalTransactionResult> and query(path, data) -> Promise<QueryResult> interfaces.
  • AccountCreatorProvider - interface, that either uses helper or given keys to create accounts.
  • connect that is configured / or searches for configuration and uses given ConnectProvider, AccountCreatorProvider and KeyStore.
  • Account abstraction, that provides accessors to account state (balance, etc), access keys (with permissions per key), etc. Allows to initialize Contract with it to send Tx from it.
  • Wallet API is defined via 2 URLs: "Authorize App" API and "Sign Tx" API.
  • Contract handles itself sending to Wallet if currently signed Tx is not allowed by access key or access key is missing.
  • KeyStore should have some form of Wallet to provide what are current accounts available for given network, and allow to change accounts and networks. Also this should use Wallet API to "login" to retrieve current account id if unavailable.

Move out protos from nearcore repo into a separate repo

Protos are part of the specification that different components of the system use.
We should have them in separate repo, that also provides Rust, JS, Python, etc packages that ppl can use without needing to re-build them.

incorrectly named argument throws cryptic error when calling contract

steps to recreate

1. use nearlib to call any contract method with incorrect or non-existent named argument

the error will appear in the client-side JS console

why/where/when did this happen?

this happened by accident while following the [Zero to Hero](https://docs.nearprotocol.com/docs/tutorials/zero-to-hero) tutorial in our docs

 // incorrect (will reproduce this error)
 await contract.setResponse(

 { string: "here we are" } 

)

// vs

// correct (will not produce the error)
 await contract.setResponse(

 { apiResponse: "here we are" } 

)

detail

i think this is the right place to submit this since nearlib could handle this error gracefully but i don't see enough information in the error message to be useful to the developer.

failed transaction on TestNet [here](https://explorer.nearprotocol.com/transactions/9c5JPRgKeAdWrw2GW6YChukDHJUxdSw76AQzfAgoNopV)

this error appears in the

Uncaught (in promise) Error: Transaction 9c5JPRgKeAdWrw2GW6YChukDHJUxdSw76AQzfAgoNopV failed. WebAssembly trap: unknown Error: Transaction 9c5JPRgKeAdWrw2GW6YChukDHJUxdSw76AQzfAgoNopV failed. WebAssembly trap: unknown
at Account.signAndSendTransaction (nearlib.js:97)
at async Contract.value <span class="error">[as setResponse]</span> (nearlib.js:294)
at /app/gbgfhnucs/async <anonymous>:1
TypedError @ nearlib.js:763
signAndSendTransaction @ nearlib.js:97

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.