near-api-js

repository·master·Indexed 19 days ago

https://github.com/near/near-api-js

A comprehensive JavaScript/TypeScript library for interacting with the NEAR Protocol via RPC API. Designed for backend services, CLIs, and scripts, it supports both Node.js and browser environments. Key features include the Account class for state-modifying calls, JsonRpcProvider for read-only interactions, FailoverRpcProvider for high availability, and MultiKeySigner for parallel transactions. The library also provides dedicated modules for Fungible Tokens (FT), Non-Fungible Tokens (NFT), and NEP-413 message signing and verification.

Tokens
31.9K
Snippets
108
Records
144
Agent score
64%

What's inside near-api-js

  1. Overview of near-api-js core abstractions

    master

    The near-api-js library is a backend-focused toolkit for interacting with the NEAR blockchain. Its core functionality is built around several key abstractions:

    • Account: Used to inspect account data and execute on-chain actions.
    • Signers: Responsible for signing transactions and messages.
    • Providers: Used to connect to NEAR nodes via JSON-RPC.
    • KeyPairs: Used to create and manage public/private key pairs.
  2. Update function parameters to use object patterns

    master

    In near-api-js, functions that previously accepted multiple positional arguments have been updated to accept a single object parameter. This change improves clarity and extensibility.

    // Before
    provider.callFunction(accountId, method, args, finality);
    
    // After
    provider.callFunction({ accountId, method, args, finality });
  3. Send parallel transactions using MultiKeySigner

    master

    To increase throughput and avoid nonce collisions, you can send transactions in parallel by rotating multiple keys for a single account.

    1. Generate multiple KeyPairs.
    2. Add these keys to the NEAR account using actions.addFullAccessKey.
    3. Use MultiKeySigner to wrap the keys.
    4. Initialize an Account with the MultiKeySigner instead of a single private key.

    near-api-js automatically handles nonce collisions by retrying with an incremented nonce.

    import { Account, actions, JsonRpcProvider, KeyPair, MultiKeySigner } from "near-api-js"
    import { NEAR } from "near-api-js/tokens"
    
    const provider = new JsonRpcProvider({
      url: "https://test.rpc.fastnear.com",
    })
    
    const accountId = '...';
    const account = new Account(accountId, provider, privateKey)
    
    // create 10 keys and add them to the account
    const keys = []
    const txActions = []
    for (let j = 0; j < 10; j++) {
      const newKeyPair = KeyPair.fromRandom('ed25519')
      keys.push(newKeyPair)
      txActions.push(
        actions.addFullAccessKey(newKeyPair.getPublicKey())
      )
    }
    
    await account.signAndSendTransaction({
      receiverId: accountId,
      actions: txActions
    })
    
    // ------- Send NEAR tokens using multiple keys -------
    const multiKeySigner = new MultiKeySigner(keys)
    const multiAccount = new Account(accountId, provider, multiKeySigner)
    
    const transfers = []
    for (let i = 0; i < 100; i++) {
      transfers.push(
        multiAccount.transfer({
            token: NEAR,
            amount: NEAR.toUnits("0.001"),
            receiverId: "influencer.testnet"
          })
        ))
    }
    
    const sendNearTokensResults = await Promise.all(transfers)
  4. Decouple transaction signing and broadcasting

    master

    For scenarios like offline signing, you can separate the process of building, signing, and sending a transaction.

    1. Build: Use account.createTransaction with only the accountId and publicKey to create a transaction object.
    2. Sign: Use KeyPairSigner.fromSecretKey to sign the transaction with a private key.
    3. Send: Use provider.sendTransaction to broadcast the signed transaction to the network.
    import { JsonRpcProvider, Account, KeyPairSigner, actions, nearToYocto, KeyPairString } from "near-api-js";
    
    const provider = new JsonRpcProvider({
      url: "https://test.rpc.fastnear.com",
    });
    
    const publicKey = '';
    const accountId = '';
    const account = new Account(accountId, provider);
    
    // 1. Create transaction
    const transaction = await account.createTransaction({
      receiverId: "receiver-account.testnet",
      actions: [actions.transfer(nearToYocto("0.1"))],
      publicKey: publicKey
    });
    
    // 2. Sign transaction (offline/separately)
    const signer = KeyPairSigner.fromSecretKey(privateKey as KeyPairString);
    const signResult = await signer.signTransaction(transaction);
    
    // 3. Send transaction
    const sendTransactionResult = await provider.sendTransaction(signResult.signedTransaction);
    console.log(sendTransactionResult);
  5. Migrate from @near-js packages to near-api-js

    master

    If you are migrating from the deprecated @near-js/* packages to near-api-js (v7+), most functionality has been consolidated into the main near-api-js package. You should update your imports to pull directly from near-api-js instead of individual scoped packages.

    // Before
    import { Account } from '@near-js/accounts';
    import { KeyPair } from '@near-js/crypto';
    import { JsonRpcProvider } from '@near-js/providers';
    
    // After
    import { Account, KeyPair, JsonRpcProvider } from 'near-api-js';
  6. Install near-api-js

    master

    Add near-api-js to your project using your preferred package manager. This library is suitable for backend services, CLIs, and scripts. For frontend web login implementations, refer to the official NEAR web login documentation instead.

    npm install near-api-js
    # or
    yarn add near-api-js
    # or
    pnpm add near-api-js
  7. Quick Start: Read and Write to NEAR

    master

    To interact with the NEAR blockchain, you need a JsonRpcProvider to connect to an RPC endpoint.

    • Read-only calls: Use provider.callFunction directly. This does not require a private key.
    • State-modifying calls: Use the Account class. You must provide an accountId, the provider, and a privateKey (as a KeyPairString) to sign transactions.
    import { Account, JsonRpcProvider, teraToGas, KeyPairString, nearToYocto } from "near-api-js";
    
    // Create a testnet provider
    const provider = new JsonRpcProvider({
      url: "https://test.rpc.fastnear.com",
    });
    
    // For read only calls, you can use the provider directly
    const messages = await provider.callFunction({
      contractId: 'guestbook.near-examples.testnet',
      method: "get_messages",
      args: {},
    });
    
    console.log(messages);
    
    // To modify state, you need an account to sign the transaction
    const accountId: string = 'example.testnet';
    const privateKey = 'ed25519:5nM...' as KeyPairString;
    const account = new Account(accountId, provider, privateKey);
    
    // Call the contract
    await account.callFunction({
      contractId: 'guestbook.near-examples.testnet',
      methodName: "add_message",
      args: { text: "Hello!" },
      gas: teraToGas('30'),
      deposit: nearToYocto('0.1'),
    });
  8. Understand Shard Layouts and Shard IDs

    master

    NEAR uses a sharding mechanism where ShardId is an ordinal number (0 to num_shards - 1). However, because the chain undergoes re-sharding, ShardUId is used to uniquely identify shards across different epochs by combining a shard_id and a version.

    ShardLayout defines how accounts are mapped to shards. Supported versions include V0 (simple mapping), V1 (boundary accounts), V2, and V3 (which include id_to_index_map and shard_ids for more complex routing).

    export type ShardUId = {
        shard_id: number;
        version: number;
    };
    
    export type ShardId = number;
  9. Use MultiKeySigner for parallel transaction signing

    master

    The MultiKeySigner is designed for high-throughput scenarios where you need to sign multiple transactions in parallel. By rotating through a set of provided keys, it helps avoid nonce conflicts that occur when multiple transactions are sent from the same key simultaneously.

    When calling getPublicKey(), the signer rotates to the next key in the array. When signing transactions or delegate actions, it automatically selects the key that matches the public key specified in the transaction/action, ensuring the correct key is used for the specific operation.

    const signer = new MultiKeySigner([key1, key2, key3]);
    const account = new Account('account.near', provider, signer);
    
    // These will use different keys in rotation to enable parallel execution
    await Promise.all([
      account.transfer({ receiverId: 'bob.near', amount: 1n }),
      account.transfer({ receiverId: 'alice.near', amount: 2n }),
      account.transfer({ receiverId: 'carol.near', amount: 3n }),
    ]);
  10. Understand ExecutionOutcomeView and ExecutionStatusView

    master

    When querying the results of a transaction or receipt, the ExecutionOutcomeView provides a detailed summary of the execution.

    Key fields include:

    • executor_id: The account ID where execution occurred (signer for transactions, receiver for receipts).
    • gas_burnt: The amount of gas consumed.
    • logs: An array of strings containing execution logs.
    • status: An ExecutionStatusView indicating if the execution was a SuccessValue, SuccessReceiptId, a Failure (with TxExecutionError), or Unknown.
    • tokens_burnt: The amount of tokens consumed (may differ from gas_burnt due to gas price differences).
    • receipt_ids: IDs of any receipts generated by this execution.
    // Example structure of an ExecutionOutcomeView
    const outcome: ExecutionOutcomeView = {
      executor_id: 'user.near',
      gas_burnt: '1000000000000000000',
      logs: ['Hello from NEAR!'],
      status: { SuccessValue: '42' },
      receipt_ids: ['...hash...'],
      tokens_burnt: '1000000000000000000'
    };
  11. Understand the structure of an AbiRoot

    master

    The AbiRoot is the top-level object representing a contract's Application Binary Interface (ABI). It contains the core logic of the contract and its metadata.

    Key components include:

    • body: An AbiBody containing the actual contract functions and the root JSON schema.
    • metadata: An AbiMetadata object providing information like the contract name, version, authors, and the wasm_hash (SHA-256 of the WASM code in Base58).
    • schema_version: A string indicating the semver of the ABI schema format.