From d7c017fbb172ae5f8084dff170e1f2160008b373 Mon Sep 17 00:00:00 2001 From: Bo Yao Date: Tue, 6 Sep 2022 18:36:32 +0800 Subject: [PATCH] add highlevel promise api tests --- lib/api.js | 2 + lib/promise.js | 2 +- package.json | 1 - src/promise.ts | 2 +- tests/__tests__/test_highlevel_promise.ava.js | 144 ++++++++++++++++++ tests/package.json | 4 +- tests/src/highlevel-promise.js | 87 +++++++++++ 7 files changed, 238 insertions(+), 4 deletions(-) create mode 100644 tests/__tests__/test_highlevel_promise.ava.js create mode 100644 tests/src/highlevel-promise.js diff --git a/lib/api.js b/lib/api.js index a1ff7bb61..3ddde250c 100644 --- a/lib/api.js +++ b/lib/api.js @@ -140,6 +140,7 @@ export function accountLockedBalance() { return env.account_locked_balance(); } export function valueReturn(value) { + log('valueReturn'); env.value_return(value); } export function promiseCreate(accountId, methodName, args, amount, gas) { @@ -204,6 +205,7 @@ export function promiseResult(resultIdx) { } } export function promiseReturn(promiseIdx) { + log('promiseReturn'); env.promise_return(promiseIdx); } export function storageWrite(key, value) { diff --git a/lib/promise.js b/lib/promise.js index 1b4f0a507..f71c0010f 100644 --- a/lib/promise.js +++ b/lib/promise.js @@ -225,6 +225,6 @@ export class NearPromise { } // Called by NearBindgen, when return object is a NearPromise instance. onReturn() { - this.constructRecursively(); + this.asReturn().constructRecursively(); } } diff --git a/package.json b/package.json index 6628130c3..4d9e127ad 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,6 @@ "@rollup/plugin-commonjs": "^21.0.1", "@rollup/plugin-node-resolve": "^13.1.1", "@scure/base": "^1.1.1", - "bs58": "^5.0.0", "rollup": "^2.61.1", "rollup-plugin-sourcemaps": "^0.6.3", "yargs": "^17.5.1" diff --git a/src/promise.ts b/src/promise.ts index 1545856a0..7de4799af 100644 --- a/src/promise.ts +++ b/src/promise.ts @@ -220,7 +220,7 @@ export class NearPromise { // Called by NearBindgen, when return object is a NearPromise instance. onReturn() { - this.constructRecursively(); + this.asReturn().constructRecursively(); } } diff --git a/tests/__tests__/test_highlevel_promise.ava.js b/tests/__tests__/test_highlevel_promise.ava.js new file mode 100644 index 000000000..57c0544ba --- /dev/null +++ b/tests/__tests__/test_highlevel_promise.ava.js @@ -0,0 +1,144 @@ +import { Worker } from 'near-workspaces'; +import test from 'ava'; + + +test.before(async t => { + // Init the worker and start a Sandbox server + const worker = await Worker.init(); + + // Prepare sandbox for tests, create accounts, deploy contracts, etx. + const root = worker.rootAccount; + + const highlevelPromise = await root.createSubAccount('highlevel-promise', {initialBalance: '100100N'}); + await highlevelPromise.deploy('build/highlevel-promise.wasm'); + + // Create and deploy callee contract + const calleeContract = await root.createSubAccount('callee-contract'); + await calleeContract.deploy('build/promise_api.wasm'); + + // Test users + const ali = await root.createSubAccount('ali'); + const bob = await root.createSubAccount('bob'); + + // Save state for test runs + t.context.worker = worker; + t.context.accounts = { root, highlevelPromise, ali, bob, calleeContract }; +}); + +test.after(async t => { + await t.context.worker.tearDown().catch(error => { + console.log('Failed to tear down the worker:', error); + }); +}); + +test('highlevel promise create account, transfer', async t => { + const { bob, highlevelPromise } = t.context.accounts; + + let r = await bob.callRaw(highlevelPromise, 'test_promise_batch_create_transfer', '', {gas: '100 Tgas'}); + t.is(r.result.receipts_outcome[1].outcome.executor_id, highlevelPromise.getSubAccount('a').accountId); + t.is(r.result.receipts_outcome[1].outcome.status.SuccessValue, ''); + + let balance = await highlevelPromise.getSubAccount('a').balance() + t.is(balance.total.toString(), '10000000000000000000000000') +}); + +test('highlevel promise stake', async t => { + const { highlevelPromise } = t.context.accounts; + await highlevelPromise.callRaw(highlevelPromise, 'test_promise_batch_stake', '', {gas: '100 Tgas'}); + let balance = await highlevelPromise.balance(); + t.is(balance.staked.toString(), '100000000000000000000000000000'); +}); + +test('highlevel promise add full access key', async t => { + const { bob, highlevelPromise } = t.context.accounts; + let r = await bob.callRaw(highlevelPromise, 'test_promise_add_full_access_key', '', {gas: '100 Tgas'}); + t.is(r.result.status.SuccessValue, ''); +}); + +test('highlevel promise add function call key', async t => { + const { bob, highlevelPromise } = t.context.accounts; + let r = await bob.callRaw(highlevelPromise, 'test_promise_add_function_call_access_key', '', {gas: '100 Tgas'}); + t.is(r.result.status.SuccessValue, ''); +}); + +test('highlevel promise delete account', async t => { + const { bob, highlevelPromise } = t.context.accounts; + let r = await bob.callRaw(highlevelPromise, 'test_delete_account', '', {gas: '100 Tgas'}); + t.is(r.result.status.SuccessValue, ''); + t.is(await highlevelPromise.getSubAccount('e').exists(), false); +}); + +test('highlevel promise then', async t => { + const { ali, highlevelPromise, calleeContract } = t.context.accounts; + let r = await ali.callRaw(highlevelPromise, 'test_promise_then', '', {gas: '70 Tgas'}); + // call the callee + t.is(r.result.receipts_outcome[1].outcome.executor_id, calleeContract.accountId); + t.deepEqual(JSON.parse(Buffer.from(r.result.receipts_outcome[1].outcome.status.SuccessValue, 'base64')), { + currentAccountId: calleeContract.accountId, + signerAccountId: ali.accountId, + predecessorAccountId: highlevelPromise.accountId, + input: 'abc', + }); + + // the callback scheduled by promise_then + t.is(r.result.receipts_outcome[3].outcome.executor_id, highlevelPromise.accountId); + t.deepEqual(JSON.parse(Buffer.from(r.result.receipts_outcome[3].outcome.status.SuccessValue, 'base64')), { + currentAccountId: highlevelPromise.accountId, + signerAccountId: ali.accountId, + predecessorAccountId: highlevelPromise.accountId, + input: '{"callbackArg1":"def"}', + promiseResults: [JSON.stringify({ + currentAccountId: calleeContract.accountId, + signerAccountId: ali.accountId, + predecessorAccountId: highlevelPromise.accountId, + input: 'abc', + })], + callbackArg1: 'def' + }); +}); + +test('highlevel promise and', async t => { + const { ali, highlevelPromise, calleeContract } = t.context.accounts; + let r = await ali.callRaw(highlevelPromise, 'test_promise_and', '', {gas: '150 Tgas'}); + + // console.log(JSON.stringify(r, null, 2)) + // promise and schedule to call the callee + t.is(r.result.receipts_outcome[1].outcome.executor_id, calleeContract.accountId); + t.deepEqual(JSON.parse(Buffer.from(r.result.receipts_outcome[1].outcome.status.SuccessValue, 'base64')), { + currentAccountId: calleeContract.accountId, + signerAccountId: ali.accountId, + predecessorAccountId: highlevelPromise.accountId, + input: 'abc', + }); + + // promise and schedule to call the callee, with different args + t.is(r.result.receipts_outcome[3].outcome.executor_id, calleeContract.accountId); + t.deepEqual(JSON.parse(Buffer.from(r.result.receipts_outcome[3].outcome.status.SuccessValue, 'base64')), { + currentAccountId: calleeContract.accountId, + signerAccountId: ali.accountId, + predecessorAccountId: highlevelPromise.accountId, + input: 'def', + }); + + // the callback scheduled by promise_then on the promise created by promise_and + t.is(r.result.receipts_outcome[5].outcome.executor_id, highlevelPromise.accountId); + t.deepEqual(JSON.parse(Buffer.from(r.result.receipts_outcome[5].outcome.status.SuccessValue, 'base64')), { + currentAccountId: highlevelPromise.accountId, + signerAccountId: ali.accountId, + predecessorAccountId: highlevelPromise.accountId, + input: '{"callbackArg1":"ghi"}', + promiseResults: [JSON.stringify({ + currentAccountId: calleeContract.accountId, + signerAccountId: ali.accountId, + predecessorAccountId: highlevelPromise.accountId, + input: 'abc', + }), JSON.stringify({ + currentAccountId: calleeContract.accountId, + signerAccountId: ali.accountId, + predecessorAccountId: highlevelPromise.accountId, + input: 'def', + })], + callbackArg1: 'ghi', + }); +}); + diff --git a/tests/package.json b/tests/package.json index 1d331f730..925d89cdf 100644 --- a/tests/package.json +++ b/tests/package.json @@ -6,13 +6,14 @@ "type": "module", "scripts": { "postinstall": "cd .. && yarn link && cd tests && yarn link near-sdk-js", - "build": "yarn build:context-api && yarn build:math-api && yarn build:storage-api && yarn build:log-panic-api && yarn build:promise-api && yarn build:promise-batch-api && yarn build:function-params && yarn build:lookup-map && yarn build:lookup-set && yarn build:unordered-map && yarn build:unordered-set && yarn build:vector && yarn build:bytes && yarn build:typescript && yarn build:public-key && yarn build:near-bindgen", + "build": "yarn build:context-api && yarn build:math-api && yarn build:storage-api && yarn build:log-panic-api && yarn build:promise-api && yarn build:promise-batch-api && yarn build:function-params && yarn build:lookup-map && yarn build:lookup-set && yarn build:unordered-map && yarn build:unordered-set && yarn build:vector && yarn build:bytes && yarn build:typescript && yarn build:public-key && yarn build:near-bindgen && yarn build:highlevel-promise", "build:context-api": "near-sdk-js build src/context_api.js build/context_api.wasm", "build:math-api": "near-sdk-js build src/math_api.js build/math_api.wasm", "build:storage-api": "near-sdk-js build src/storage_api.js build/storage_api.wasm", "build:log-panic-api": "near-sdk-js build src/log_panic_api.js build/log_panic_api.wasm", "build:promise-api": "near-sdk-js build src/promise_api.js build/promise_api.wasm", "build:promise-batch-api": "near-sdk-js build src/promise_batch_api.js build/promise_batch_api.wasm", + "build:highlevel-promise": "near-sdk-js build src/highlevel-promise.js build/highlevel-promise.wasm", "build:function-params": "near-sdk-js build src/function-params.js build/function-params.wasm", "build:lookup-map": "near-sdk-js build src/lookup-map.js build/lookup-map.wasm", "build:lookup-set": "near-sdk-js build src/lookup-set.js build/lookup-set.wasm", @@ -29,6 +30,7 @@ "test:storage-api": "ava __tests__/test_storage_api.ava.js", "test:log-panic-api": "ava __tests__/test_log_panic_api.ava.js", "test:promise-api": "ava __tests__/test_promise_api.ava.js", + "test:highlevel-promise": "ava __tests__/test_highlevel_promise.ava.js", "test:function-params": "ava __tests__/function-params.ava.js", "test:lookup-map": "ava __tests__/lookup-map.ava.js", "test:lookup-set": "ava __tests__/lookup-set.ava.js", diff --git a/tests/src/highlevel-promise.js b/tests/src/highlevel-promise.js new file mode 100644 index 000000000..47e0216c6 --- /dev/null +++ b/tests/src/highlevel-promise.js @@ -0,0 +1,87 @@ +import {NearBindgen, call, view, NearPromise, near, bytes} from 'near-sdk-js' +import { PublicKey } from 'near-sdk-js/lib/types'; + +function callingData() { + return { + currentAccountId: near.currentAccountId(), + signerAccountId: near.signerAccountId(), + predecessorAccountId: near.predecessorAccountId(), + input: near.input(), + } +} + +function arrayN(n) { + return [...Array(Number(n)).keys()] +} + +@NearBindgen({}) +class HighlevelPromiseContract { + @call + test_promise_batch_stake() { + let promise = NearPromise.new('highlevel-promise.test.near') + .stake(100000000000000000000000000000n, new PublicKey(near.signerAccountPk())) + + return promise; + } + + @call + test_promise_batch_create_transfer() { + let promise = NearPromise.new('a.highlevel-promise.test.near') + .createAccount() + .transfer(10000000000000000000000000n) + return promise; + } + + @call + test_promise_add_full_access_key() { + let promise = NearPromise.new('c.highlevel-promise.test.near') + .createAccount() + .transfer(10000000000000000000000000n) + .addFullAccessKey(new PublicKey(near.signerAccountPk())) + return promise; + } + + @call + test_promise_add_function_call_access_key() { + let promise = NearPromise.new('d.highlevel-promise.test.near') + .createAccount() + .transfer(10000000000000000000000000n) + .addAccessKey(new PublicKey(near.signerAccountPk()), 250000000000000000000000n, 'highlevel-promise.test.near', 'test_promise_batch_create_transfer') + return promise; + } + + @call + test_delete_account() { + let promise = NearPromise.new('e.highlevel-promise.test.near') + .createAccount() + .transfer(10000000000000000000000000n) + .deleteAccount(near.signerAccountId()) + return promise; + } + + @call + test_promise_then() { + let promise = NearPromise.new('callee-contract.test.near') + .functionCall('cross_contract_callee', bytes('abc'), 0, 2 * Math.pow(10, 13)) + .then(NearPromise.new('highlevel-promise.test.near').functionCall('cross_contract_callback', bytes(JSON.stringify({callbackArg1: 'def'})), 0, 2 * Math.pow(10, 13))) + return promise; + } + + @call + test_promise_and() { + let promise = NearPromise.new('callee-contract.test.near') + .functionCall('cross_contract_callee', bytes('abc'), 0, 2 * Math.pow(10, 13)) + let promise2 = NearPromise.new('callee-contract.test.near') + .functionCall('cross_contract_callee', bytes('def'), 0, 2 * Math.pow(10, 13)) + let retPromise = promise.and(promise2).then( + NearPromise.new('highlevel-promise.test.near') + .functionCall('cross_contract_callback', bytes(JSON.stringify({callbackArg1: 'ghi'})), 0, 3 * Math.pow(10, 13))) + + return retPromise; + } + + @call + cross_contract_callback({callbackArg1}) { + return {...callingData(), promiseResults: arrayN(near.promiseResultsCount()).map(i => near.promiseResult(i)), callbackArg1} + } +} \ No newline at end of file