diff --git a/examples/__tests__/test-cross-contract-call-ts.ava.js b/examples/__tests__/test-cross-contract-call-ts.ava.js new file mode 100644 index 000000000..773d718f1 --- /dev/null +++ b/examples/__tests__/test-cross-contract-call-ts.ava.js @@ -0,0 +1,81 @@ +import { Worker } from "near-workspaces"; +import test from "ava"; + +test.beforeEach(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; + + // Deploy status-message the contract. + const statusMessage = await root.devDeploy("./build/status-message.wasm"); + + // Deploy the onCall contract. + const onCall = await root.devDeploy("./build/cross-contract-call-ts.wasm"); + + // Init the contract + await onCall.call(onCall, "init", { + statusMessageContract: statusMessage.accountId, + }); + + // Create test accounts + const ali = await root.createSubAccount("ali"); + const bob = await root.createSubAccount("bob"); + + // Save state for test runs, it is unique for each test + t.context.worker = worker; + t.context.accounts = { + root, + statusMessage, + onCall, + ali, + bob, + }; +}); + +test.afterEach.always(async (t) => { + await t.context.worker.tearDown().catch((error) => { + console.log("Failed tear down the worker:", error); + }); +}); + +test("Nobody is on-call in the beginning", async (t) => { + const { onCall } = t.context.accounts; + const result = await onCall.view("person_on_call", {}); + t.is(result, ""); +}); + +test("Person can be set on-call if AVAILABLE", async (t) => { + const { ali, bob, onCall, statusMessage } = t.context.accounts; + + // Ali set her status as AVAILABLE + await ali.call(statusMessage, "set_status", { message: "AVAILABLE" }); + // Bob sets Ali on-call + await bob.call( + onCall, + "set_person_on_call", + { accountId: ali.accountId }, + { gas: 120000000000000 } + ); + + // Check that Ali is on-call + t.is(await onCall.view("person_on_call", {}), ali.accountId); +}); + +test("Person can NOT be set on-call if UNAVAILABLE", async (t) => { + const { ali, bob, onCall, statusMessage } = t.context.accounts; + + // Ali set her status as AVAILABLE + await ali.call(statusMessage, "set_status", { message: "UNAVAILABLE" }); + // Bob tries to sets Ali on-call + await bob.call( + onCall, + "set_person_on_call", + { accountId: ali.accountId }, + { gas: 120000000000000 } + ); + + // Check that Ali is NOT on-call + t.not(await onCall.view("person_on_call", {}), ali.accountId); +}); diff --git a/examples/package.json b/examples/package.json index e1220ca31..55897f4b3 100644 --- a/examples/package.json +++ b/examples/package.json @@ -16,6 +16,7 @@ "build:counter-lowlevel": "near-sdk-js build src/counter-lowlevel.js build/counter-lowlevel.wasm", "build:counter-ts": "near-sdk-js build src/counter.ts build/counter-ts.wasm", "build:cross-contract-call": "near-sdk-js build src/status-message.js build/status-message.wasm && near-sdk-js build src/cross-contract-call.js build/cross-contract-call.wasm", + "build:cross-contract-call-ts": "near-sdk-js build src/status-message.js build/status-message.wasm && near-sdk-js build src/cross-contract-call.ts build/cross-contract-call-ts.wasm", "build:cross-contract-call-loop": "near-sdk-js build src/counter.js build/counter.wasm && near-sdk-js build src/cross-contract-call-loop.js build/cross-contract-call-loop.wasm", "build:fungible-token-lockable": "near-sdk-js build src/fungible-token-lockable.js build/fungible-token-lockable.wasm", "build:fungible-token": "near-sdk-js build src/fungible-token.ts build/fungible-token.wasm && near-sdk-js build src/fungible-token-helper.ts build/fungible-token-helper.wasm", @@ -43,6 +44,7 @@ "test:counter-lowlevel": "COUNTER_LOWLEVEL=1 ava __tests__/test-counter.ava.js", "test:counter-ts": "COUNTER_TS=1 ava __tests__/test-counter.ava.js", "test:cross-contract-call": "ava __tests__/test-cross-contract-call.ava.js", + "test:cross-contract-call-ts": "ava __tests__/test-cross-contract-call-ts.ava.js", "test:cross-contract-call-loop": "ava __tests__/test-cross-contract-call-loop.ava.js", "test:fungible-token-lockable": "ava __tests__/test-fungible-token-lockable.ava.js", "test:fungible-token": "ava __tests__/test-fungible-token.ava.js", diff --git a/examples/src/cross-contract-call.ts b/examples/src/cross-contract-call.ts new file mode 100644 index 000000000..9d65938be --- /dev/null +++ b/examples/src/cross-contract-call.ts @@ -0,0 +1,52 @@ +import { NearBindgen, call, view, initialize, near, bytes } from "near-sdk-js"; + +@NearBindgen({ requireInit: true }) +export class OnCall { + personOnCall:string =""; + statusMessageContract:string =""; + + @initialize({}) + init({ statusMessageContract }) { + this.statusMessageContract = statusMessageContract; + } + + @call({}) + set_person_on_call({ accountId }) { + near.log(`Trying to set ${accountId} on-call`); + const promise = near.promiseBatchCreate(this.statusMessageContract); + near.promiseBatchActionFunctionCall( + promise, + "get_status", + JSON.stringify({ account_id: accountId }), + 0, + 30000000000000 + ); + near.promiseThen( + promise, + near.currentAccountId(), + "_set_person_on_call_private", + JSON.stringify({ accountId: accountId }), + 0, + 30000000000000 + ); + } + + @call({ privateFunction: true }) + _set_person_on_call_private({ accountId }) { + near.log(`_set_person_on_call_private called, accountId ${accountId}`); + const status = JSON.parse(near.promiseResult(0)); + near.log(`${accountId} status is ${status}`); + if (status === "AVAILABLE") { + this.personOnCall = accountId; + near.log(`${accountId} set on-call`); + } else { + near.log(`${accountId} can not be set on-call`); + } + } + + @view({}) + person_on_call() { + near.log(`Returning person on-call: ${this.personOnCall}`); + return this.personOnCall; + } +} diff --git a/packages/near-sdk-js/lib/utils.d.ts b/packages/near-sdk-js/lib/utils.d.ts index 805f92b74..616adccd0 100644 --- a/packages/near-sdk-js/lib/utils.d.ts +++ b/packages/near-sdk-js/lib/utils.d.ts @@ -5,13 +5,10 @@ export interface Env { latin1_string_to_uint8array(s: string): Uint8Array; utf8_string_to_uint8array(s: string): Uint8Array; } -declare enum PromiseIndexBrand { - _ = -1 -} /** * A PromiseIndex which represents the ID of a NEAR Promise. */ -export declare type PromiseIndex = (number | bigint) & PromiseIndexBrand; +export declare type PromiseIndex = number | bigint; /** * A number that specifies the amount of NEAR in yoctoNEAR. */ @@ -95,4 +92,3 @@ export declare function decode(a: Uint8Array): string; export interface IntoStorageKey { into_storage_key(): string; } -export {}; diff --git a/packages/near-sdk-js/lib/utils.js b/packages/near-sdk-js/lib/utils.js index 45e34e83f..395c825bc 100644 --- a/packages/near-sdk-js/lib/utils.js +++ b/packages/near-sdk-js/lib/utils.js @@ -1,9 +1,4 @@ import { cloneDeep } from "lodash-es"; -// make PromiseIndex a nominal typing -var PromiseIndexBrand; -(function (PromiseIndexBrand) { - PromiseIndexBrand[PromiseIndexBrand["_"] = -1] = "_"; -})(PromiseIndexBrand || (PromiseIndexBrand = {})); const TYPE_KEY = "typeInfo"; var TypeBrand; (function (TypeBrand) { diff --git a/packages/near-sdk-js/src/utils.ts b/packages/near-sdk-js/src/utils.ts index f611e0d21..7611831bc 100644 --- a/packages/near-sdk-js/src/utils.ts +++ b/packages/near-sdk-js/src/utils.ts @@ -10,14 +10,10 @@ export interface Env { declare const env: Env; -// make PromiseIndex a nominal typing -enum PromiseIndexBrand { - _ = -1, -} /** * A PromiseIndex which represents the ID of a NEAR Promise. */ -export type PromiseIndex = (number | bigint) & PromiseIndexBrand; +export type PromiseIndex = number | bigint; /** * A number that specifies the amount of NEAR in yoctoNEAR. */