diff --git a/.changeset/great-jobs-destroy.md b/.changeset/great-jobs-destroy.md new file mode 100644 index 0000000000..e0022b6c64 --- /dev/null +++ b/.changeset/great-jobs-destroy.md @@ -0,0 +1,17 @@ +--- +"near-api-js": major +--- + +`account.viewFunction` now takes a single object argument rather than individual args. Callsites will now need to be updated like so: +```diff +-await account.viewFunction( +- 'wrap.near', +- 'storage_balance_of', +- { account_id: 'example.near' } +-); ++await account.viewFunction({ ++ contractId: 'wrap.near', ++ methodName: 'storage_balance_of', ++ args: { account_id: 'example.near' }, ++}); +``` \ No newline at end of file diff --git a/packages/cookbook/utils/wrap-near.js b/packages/cookbook/utils/wrap-near.js index dd8b40cdc2..1dc5edbfea 100644 --- a/packages/cookbook/utils/wrap-near.js +++ b/packages/cookbook/utils/wrap-near.js @@ -41,11 +41,11 @@ async function wrapNear(accountId, wrapAmount) { ]; // check if storage has been paid (the account has a wNEAR account) - const storage = await account.viewFunction( - WRAP_NEAR_CONTRACT_ID, - "storage_balance_of", - { account_id: accountId } - ); + const storage = await account.viewFunction({ + contractId: WRAP_NEAR_CONTRACT_ID, + methodName: "storage_balance_of", + args: { account_id: accountId }, + }); // if storage hasn't been paid, pay for storage (create an account) if (!storage) { diff --git a/packages/near-api-js/src/account.ts b/packages/near-api-js/src/account.ts index 081e86e491..b2b5bced0e 100644 --- a/packages/near-api-js/src/account.ts +++ b/packages/near-api-js/src/account.ts @@ -1,5 +1,5 @@ import BN from 'bn.js'; -import depd from 'depd'; + import { transfer, createAccount, @@ -91,7 +91,7 @@ export interface FunctionCallOptions { /** * named arguments to pass the method `{ messageText: 'my message' }` */ - args: object; + args?: object; /** max amount of gas that method call can use */ gas?: BN; /** amount of NEAR (in yoctoNEAR) to send together with the call */ @@ -499,43 +499,20 @@ export class Account { * 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 contractId NEAR account where the contract is deployed - * @param methodName The view-only method (no state mutations) name on the contract as it is written in the contract code - * @param 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.jsContract Is contract from JS SDK, automatically encodes args from JS SDK to binary. - * @param options.blockQuery specifies which block to query state at. By default returns last "optimistic" block (i.e. not necessarily finalized). + * @param viewFunctionCallOptions.contractId NEAR account where the contract is deployed + * @param viewFunctionCallOptions.methodName The view-only method (no state mutations) name on the contract as it is written in the contract code + * @param viewFunctionCallOptions.args Any arguments to the view contract method, wrapped in JSON + * @param viewFunctionCallOptions.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 viewFunctionCallOptions.stringify Convert input arguments into a bytes array. By default the input is treated as a JSON. + * @param viewFunctionCallOptions.jsContract Is contract from JS SDK, automatically encodes args from JS SDK to binary. + * @param viewFunctionCallOptions.blockQuery specifies which block to query state at. By default returns last "optimistic" block (i.e. not necessarily finalized). * @returns {Promise} */ - async viewFunction(...restArgs: any) { - if (typeof restArgs[0] === 'string') { - const contractId = restArgs[0]; - const methodName = restArgs[1]; - const args = restArgs[2]; - const options = restArgs[3]; - return await this.viewFunctionV1(contractId, methodName, args, options); - } else { - return await this.viewFunctionV2(restArgs[0]); - } - } - - async viewFunctionV1( - contractId: string, - methodName: string, - args: any = {}, - { parse = parseJsonFromRawResponse, stringify = bytesJsonStringify, jsContract=false, blockQuery = { finality: 'optimistic' } }: { parse?: (response: Uint8Array) => any; stringify?: (input: any) => Buffer; blockQuery?: BlockReference; jsContract?: boolean } = {} - ): Promise { - const deprecate = depd('Account.viewFunction(contractId, methodName, args, options)'); - deprecate('use `Account.viewFunction(ViewFunctionCallOptions)` instead'); - return this.viewFunctionV2({ contractId, methodName, args, parse, stringify, jsContract, blockQuery }); - } - - async viewFunctionV2({ + async viewFunction({ contractId, methodName, - args, + args = {}, parse = parseJsonFromRawResponse, stringify = bytesJsonStringify, jsContract = false, diff --git a/packages/near-api-js/src/account_multisig.ts b/packages/near-api-js/src/account_multisig.ts index 31412ba484..621d8dedb3 100644 --- a/packages/near-api-js/src/account_multisig.ts +++ b/packages/near-api-js/src/account_multisig.ts @@ -189,7 +189,10 @@ export class AccountMultisig extends Account { async getRequestIds(): Promise { // TODO: Read requests from state to allow filtering by expiration time // TODO: https://github.com/near/core-contracts/blob/305d1db4f4f2cf5ce4c1ef3479f7544957381f11/multisig/src/lib.rs#L84 - return this.viewFunction(this.accountId, 'list_request_ids'); + return this.viewFunction({ + contractId: this.accountId, + methodName: 'list_request_ids', + }); } getRequest() { diff --git a/packages/near-api-js/src/contract.ts b/packages/near-api-js/src/contract.ts index 11173ff42b..0fbe7182f8 100644 --- a/packages/near-api-js/src/contract.ts +++ b/packages/near-api-js/src/contract.ts @@ -99,7 +99,12 @@ export class Contract { if (ignored.length || !(isObject(args) || isUint8Array(args)) || !isObject(options)) { throw new PositionalArgsError(); } - return this.account.viewFunction(this.contractId, methodName, args, options); + return this.account.viewFunction({ + contractId: this.contractId, + methodName, + args, + ...options, + }); }) }); }); diff --git a/packages/near-api-js/test/account.test.js b/packages/near-api-js/test/account.test.js index 7839d31814..f69cc5ca38 100644 --- a/packages/near-api-js/test/account.test.js +++ b/packages/near-api-js/test/account.test.js @@ -153,10 +153,11 @@ describe('with deploy contract', () => { }); test('make function calls via account', async() => { - const result = await workingAccount.viewFunction( + const result = await workingAccount.viewFunction({ contractId, - 'hello', // this is the function defined in hello.wasm file that we are calling - {name: 'trex'}); + methodName: 'hello', // this is the function defined in hello.wasm file that we are calling + args: {name: 'trex'} + }); expect(result).toEqual('hello trex'); const setCallValue = testUtils.generateUniqueString('setCallPrefix'); @@ -166,7 +167,10 @@ describe('with deploy contract', () => { args: { value: setCallValue } }); expect(providers.getTransactionLastResult(result2)).toEqual(setCallValue); - expect(await workingAccount.viewFunction(contractId, 'getValue', {})).toEqual(setCallValue); + expect(await workingAccount.viewFunction({ + contractId, + methodName: 'getValue' + })).toEqual(setCallValue); }); test('view contract state', async() => { @@ -183,12 +187,12 @@ describe('with deploy contract', () => { }); test('make function calls via account with custom parser', async() => { - const result = await workingAccount.viewFunction( + const result = await workingAccount.viewFunction({ contractId, - 'hello', // this is the function defined in hello.wasm file that we are calling - {name: 'trex'}, - { parse: x => JSON.parse(x.toString()).replace('trex', 'friend') } - ); + methodName:'hello', // this is the function defined in hello.wasm file that we are calling + args: {name: 'trex'}, + parse: x => JSON.parse(x.toString()).replace('trex', 'friend') + }); expect(result).toEqual('hello friend'); }); @@ -208,22 +212,31 @@ describe('with deploy contract', () => { expect(result1).toEqual(setCallValue1); expect(await contract.getValue()).toEqual(setCallValue1); - expect(await workingAccount.viewFunction(contractId, 'getValue', {}, { - blockQuery: { finality: 'optimistic' } + expect(await workingAccount.viewFunction({ + contractId, + methodName: 'getValue', + blockQuery: { finality: 'optimistic' }, })).toEqual(setCallValue1); - expect(await workingAccount.viewFunction(contractId, 'getValue', {})).toEqual(setCallValue1); + expect(await workingAccount.viewFunction({ + contractId, + methodName: 'getValue' + })).toEqual(setCallValue1); const block1 = await workingAccount.connection.provider.block({ finality: 'optimistic' }); const blockHash1 = block1.header.hash; const blockIndex1 = block1.header.height; - expect(await workingAccount.viewFunction(contractId, 'getValue', {}, { - blockQuery: { blockId: blockHash1 } + expect(await workingAccount.viewFunction({ + contractId, + methodName: 'getValue', + blockQuery: { blockId: blockHash1 }, })).toEqual(setCallValue1); - expect(await workingAccount.viewFunction(contractId, 'getValue', {}, { - blockQuery: { blockId: blockIndex1 } + expect(await workingAccount.viewFunction({ + contractId, + methodName: 'getValue', + blockQuery: { blockId: blockIndex1 }, })).toEqual(setCallValue1); const setCallValue2 = testUtils.generateUniqueString('setCallPrefix'); @@ -231,31 +244,44 @@ describe('with deploy contract', () => { expect(result2).toEqual(setCallValue2); expect(await contract.getValue()).toEqual(setCallValue2); - expect(await workingAccount.viewFunction(contractId, 'getValue', {}, { - blockQuery: { finality: 'optimistic' } + expect(await workingAccount.viewFunction({ + contractId, + methodName: 'getValue', + blockQuery: { finality: 'optimistic' }, })).toEqual(setCallValue2); - expect(await workingAccount.viewFunction(contractId, 'getValue', {})).toEqual(setCallValue2); + expect(await workingAccount.viewFunction({ + contractId, + methodName: 'getValue' + })).toEqual(setCallValue2); // Old blockHash should still be value #1 - expect(await workingAccount.viewFunction(contractId, 'getValue', {}, { - blockQuery: { blockId: blockHash1 } + expect(await workingAccount.viewFunction({ + contractId, + methodName: 'getValue', + blockQuery: { blockId: blockHash1 }, })).toEqual(setCallValue1); - expect(await workingAccount.viewFunction(contractId, 'getValue', {}, { - blockQuery: { blockId: blockIndex1 } + expect(await workingAccount.viewFunction({ + contractId, + methodName: 'getValue', + blockQuery: { blockId: blockIndex1 }, })).toEqual(setCallValue1); const block2 = await workingAccount.connection.provider.block({ finality: 'optimistic' }); const blockHash2 = block2.header.hash; const blockIndex2 = block2.header.height; - expect(await workingAccount.viewFunction(contractId, 'getValue', {}, { - blockQuery: { blockId: blockHash2 } + expect(await workingAccount.viewFunction({ + contractId, + methodName: 'getValue', + blockQuery: { blockId: blockHash2 }, })).toEqual(setCallValue2); - expect(await workingAccount.viewFunction(contractId, 'getValue', {}, { - blockQuery: { blockId: blockIndex2 } + expect(await workingAccount.viewFunction({ + contractId, + methodName: 'getValue', + blockQuery: { blockId: blockIndex2 }, })).toEqual(setCallValue2); }); diff --git a/packages/near-api-js/test/contract.test.js b/packages/near-api-js/test/contract.test.js index 3e0935256d..fbeb57790d 100644 --- a/packages/near-api-js/test/contract.test.js +++ b/packages/near-api-js/test/contract.test.js @@ -2,8 +2,8 @@ const { Contract } = require('../src/contract'); const { PositionalArgsError } = require('../src/utils/errors'); const account = { - viewFunction(contractId, methodName, args, options) { - return { this: this, contractId, methodName, args, options }; + viewFunction({ contractId, methodName, args, parse, stringify, jsContract, blockQuery}) { + return { this: this, contractId, methodName, args, parse, stringify, jsContract, blockQuery }; }, functionCall() { return this; @@ -50,8 +50,8 @@ const contract = new Contract(account, 'contractId', { describe('viewMethod', () => { test('passes options through to account viewFunction', async () => { function customParser () {} - const stubbedReturnValue = await contract.viewMethod({}, { parse: customParser }); - expect(stubbedReturnValue.options.parse).toBe(customParser); + const stubbedReturnValue = await account.viewFunction({ parse: customParser }); + expect(stubbedReturnValue.parse).toBe(customParser); }); describe.each([