UNPKG

@near-js/accounts

Version:

Classes encapsulating account-specific functionality

1,046 lines (1,045 loc) 37.6 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var account_exports = {}; __export(account_exports, { Account: () => Account, DEFAULT_WAIT_STATUS: () => DEFAULT_WAIT_STATUS }); module.exports = __toCommonJS(account_exports); var import_crypto = require("@near-js/crypto"); var import_providers = require("@near-js/providers"); var import_transactions = require("@near-js/transactions"); var import_types = require("@near-js/types"); var import_utils = require("@near-js/utils"); var import_connection = require('./connection.cjs'); var import_utils2 = require('./utils.cjs'); var import_tokens = require("@near-js/tokens"); const { addKey, createAccount, deleteAccount, deleteKey, deployContract, deployGlobalContract, fullAccessKey, functionCall, functionCallAccessKey, transfer, useGlobalContract } = import_transactions.actionCreators; const DEFAULT_FINALITY = process.env.DEFAULT_FINALITY || "near-final"; const DEFAULT_WAIT_STATUS = "EXECUTED_OPTIMISTIC"; class Account { accountId; provider; signer; constructor(accountId, provider, signer) { this.accountId = accountId; this.provider = provider; this.signer = signer; } /** * Allows to set the signer used to control the account * * @param signer holds the private key and can sign Transactions */ setSigner(signer) { this.signer = signer; } getSigner() { return this.signer; } /** * Returns an overview of the account's state, including the account's * balance, storage usage, and code hash */ async getState() { const protocolConfig = await this.provider.experimental_protocolConfig({ finality: DEFAULT_FINALITY }); const state = await this.provider.viewAccount(this.accountId, { finality: DEFAULT_FINALITY }); const costPerByte = BigInt( protocolConfig.runtime_config.storage_amount_per_byte ); const usedOnStorage = BigInt(state.storage_usage) * costPerByte; const locked = BigInt(state.locked); const total = BigInt(state.amount) + locked; const available = total - (locked > usedOnStorage ? locked : usedOnStorage); return { balance: { total, usedOnStorage, locked, available }, storageUsage: state.storage_usage, codeHash: state.code_hash }; } /** * Calls {@link Provider.viewAccessKey} to retrieve information for a * specific key in the account */ async getAccessKey(publicKey) { return this.provider.viewAccessKey(this.accountId, publicKey, { finality: DEFAULT_FINALITY }); } /** * Calls {@link Provider.viewAccessKeyList} to retrieve the account's keys */ async getAccessKeyList() { return this.provider.viewAccessKeyList(this.accountId, { finality: DEFAULT_FINALITY }); } /** * Calls {@link Provider.viewContractCode} to retrieve the account's * contract code and its hash */ async getContractCode() { return this.provider.viewContractCode(this.accountId, { finality: DEFAULT_FINALITY }); } /** * Calls {@link Provider.viewContractState} to retrieve the keys and values * stored on the account's contract */ async getContractState(prefix) { return this.provider.viewContractState(this.accountId, prefix, { finality: DEFAULT_FINALITY }); } /** * Create a transaction that can be later signed with a {@link Signer} * * @param receiverId Account against which to perform the actions * @param actions Actions to perform * @param publicKey The public part of the key that will be used to sign the transaction */ async createTransaction(receiverId, actions, publicKey) { if (!publicKey) throw new Error("Please provide a public key"); const pk = import_crypto.PublicKey.from(publicKey); const accessKey = await this.getAccessKey(pk); const block = await this.provider.viewBlock({ finality: DEFAULT_FINALITY }); const recentBlockHash = block.header.hash; const nonce = BigInt(accessKey.nonce) + 1n; return (0, import_transactions.createTransaction)( this.accountId, pk, receiverId, nonce + 1n, actions, (0, import_utils.baseDecode)(recentBlockHash) ); } /** * Create a signed transaction ready to be broadcast by a {@link Provider} */ async createSignedTransaction(receiverId, actions) { if (!this.signer) throw new Error("Please set a signer"); const tx = await this.createTransaction( receiverId, actions, await this.signer.getPublicKey() ); const [, signedTx] = await this.signer.signTransaction(tx); return signedTx; } /** * Create a meta transaction ready to be signed by a {@link Signer} * * @param receiverId NEAR account receiving the transaction * @param actions list of actions to perform as part of the meta transaction * @param blockHeightTtl number of blocks after which a meta transaction will expire if not processed */ async createMetaTransaction(receiverId, actions, blockHeightTtl = 200, publicKey) { if (!publicKey) throw new Error(`Please provide a public key`); const pk = import_crypto.PublicKey.from(publicKey); const accessKey = await this.getAccessKey(pk); const nonce = BigInt(accessKey.nonce) + 1n; const { header } = await this.provider.viewBlock({ finality: DEFAULT_FINALITY }); const maxBlockHeight = BigInt(header.height) + BigInt(blockHeightTtl); return (0, import_transactions.buildDelegateAction)({ receiverId, senderId: this.accountId, actions, publicKey: pk, nonce, maxBlockHeight }); } /** * Create a signed MetaTransaction that can be broadcasted to a relayer * * @param receiverId NEAR account receiving the transaction * @param actions list of actions to perform as part of the meta transaction * @param blockHeightTtl number of blocks after which a meta transaction will expire if not processed */ async createSignedMetaTransaction(receiverId, actions, blockHeightTtl = 200) { if (!this.signer) throw new Error(`Please set a signer`); const delegateAction = await this.createMetaTransaction( receiverId, actions, blockHeightTtl, await this.signer.getPublicKey() ); return this.signer.signDelegateAction(delegateAction); } /** * Creates a transaction, signs it and broadcast it to the network * * @param receiverId The NEAR account ID of the transaction receiver. * @param actions The list of actions to be performed in the transaction. * @param throwOnFailure Whether to throw an error if the transaction fails. * @returns {Promise<FinalExecutionOutcome>} A promise that resolves to the final execution outcome of the transaction. * */ async signAndSendTransaction({ receiverId, actions, waitUntil = DEFAULT_WAIT_STATUS, throwOnFailure = true }) { const signedTx = await this.createSignedTransaction( receiverId, actions ); const result = await this.provider.sendTransactionUntil( signedTx, waitUntil ); if (throwOnFailure && typeof result.status === "object" && typeof result.status.Failure === "object" && result.status.Failure !== null) { throw (0, import_utils.parseResultError)(result); } return result; } async signAndSendTransactions({ transactions, waitUntil = DEFAULT_WAIT_STATUS, throwOnFailure = true }) { if (!this.signer) throw new Error("Please set a signer"); const results = await Promise.all( transactions.map(async ({ receiverId, actions }) => { return this.signAndSendTransaction({ receiverId, actions, waitUntil, throwOnFailure }); }) ); return results; } /** * Creates a new NEAR account with a given ID and public key. * * This method can create two types of accounts: * * 1. Top-level accounts of the form `name.tla` (e.g., `bob.near`): * * 2. Sub-accounts of the current account (e.g., `sub.ana.near`): * - The new account ID must end with the current account ID * - Example: If your account is `ana.near`, you can create `sub.ana.near` * * @param newAccountId the new account to create (e.g. bob.near or sub.ana.near) * @param publicKey the public part of the key that will control the account * @param nearToTransfer how much NEAR to transfer to the account in yoctoNEAR (default: 0) * */ async createAccount(newAccountId, publicKey, nearToTransfer = "0") { if (newAccountId.endsWith(this.accountId)) { return this.createSubAccount( newAccountId, publicKey, nearToTransfer ); } const splitted = newAccountId.split("."); if (splitted.length != 2) { throw new Error( "newAccountId needs to be of the form <string>.<tla>" ); } const TLA = splitted[1]; return this.signAndSendTransaction({ receiverId: TLA, actions: [ functionCall( "create_account", { new_account_id: newAccountId, new_public_key: publicKey.toString() }, BigInt("60000000000000"), BigInt(nearToTransfer) ) ] }); } /** * Creates a sub account of this account. For example, if the account is * ana.near, you can create sub.ana.near. * * @param accountOrPrefix a prefix (e.g. `sub`) or the full sub-account (`sub.ana.near`) * @param publicKey the public part of the key that will control the account * @param nearToTransfer how much NEAR to transfer to the account (default: 0) * */ async createSubAccount(accountOrPrefix, publicKey, nearToTransfer = "0") { if (!this.signer) throw new Error("Please set a signer"); const newAccountId = accountOrPrefix.includes(".") ? accountOrPrefix : `${accountOrPrefix}.${this.accountId}`; if (newAccountId.length > 64) { throw new Error(`Accounts cannot exceed 64 characters`); } if (!newAccountId.endsWith(this.accountId)) { throw new Error(`New account must end up with ${this.accountId}`); } const actions = [ createAccount(), transfer(BigInt(nearToTransfer)), addKey(import_crypto.PublicKey.from(publicKey), fullAccessKey()) ]; return this.signAndSendTransaction({ receiverId: newAccountId, actions }); } /** * Deletes the account, transferring all remaining NEAR to a beneficiary * account * * Important: Deleting an account does not transfer FTs or NFTs * * @param beneficiaryId Will receive the account's remaining balance */ async deleteAccount(beneficiaryId) { return this.signAndSendTransaction({ receiverId: this.accountId, actions: [deleteAccount(beneficiaryId)] }); } /** * Deploy a smart contract in the account * * @param code The compiled contract code bytes */ async deployContract(code) { return this.signAndSendTransaction({ receiverId: this.accountId, actions: [deployContract(code)] }); } /** * Deploy a global contract that can be reused by multiple accounts * * @param code The compiled contract code bytes * @param deployMode Deploy mode - "codeHash" for immutable contracts, "accountId" for updateable contracts */ async deployGlobalContract(code, deployMode) { const mode = deployMode === "codeHash" ? new import_transactions.GlobalContractDeployMode({ CodeHash: null }) : new import_transactions.GlobalContractDeployMode({ AccountId: null }); return this.signAndSendTransaction({ receiverId: this.accountId, actions: [deployGlobalContract(code, mode)] }); } /** * Use a previously deployed global contract on this account * * @param contractIdentifier The global contract identifier - either { accountId: string } or { codeHash: string | Uint8Array } */ async useGlobalContract(contractIdentifier) { const identifier = "accountId" in contractIdentifier ? new import_transactions.GlobalContractIdentifier({ AccountId: contractIdentifier.accountId }) : new import_transactions.GlobalContractIdentifier({ CodeHash: typeof contractIdentifier.codeHash === "string" ? Buffer.from(contractIdentifier.codeHash, "hex") : contractIdentifier.codeHash }); return this.signAndSendTransaction({ receiverId: this.accountId, actions: [useGlobalContract(identifier)] }); } /** * * @param options * @param options.publicKey The key to add to the account * @param options.contractId The contract that this key can call * @param options.methodNames The methods this key is allowed to call * @param options.allowance The amount of NEAR this key can expend in gas * @returns */ async addFunctionCallAccessKey({ publicKey, contractId, methodNames = [], allowance = import_tokens.NEAR.toUnits("0.25") }) { return this.signAndSendTransaction({ receiverId: this.accountId, actions: [ addKey( import_crypto.PublicKey.from(publicKey), functionCallAccessKey( contractId, methodNames, BigInt(allowance) ) ) ] }); } /** * Add a full access key to the account * * @param publicKey The public key to be added * @returns {Promise<FinalExecutionOutcome>} */ async addFullAccessKey(publicKey) { return this.signAndSendTransaction({ receiverId: this.accountId, actions: [addKey(import_crypto.PublicKey.from(publicKey), fullAccessKey())] }); } /** * @param publicKey The public key to be deleted * @returns {Promise<FinalExecutionOutcome>} */ async deleteKey(publicKey) { return this.signAndSendTransaction({ receiverId: this.accountId, actions: [deleteKey(import_crypto.PublicKey.from(publicKey))] }); } /** * Call a function on a smart contract and return parsed transaction result * * @param options * @param options.contractId The contract in which to call the function * @param options.methodName The method that will be called * @param options.args Arguments, either as a valid JSON Object or a raw Uint8Array * @param options.deposit (optional) Amount of NEAR Tokens to attach to the call (default 0) * @param options.gas (optional) Amount of GAS to use attach to the call (default 30TGas) * @param options.waitUntil (optional) Transaction finality to wait for (default INCLUDED_FINAL) * @returns */ async callFunction(params) { const result = await this.callFunctionRaw(params); return (0, import_utils.getTransactionLastResult)(result); } /** * Call a function on a smart contract and return raw transaction outcome * * @param options * @param options.contractId The contract in which to call the function * @param options.methodName The method that will be called * @param options.args Arguments, either as a valid JSON Object or a raw Uint8Array * @param options.deposit (optional) Amount of NEAR Tokens to attach to the call (default 0) * @param options.gas (optional) Amount of GAS to use attach to the call (default 30TGas) * @param options.waitUntil (optional) Transaction finality to wait for (default INCLUDED_FINAL) * @returns {FinalExecutionOutcome} */ async callFunctionRaw({ contractId, methodName, args = {}, deposit = "0", gas = import_utils.DEFAULT_FUNCTION_CALL_GAS, waitUntil = DEFAULT_WAIT_STATUS }) { return await this.signAndSendTransaction({ receiverId: contractId, actions: [ functionCall(methodName, args, BigInt(gas), BigInt(deposit)) ], waitUntil }); } /** * This function simply calls the `signNep413Message` method of the Signer * * @param options * @param options.message The message to be signed (e.g. "authenticating") * @param options.recipient Who will receive the message (e.g. auth.app.com) * @param options.nonce A challenge sent by the recipient * @param options.callbackUrl (optional) Deprecated parameter used only by browser wallets * @returns */ async signNep413Message({ message, recipient, nonce, callbackUrl }) { if (!this.signer) throw new Error("Please set a signer"); return this.signer.signNep413Message( message, this.accountId, recipient, nonce, callbackUrl ); } /** * * @param token The token to check the balance of. Defaults to Native NEAR. * @returns The available balance of the account in units (e.g. yoctoNEAR). */ async getBalance(token = import_tokens.NEAR) { return token.getBalance(this); } /** * Transfers a token to the specified receiver. * * Supports sending either the native NEAR token or any supported Fungible Token (FT). * * @param amount - The amount of tokens to transfer in units (e.g. yoctoNEAR). * @param receiverId - The NEAR account ID of the receiver. * @param token - The token to transfer. Defaults to Native NEAR. * */ async transfer({ receiverId, amount, token = import_tokens.NEAR }) { return token.transfer({ from: this, receiverId, amount }); } // DEPRECATED FUNCTIONS BELLOW - Please remove in next release /** * @deprecated please use {@link Account.createSignedMetaTransaction} instead * * Compose and sign a SignedDelegate action to be executed in a transaction on behalf of this Account instance * * @param options Options for the transaction. * @param options.actions Actions to be included in the meta transaction * @param options.blockHeightTtl Number of blocks past the current block height for which the SignedDelegate action may be included in a meta transaction * @param options.receiverId Receiver account of the meta transaction */ async signedDelegate({ actions, blockHeightTtl, receiverId }) { const { header } = await this.provider.viewBlock({ finality: DEFAULT_FINALITY }); if (!this.signer) throw new Error(`Please set a signer`); const pk = await this.signer.getPublicKey(); const accessKey = await this.getAccessKey(pk); const delegateAction = (0, import_transactions.buildDelegateAction)({ actions, maxBlockHeight: BigInt(header.height) + BigInt(blockHeightTtl), nonce: BigInt(accessKey.nonce) + 1n, publicKey: pk, receiverId, senderId: this.accountId }); const [, signedDelegate] = await this.signer.signDelegateAction( delegateAction ); return signedDelegate; } /** * @deprecated, accounts no longer use Connections since it's deprecated too */ getConnection() { return new import_connection.Connection("", this.provider, this.signer); } /** @hidden */ validateArgs(args) { const isUint8Array = args.byteLength !== void 0 && args.byteLength === args.length; if (isUint8Array) { return; } if (Array.isArray(args) || typeof args !== "object") { throw new import_types.PositionalArgsError(); } } /** * @deprecated please use {@link callFunction} instead * * Execute a function call. * @param options The options for the function call. * @param options.contractId The NEAR account ID of the smart contract. * @param options.methodName The name of the method to be called on the smart contract. * @param options.args The arguments to be passed to the method. * @param options.gas The maximum amount of gas to be used for the function call. * @param options.attachedDeposit The amount of NEAR tokens to be attached to the function call. * @param options.walletMeta Metadata for wallet integration. * @param options.walletCallbackUrl The callback URL for wallet integration. * @param options.stringify A function to convert input arguments into bytes array * @returns {Promise<FinalExecutionOutcome>} A promise that resolves to the final execution outcome of the function call. */ async functionCall({ contractId, methodName, args = {}, gas = import_utils.DEFAULT_FUNCTION_CALL_GAS, attachedDeposit, walletMeta, walletCallbackUrl, stringify }) { this.validateArgs(args); const stringifyArg = stringify === void 0 ? import_transactions.stringifyJsonOrBytes : stringify; const functionCallArgs = [ methodName, args, gas, attachedDeposit, stringifyArg, false ]; return this.signAndSendTransactionLegacy({ receiverId: contractId, // eslint-disable-next-line prefer-spread actions: [functionCall.apply(void 0, functionCallArgs)], walletMeta, walletCallbackUrl }); } /** * @deprecated use instead {@link Provider.viewTransactionStatus} */ async getTransactionStatus(txHash) { return this.provider.viewTransactionStatus( txHash, this.accountId, // accountId is used to determine on which shard to look for a tx "EXECUTED_OPTIMISTIC" ); } /** * @deprecated use ${@link createSignedTransaction} * Create a signed transaction which can be broadcast to the network * @param receiverId NEAR account receiving the transaction * @param actions list of actions to perform as part of the transaction * @see {@link "@near-js/providers".json-rpc-provider.JsonRpcProvider.sendTransaction | JsonRpcProvider.sendTransaction} */ async signTransaction(receiverId, actions, opts) { const signer = opts?.signer || this.signer; if (!signer) throw new Error(`Please set a signer`); const pk = await signer.getPublicKey(); const accessKey = await this.getAccessKey(pk); const block = await this.provider.viewBlock({ finality: DEFAULT_FINALITY }); const recentBlockHash = block.header.hash; const nonce = BigInt(accessKey.nonce) + 1n; const tx = (0, import_transactions.createTransaction)( this.accountId, pk, receiverId, nonce + 1n, actions, (0, import_utils.baseDecode)(recentBlockHash) ); return signer.signTransaction(tx); } /** * @deprecated instead please create a transaction with * the actions bellow and broadcast it to the network * 1. createAccount * 2. transfer some tokens * 3. deployContract * 4. (optional) addKey * 5. (optional) functionCall to an initialization function * * Create a new account and deploy a contract to it * @param contractId NEAR account where the contract is deployed * @param publicKey The public key to add to the created contract account * @param data The compiled contract code * @param amount of NEAR to transfer to the created contract account. Transfer enough to pay for storage https://docs.near.org/docs/concepts/storage-staking */ async createAndDeployContract(contractId, publicKey, data, amount) { const accessKey = fullAccessKey(); await this.signAndSendTransactionLegacy({ receiverId: contractId, actions: [ createAccount(), transfer(amount), addKey(import_crypto.PublicKey.from(publicKey), accessKey), deployContract(data) ] }); return new Account(contractId, this.provider); } /** * @deprecated please instead use {@link transfer} * * @param receiverId NEAR account receiving Ⓝ * @param amount Amount to send in yoctoⓃ */ async sendMoney(receiverId, amount) { return this.signAndSendTransactionLegacy({ receiverId, actions: [transfer(amount)] }); } /** * @deprecated please instead use {@link signAndSendTransaction} * * Sign a transaction to perform a list of actions and broadcast it using the RPC API. * @see {@link "@near-js/providers".json-rpc-provider.JsonRpcProvider | JsonRpcProvider } * * @param options The options for signing and sending the transaction. * @param options.receiverId The NEAR account ID of the transaction receiver. * @param options.actions The list of actions to be performed in the transaction. * @param options.returnError Whether to return an error if the transaction fails. * @returns {Promise<FinalExecutionOutcome>} A promise that resolves to the final execution outcome of the transaction. * */ async signAndSendTransactionLegacy({ receiverId, actions, returnError }, opts) { let txHash, signedTx; const TX_NONCE_RETRY_NUMBER = 12; const TX_NONCE_RETRY_WAIT = 500; const TX_NONCE_RETRY_WAIT_BACKOFF = 1.5; const result = await (0, import_providers.exponentialBackoff)( TX_NONCE_RETRY_WAIT, TX_NONCE_RETRY_NUMBER, TX_NONCE_RETRY_WAIT_BACKOFF, async () => { [txHash, signedTx] = await this.signTransaction( receiverId, actions, opts ); try { return await this.provider.sendTransaction(signedTx); } catch (error) { if (error.type === "InvalidNonce") { import_utils.Logger.warn( `Retrying transaction ${receiverId}:${(0, import_utils.baseEncode)( txHash )} with new nonce.` ); return null; } if (error.type === "Expired") { import_utils.Logger.warn( `Retrying transaction ${receiverId}:${(0, import_utils.baseEncode)( txHash )} due to expired block hash` ); return null; } error.context = new import_types.ErrorContext((0, import_utils.baseEncode)(txHash)); throw error; } } ); if (!result) { throw new import_types.TypedError( "nonce retries exceeded for transaction. This usually means there are too many parallel requests with the same access key.", "RetriesExceeded" ); } (0, import_utils.printTxOutcomeLogsAndFailures)({ contractId: signedTx.transaction.receiverId, outcome: result }); if (!returnError && typeof result.status === "object" && typeof result.status.Failure === "object" && result.status.Failure !== null) { if (result.status.Failure.error_message && result.status.Failure.error_type) { throw new import_types.TypedError( `Transaction ${result.transaction_outcome.id} failed. ${result.status.Failure.error_message}`, result.status.Failure.error_type ); } else { throw (0, import_utils.parseResultError)(result); } } return result; } /** @hidden */ accessKeyByPublicKeyCache = {}; /** * @deprecated, accounts will no longer handle keystores * * Finds the {@link AccessKeyView} associated with the accounts {@link PublicKey} stored in the {@link "@near-js/keystores".keystore.KeyStore | Keystore}. * * @param receiverId currently unused * @param actions currently unused * @returns `{ publicKey PublicKey; accessKey: AccessKeyView }` */ // eslint-disable-next-line @typescript-eslint/no-unused-vars async findAccessKey(receiverId, actions) { if (!this.signer) throw new Error(`Please set a signer`); const publicKey = await this.signer.getPublicKey(); if (!publicKey) { throw new import_types.TypedError( `no matching key pair found in ${this.signer.constructor.name}`, "PublicKeyNotFound" ); } const cachedAccessKey = this.accessKeyByPublicKeyCache[publicKey.toString()]; if (cachedAccessKey !== void 0) { return { publicKey, accessKey: cachedAccessKey }; } try { const rawAccessKey = await this.provider.query({ request_type: "view_access_key", account_id: this.accountId, public_key: publicKey.toString(), finality: DEFAULT_FINALITY }); const accessKey = { ...rawAccessKey, nonce: BigInt(rawAccessKey.nonce || 0) }; if (this.accessKeyByPublicKeyCache[publicKey.toString()]) { return { publicKey, accessKey: this.accessKeyByPublicKeyCache[publicKey.toString()] }; } this.accessKeyByPublicKeyCache[publicKey.toString()] = accessKey; return { publicKey, accessKey }; } catch (e) { if (e.type == "AccessKeyDoesNotExist") { return null; } throw e; } } /** * @deprecated please use {@link addFullAccessKey} or {@link addFunctionAccessKey} * * @see [https://docs.near.org/concepts/basics/accounts/access-keys](https://docs.near.org/concepts/basics/accounts/access-keys) * @todo expand this API to support more options. * @param publicKey A public key to be associated with the contract * @param contractId NEAR account where the contract is deployed * @param methodNames The method names on the contract that should be allowed to be called. Pass null for no method names and '' or [] for any method names. * @param amount Payment in yoctoⓃ that is sent to the contract during this function call */ async addKey(publicKey, contractId, methodNames, amount) { if (!methodNames) { methodNames = []; } if (!Array.isArray(methodNames)) { methodNames = [methodNames]; } let accessKey; if (!contractId) { accessKey = fullAccessKey(); } else { accessKey = functionCallAccessKey(contractId, methodNames, amount); } return this.signAndSendTransactionLegacy({ receiverId: this.accountId, actions: [addKey(import_crypto.PublicKey.from(publicKey), accessKey)] }); } /** * @deprecated please use {@link Provider.callFunction} instead * * Invoke a contract view function using the RPC API. * @see [https://docs.near.org/api/rpc/contracts#call-a-contract-function](https://docs.near.org/api/rpc/contracts#call-a-contract-function) * * @param options Function call options. * @param options.contractId NEAR account where the contract is deployed * @param options.methodName The view-only method (no state mutations) name on the contract as it is written in the contract code * @param options.args Any arguments to the view contract method, wrapped in JSON * @param options.parse Parse the result of the call. Receives a Buffer (bytes array) and converts it to any object. By default result will be treated as json. * @param options.stringify Convert input arguments into a bytes array. By default the input is treated as a JSON. * @param options.blockQuery specifies which block to query state at. By default returns last DEFAULT_FINALITY block (i.e. not necessarily finalized). * @returns {Promise<any>} */ async viewFunction(options) { return await (0, import_utils2.viewFunction)(this.getConnection(), options); } /** * @deprecated please use {@link getContractState} instead * * Returns the state (key value pairs) of this account's contract based on the key prefix. * Pass an empty string for prefix if you would like to return the entire state. * @see [https://docs.near.org/api/rpc/contracts#view-contract-state](https://docs.near.org/api/rpc/contracts#view-contract-state) * * @param prefix allows to filter which keys should be returned. Empty prefix means all keys. String prefix is utf-8 encoded. * @param blockQuery specifies which block to query state at. By default returns last DEFAULT_FINALITY block (i.e. not necessarily finalized). */ async viewState(prefix, blockQuery = { finality: DEFAULT_FINALITY }) { return await (0, import_utils2.viewState)( this.getConnection(), this.accountId, prefix, blockQuery ); } /** * @deprecated please use {@link getAccessKeyList} instead * * Get all access keys for the account * @see [https://docs.near.org/api/rpc/access-keys#view-access-key-list](https://docs.near.org/api/rpc/access-keys#view-access-key-list) * */ async getAccessKeys() { const response = await this.provider.query({ request_type: "view_access_key_list", account_id: this.accountId, finality: DEFAULT_FINALITY }); return response?.keys?.map((key) => ({ ...key, access_key: { ...key.access_key, nonce: BigInt(key.access_key.nonce) } })); } /** * @deprecated * * Returns a list of authorized apps * @todo update the response value to return all the different keys, not just app keys. * */ async getAccountDetails() { const accessKeys = await this.getAccessKeys(); const authorizedApps = accessKeys.filter((item) => item.access_key.permission !== "FullAccess").map((item) => { const perm = item.access_key.permission; return { contractId: perm.FunctionCall.receiver_id, amount: perm.FunctionCall.allowance, publicKey: item.public_key }; }); return { authorizedApps }; } /** * @deprecated please use {@link getState} instead * * Returns basic NEAR account information via the `view_account` RPC query method * @see [https://docs.near.org/api/rpc/contracts#view-account](https://docs.near.org/api/rpc/contracts#view-account) */ async state() { return this.provider.query({ request_type: "view_account", account_id: this.accountId, finality: "optimistic" }); } /** * @deprecated please use {@link getState} instead * */ async getAccountBalance() { const protocolConfig = await this.provider.experimental_protocolConfig({ finality: DEFAULT_FINALITY }); const state = await this.state(); const costPerByte = BigInt( protocolConfig.runtime_config.storage_amount_per_byte ); const stateStaked = BigInt(state.storage_usage) * costPerByte; const staked = BigInt(state.locked); const totalBalance = BigInt(state.amount) + staked; const availableBalance = totalBalance - (staked > stateStaked ? staked : stateStaked); return { total: totalBalance.toString(), stateStaked: stateStaked.toString(), staked: staked.toString(), available: availableBalance.toString() }; } /** * Returns the NEAR tokens balance and validators of a given account that is delegated to the staking pools that are part of the validators set in the current epoch. * * @deprecated * * NOTE: If the tokens are delegated to a staking pool that is currently on pause or does not have enough tokens to participate in validation, they won't be accounted for. * @returns {Promise<ActiveDelegatedStakeBalance>} */ async getActiveDelegatedStakeBalance() { const block = await this.provider.block({ finality: DEFAULT_FINALITY }); const blockHash = block.header.hash; const epochId = block.header.epoch_id; const { current_validators, next_validators, current_proposals } = await this.provider.validators(epochId); const pools = /* @__PURE__ */ new Set(); [ ...current_validators, ...next_validators, ...current_proposals ].forEach((validator) => pools.add(validator.account_id)); const uniquePools = [...pools]; const promises = uniquePools.map( (validator) => this.viewFunction({ contractId: validator, methodName: "get_account_total_balance", args: { account_id: this.accountId }, blockQuery: { blockId: blockHash } }) ); const results = await Promise.allSettled(promises); const hasTimeoutError = results.some((result) => { if (result.status === "rejected" && result.reason.type === "TimeoutError") { return true; } return false; }); if (hasTimeoutError) { throw new Error("Failed to get delegated stake balance"); } const summary = results.reduce( (result, state, index) => { const validatorId = uniquePools[index]; if (state.status === "fulfilled") { const currentBN = BigInt(state.value); if (currentBN !== 0n) { return { ...result, stakedValidators: [ ...result.stakedValidators, { validatorId, amount: currentBN.toString() } ], total: result.total + currentBN }; } } if (state.status === "rejected") { return { ...result, failedValidators: [ ...result.failedValidators, { validatorId, error: state.reason } ] }; } return result; }, { stakedValidators: [], failedValidators: [], total: 0n } ); return { ...summary, total: summary.total.toString() }; } } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { Account, DEFAULT_WAIT_STATUS });