diff --git a/examples/src/clean-state.js b/examples/src/clean-state.js index 6d7a379e8..cb9600675 100644 --- a/examples/src/clean-state.js +++ b/examples/src/clean-state.js @@ -2,17 +2,17 @@ import { NearBindgen, call, view, near } from 'near-sdk-js' @NearBindgen({}) class CleanState { - @call + @call({}) clean({ keys }) { keys.forEach(key => near.storageRemove(key)) } - @call + @call({}) put({ key, value }) { near.storageWrite(key, value) } - @view + @view({}) get({ key }) { return near.storageRead(key) diff --git a/examples/src/counter.js b/examples/src/counter.js index 4d214a805..1f898a985 100644 --- a/examples/src/counter.js +++ b/examples/src/counter.js @@ -7,13 +7,13 @@ class Counter { this.count = 0 } - @call + @call({}) increase({ n = 1 }) { this.count += n near.log(`Counter increased to ${this.count}`) } - @call + @call({}) decrease({ n }) { // you can use default argument `n=1` too // this is to illustrate a npm dependency: lodash can be used @@ -25,7 +25,7 @@ class Counter { near.log(`Counter decreased to ${this.count}`) } - @view + @view({}) getCount() { return this.count } diff --git a/examples/src/counter.ts b/examples/src/counter.ts index 501416f9d..9ab98cb63 100644 --- a/examples/src/counter.ts +++ b/examples/src/counter.ts @@ -6,13 +6,13 @@ import { log } from './log' class Counter { count: number = 0; - @call + @call({}) increase({ n = 1 }: { n: number }) { this.count += n near.log(`Counter increased to ${this.count}`) } - @call + @call({}) decrease({ n }: { n: number }) { // you can use default argument `n=1` too // this is to illustrate a npm dependency: lodash can be used @@ -25,7 +25,7 @@ class Counter { log(`Counter decreased to ${this.count}`) } - @view + @view({}) getCount(): number { return this.count } diff --git a/examples/src/cross-contract-call.js b/examples/src/cross-contract-call.js index c99116897..40388903d 100644 --- a/examples/src/cross-contract-call.js +++ b/examples/src/cross-contract-call.js @@ -7,13 +7,13 @@ class OnCall { this.statusMessageContract = '' } - @initialize + @initialize({}) init({ statusMessageContract }) { this.personOnCall = "undefined" this.statusMessageContract = statusMessageContract } - @call + @call({}) set_person_on_call({ accountId }) { near.log(`Trying to set ${accountId} on-call`) const promise = near.promiseBatchCreate(this.statusMessageContract) @@ -21,12 +21,9 @@ class OnCall { near.promiseThen(promise, near.currentAccountId(), '_set_person_on_call_private', bytes(JSON.stringify({ accountId: accountId })), 0, 30000000000000); } - @call + @call({ privateFunction: true }) _set_person_on_call_private({ accountId }) { near.log(`_set_person_on_call_private called, accountId ${accountId}`) - if (near.currentAccountId() !== near.predecessorAccountId()) { - throw Error('Function can be used as a callback only') - } const status = JSON.parse(near.promiseResult(0)) near.log(`${accountId} status is ${status}`) if (status === 'AVAILABLE') { @@ -37,7 +34,7 @@ class OnCall { } } - @view + @view({}) person_on_call() { near.log(`Returning person on-call: ${this.personOnCall}`) return this.personOnCall diff --git a/examples/src/fungible-token-helper.js b/examples/src/fungible-token-helper.js index 68a076e41..fd2bc18a1 100644 --- a/examples/src/fungible-token-helper.js +++ b/examples/src/fungible-token-helper.js @@ -6,13 +6,13 @@ class FungibleTokenHelper { this.data = ""; } - @call + @call({}) ftOnTransfer({ senderId, amount, msg, receiverId }) { const concatString = `[${amount} from ${senderId} to ${receiverId}] ${msg} `; this.data = this.data.concat("", concatString); } - @view + @view({}) getContractData() { return this.data; } diff --git a/examples/src/fungible-token-lockable.js b/examples/src/fungible-token-lockable.js index 8eb235dc7..9b3c36d44 100644 --- a/examples/src/fungible-token-lockable.js +++ b/examples/src/fungible-token-lockable.js @@ -56,7 +56,7 @@ class LockableFungibleToken { this.totalSupply = 0 // Total supply of the all tokens } - @initialize + @initialize({}) init({ prefix, totalSupply }) { this.accounts = new LookupMap(prefix) this.totalSupply = totalSupply @@ -78,7 +78,7 @@ class LockableFungibleToken { this.accounts.set(accountId, account) } - @call + @call({}) setAllowance({ escrowAccountId, allowance }) { let ownerId = near.predecessorAccountId() if (escrowAccountId === ownerId) { @@ -94,7 +94,7 @@ class LockableFungibleToken { this.setAccount(ownerId, account) } - @call + @call({}) lock({ ownerId, lockAmount }) { if (lockAmount <= 0) { throw Error("Can't lock 0 or less tokens") @@ -124,7 +124,7 @@ class LockableFungibleToken { this.setAccount(ownerId, account) } - @call + @call({}) unlock({ ownerId, unlockAmount }) { if (unlockAmount <= 0) { throw Error("Can't unlock 0 or less tokens") @@ -151,7 +151,7 @@ class LockableFungibleToken { this.setAccount(ownerId, account) } - @call + @call({}) transferFrom({ ownerId, newOwnerId, amount }) { if (amount <= 0) { throw Error("Can't transfer 0 or less tokens") @@ -197,32 +197,32 @@ class LockableFungibleToken { this.setAccount(newOwnerId, newAccount) } - @call + @call({}) transfer({ newOwnerId, amount }) { this.transferFrom({ ownerId: near.predecessorAccountId(), newOwnerId, amount }) } - @view + @view({}) getTotalSupply() { return this.totalSupply } - @view + @view({}) getTotalBalance({ ownerId }) { return this.getAccount(ownerId).totalBalance() } - @view + @view({}) getUnlockedBalance({ ownerId }) { return this.getAccount(ownerId).balance } - @view + @view({}) getAllowance({ ownerId, escrowAccountId }) { return this.getAccount(ownerId).getAllowance(escrowAccountId) } - @view + @view({}) getLockedBalance({ ownerId, escrowAccountId }) { return this.getAccount(ownerId).getLockedBalance(escrowAccountId) } diff --git a/examples/src/fungible-token.js b/examples/src/fungible-token.js index 0c3c1f392..0cb6be8dc 100644 --- a/examples/src/fungible-token.js +++ b/examples/src/fungible-token.js @@ -16,7 +16,7 @@ class FungibleToken { this.totalSupply = 0 } - @initialize + @initialize({}) init({ prefix, totalSupply }) { this.accounts = new LookupMap(prefix) this.totalSupply = totalSupply @@ -49,13 +49,13 @@ class FungibleToken { this.internalDeposit({ accountId: receiverId, amount }) } - @call + @call({}) ftTransfer({ receiverId, amount, memo }) { let senderId = near.predecessorAccountId() this.internalTransfer({ senderId, receiverId, amount, memo }) } - @call + @call({}) ftTransferCall({ receiverId, amount, memo, msg }) { let senderId = near.predecessorAccountId() this.internalTransfer({ senderId, receiverId, amount, memo }); @@ -65,12 +65,12 @@ class FungibleToken { return near.promiseReturn(); } - @view + @view({}) ftTotalSupply() { return this.totalSupply } - @view + @view({}) ftBalanceOf({ accountId }) { return this.accounts.get(accountId) || '0' } diff --git a/examples/src/non-fungible-token-receiver.js b/examples/src/non-fungible-token-receiver.js index 3468c59c3..a7e57571a 100644 --- a/examples/src/non-fungible-token-receiver.js +++ b/examples/src/non-fungible-token-receiver.js @@ -6,12 +6,12 @@ class NftContract { this.nonFungibleTokenAccountId = '' } - @initialize + @initialize({}) init({ nonFungibleTokenAccountId }) { this.nonFungibleTokenAccountId = nonFungibleTokenAccountId } - @call + @call({}) nftOnTransfer({ senderId, previousOwnerId, tokenId, msg }) { near.log(`nftOnTransfer called, params: senderId: ${senderId}, previousOwnerId: ${previousOwnerId}, tokenId: ${tokenId}, msg: ${msg}`) assert( diff --git a/examples/src/non-fungible-token.js b/examples/src/non-fungible-token.js index 9d6d214a8..b9fb45c4f 100644 --- a/examples/src/non-fungible-token.js +++ b/examples/src/non-fungible-token.js @@ -14,7 +14,7 @@ class NftContract { this.owner_by_id = new LookupMap('a') } - @initialize + @initialize({}) init({ owner_id, owner_by_id_prefix }) { this.owner_id = owner_id this.owner_by_id = new LookupMap(owner_by_id_prefix) @@ -32,13 +32,13 @@ class NftContract { return owner_id } - @call + @call({}) nftTransfer({ receiver_id, token_id, approval_id, memo }) { let sender_id = near.predecessorAccountId() this.internalTransfer({ sender_id, receiver_id, token_id, approval_id, memo }) } - @call + @call({}) nftTransferCall({ receiver_id, token_id, approval_id, memo, msg }) { near.log(`nftTransferCall called, receiver_id ${receiver_id}, token_id ${token_id}`) let sender_id = near.predecessorAccountId() @@ -49,12 +49,9 @@ class NftContract { near.promiseThen(promise, near.currentAccountId(), '_nftResolveTransfer', bytes(JSON.stringify({ sender_id, receiver_id, token_id })), 0, 30000000000000); } - @call + @call({ privateFunction: true }) _nftResolveTransfer({ sender_id, receiver_id, token_id }) { near.log(`_nftResolveTransfer called, receiver_id ${receiver_id}, token_id ${token_id}`) - if (near.currentAccountId() == !near.predecessorAccountId()) { - throw Error('Function can be used as a callback only') - } const isTokenTransfered = JSON.parse(near.promiseResult(0)) near.log(`${token_id} ${isTokenTransfered ? 'was transfered' : 'was NOT transfered'}`) @@ -70,7 +67,7 @@ class NftContract { } } - @call + @call({}) nftMint({ token_id, token_owner_id, token_metadata }) { let sender_id = near.predecessorAccountId() assert(sender_id === this.owner_id, "Unauthorized") @@ -81,7 +78,7 @@ class NftContract { return new Token(token_id, token_owner_id) } - @view + @view({}) nftToken({ token_id }) { let owner_id = this.owner_by_id.get(token_id) if (owner_id === null) { diff --git a/examples/src/parking-lot.ts b/examples/src/parking-lot.ts index 5aa12c8dc..023eff757 100644 --- a/examples/src/parking-lot.ts +++ b/examples/src/parking-lot.ts @@ -37,7 +37,7 @@ class ParkingLot { this.cars = new LookupMap('a'); } - @call + @call({}) addCar({ name, id, color, price, engineHp }: { name: string, id: number, color: string, price: number, engineHp: number }) { // args can be json arguments only, they cannot be of a JS/TS class like following, unless override NearContract.deserializeArgs method. // addCar({ name, specs }: { name: string, specs: CarSpecs }) { @@ -47,19 +47,19 @@ class ParkingLot { this.cars.set(name, car) } - @call + @call({}) removeCar({ name }: { name: string }) { near.log(`removeCar() called, name: ${name}`) this.cars.remove(name) } - @view + @view({}) getCarSpecs({ name }: { name: string }) { near.log(`getCarSpecs() called, name: ${name}`) return this.cars.get(name) } - @view + @view({}) runCar({ name }: { name: string }) { /* We are getting plain carSpecs object from the storage. It needs to be converted to the class object in order to execute engine.run() function.*/ diff --git a/examples/src/status-message-collections.js b/examples/src/status-message-collections.js index bc080d41b..f84dddfee 100644 --- a/examples/src/status-message-collections.js +++ b/examples/src/status-message-collections.js @@ -7,7 +7,7 @@ class StatusMessage { this.uniqueValues = new LookupSet('b') } - @call + @call({}) set_status({ message }) { let account_id = near.signerAccountId() near.log(`${account_id} set_status with message ${message}`) @@ -15,19 +15,19 @@ class StatusMessage { this.uniqueValues.set(message) } - @view + @view({}) get_status({ account_id }) { near.log(`get_status for account_id ${account_id}`) return this.records.get(account_id) } - @view + @view({}) has_status({ message }) { // used for test LookupMap return this.uniqueValues.contains(message) } - @view + @view({}) get_all_statuses() { // used for test UnorderedMap return this.records.toArray() diff --git a/examples/src/status-message.js b/examples/src/status-message.js index caf37f2d8..7ec2168fa 100644 --- a/examples/src/status-message.js +++ b/examples/src/status-message.js @@ -6,14 +6,14 @@ class StatusMessage { this.records = {} } - @call + @call({}) set_status({ message }) { let account_id = near.signerAccountId() near.log(`${account_id} set_status with message ${message}`) this.records[account_id] = message } - @view + @view({}) get_status({ account_id }) { near.log(`get_status for account_id ${account_id}`) return this.records[account_id] || null diff --git a/lib/build-tools/near-bindgen-exporter.js b/lib/build-tools/near-bindgen-exporter.js index 08bb18c10..4a201dd08 100644 --- a/lib/build-tools/near-bindgen-exporter.js +++ b/lib/build-tools/near-bindgen-exporter.js @@ -9,15 +9,15 @@ export default function () { let contractMethods = {}; for (let child of classNode.body.body) { if (child.type == 'ClassMethod' && child.kind == 'method' && child.decorators) { - if (child.decorators[0].expression.name == 'call') { + if (child.decorators[0].expression.callee.name == 'call') { let callMethod = child.key.name; contractMethods[callMethod] = 'call'; } - else if (child.decorators[0].expression.name == 'view') { + else if (child.decorators[0].expression.callee.name == 'view') { let viewMethod = child.key.name; contractMethods[viewMethod] = 'view'; } - else if (child.decorators[0].expression.name == 'initialize') { + else if (child.decorators[0].expression.callee.name == 'initialize') { let initMethod = child.key.name; contractMethods[initMethod] = 'initialize'; } diff --git a/lib/near-bindgen.d.ts b/lib/near-bindgen.d.ts index d3efdeda1..67608c49d 100644 --- a/lib/near-bindgen.d.ts +++ b/lib/near-bindgen.d.ts @@ -1,6 +1,9 @@ -export declare function initialize(target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor): void; -export declare function call(target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor): void; -export declare function view(target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor): void; +export declare function initialize({}: {}): (target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor) => void; +export declare function call({ privateFunction, payableFunction }: { + privateFunction?: boolean; + payableFunction?: boolean; +}): (target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor) => void; +export declare function view({}: {}): (target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor) => void; export declare function NearBindgen({ requireInit }: { requireInit?: boolean; }): {}>(target: T) => { diff --git a/lib/near-bindgen.js b/lib/near-bindgen.js index 07a6c7e11..d266db78c 100644 --- a/lib/near-bindgen.js +++ b/lib/near-bindgen.js @@ -1,9 +1,25 @@ import * as near from "./api"; -export function initialize(target, key, descriptor) { +export function initialize({}) { + return function (target, key, descriptor) { + }; } -export function call(target, key, descriptor) { +export function call({ privateFunction = false, payableFunction = false }) { + return function (target, key, descriptor) { + const originalMethod = descriptor.value; + descriptor.value = function (...args) { + if (privateFunction && near.predecessorAccountId() !== near.currentAccountId()) { + throw Error("Function is private"); + } + if (!payableFunction && near.attachedDeposit() > BigInt(0)) { + throw Error("Function is not payable"); + } + return originalMethod.apply(this, args); + }; + }; } -export function view(target, key, descriptor) { +export function view({}) { + return function (target, key, descriptor) { + }; } export function NearBindgen({ requireInit = false }) { return (target) => { diff --git a/src/build-tools/near-bindgen-exporter.js b/src/build-tools/near-bindgen-exporter.js index 7b2483ca0..f4e4335be 100644 --- a/src/build-tools/near-bindgen-exporter.js +++ b/src/build-tools/near-bindgen-exporter.js @@ -10,15 +10,15 @@ export default function () { let contractMethods = {}; for (let child of classNode.body.body) { if (child.type == 'ClassMethod' && child.kind == 'method' && child.decorators) { - if (child.decorators[0].expression.name == 'call') { + if (child.decorators[0].expression.callee.name == 'call') { let callMethod = child.key.name; contractMethods[callMethod] = 'call'; } - else if (child.decorators[0].expression.name == 'view') { + else if (child.decorators[0].expression.callee.name == 'view') { let viewMethod = child.key.name; contractMethods[viewMethod] = 'view'; } - else if (child.decorators[0].expression.name == 'initialize') { + else if (child.decorators[0].expression.callee.name == 'initialize') { let initMethod = child.key.name; contractMethods[initMethod] = 'initialize'; } diff --git a/src/near-bindgen.ts b/src/near-bindgen.ts index 9cf0d0ec6..9b9d40f87 100644 --- a/src/near-bindgen.ts +++ b/src/near-bindgen.ts @@ -1,12 +1,28 @@ import * as near from "./api"; -export function initialize(target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor): void { +export function initialize({ }) { + return function (target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor): void { + } } -export function call(target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor): void { +export function call({ privateFunction = false, payableFunction = false }: { privateFunction?: boolean, payableFunction?: boolean }) { + return function (target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor): void { + const originalMethod = descriptor.value; + descriptor.value = function (...args: any[]) { + if (privateFunction && near.predecessorAccountId() !== near.currentAccountId()) { + throw Error("Function is private"); + } + if (!payableFunction && near.attachedDeposit() > BigInt(0)) { + throw Error("Function is not payable"); + } + return originalMethod.apply(this, args); + } + } } -export function view(target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor): void { +export function view({ }) { + return function (target: Object, key: string | symbol, descriptor: TypedPropertyDescriptor): void { + } } export function NearBindgen({ requireInit = false }: { requireInit?: boolean }) { diff --git a/tests/__tests__/near_bindgen.ava.js b/tests/__tests__/decorators/near_bindgen.ava.js similarity index 100% rename from tests/__tests__/near_bindgen.ava.js rename to tests/__tests__/decorators/near_bindgen.ava.js diff --git a/tests/__tests__/decorators/payable.ava.js b/tests/__tests__/decorators/payable.ava.js new file mode 100644 index 000000000..44c3c2940 --- /dev/null +++ b/tests/__tests__/decorators/payable.ava.js @@ -0,0 +1,61 @@ +import { Worker } from 'near-workspaces'; +import test from 'ava'; + +const DEPOSIT = 1_000_000_000; + +test.beforeEach(async t => { + const worker = await Worker.init(); + const root = worker.rootAccount; + + const payableContract = await root.devDeploy('build/payable.wasm'); + const ali = await root.createSubAccount('ali'); + + t.context.worker = worker; + t.context.accounts = { + root, + payableContract, + ali, + }; +}); + + +test.afterEach(async t => { + await t.context.worker.tearDown().catch(error => { + console.log('Failed to tear down the worker:', error); + }); +}); + +test('payable: true functions works with deposit', async t => { + const { ali, payableContract } = t.context.accounts; + + await t.notThrowsAsync(ali.call(payableContract, 'setValueWithPayableFunction', { value: 'hello' }, { attachedDeposit: DEPOSIT })); + +}) + +test('payable: true functions works without deposit', async t => { + const { ali, payableContract } = t.context.accounts; + + await t.notThrowsAsync(ali.call(payableContract, 'setValueWithPayableFunction', { value: 'hello' })); + +}) + +test('payable: false throws if atach deposit', async t => { + const { ali, payableContract } = t.context.accounts; + + const result = await ali.callRaw(payableContract, 'setValueWithNotPayableFunction', { value: 'hello' }, { attachedDeposit: DEPOSIT }); + + t.assert(result.result.status.Failure.ActionError.kind.FunctionCallError.ExecutionError.includes('Function is not payable')); +}) + +test('payable default throws if atach deposit', async t => { + const { ali, payableContract } = t.context.accounts; + + const result = await ali.callRaw(payableContract, 'setValueWithNotPayableFunctionByDefault', { value: 'hello' }, { attachedDeposit: DEPOSIT }); + t.assert(result.result.status.Failure.ActionError.kind.FunctionCallError.ExecutionError.includes('Function is not payable')); +}) + +test('payable default works without deposit', async t => { + const { ali, payableContract } = t.context.accounts; + + await t.notThrowsAsync(ali.call(payableContract, 'setValueWithNotPayableFunctionByDefault', { value: 'hello' })); +}) diff --git a/tests/__tests__/decorators/private.ava.js b/tests/__tests__/decorators/private.ava.js new file mode 100644 index 000000000..69b4fa509 --- /dev/null +++ b/tests/__tests__/decorators/private.ava.js @@ -0,0 +1,46 @@ +import { Worker } from 'near-workspaces'; +import test from 'ava'; + +test.beforeEach(async t => { + const worker = await Worker.init(); + const root = worker.rootAccount; + + const contract = await root.devDeploy('build/private.wasm'); + const ali = await root.createSubAccount('ali'); + + t.context.worker = worker; + t.context.accounts = { + root, + contract, + ali, + }; +}); + + +test.afterEach(async t => { + await t.context.worker.tearDown().catch(error => { + console.log('Failed to tear down the worker:', error); + }); +}); + +test('private: true throws if called from another acc', async t => { + const { ali, contract } = t.context.accounts; + + const result = await ali.callRaw(contract, 'setValueWithPrivateFunction', { value: 'hello' }); + + t.assert(result.result.status.Failure.ActionError.kind.FunctionCallError.ExecutionError.includes('Function is private')); + +}) + +test('private: true not throws if called from owner acc', async t => { + const { contract } = t.context.accounts; + + await t.notThrowsAsync(contract.call(contract, 'setValueWithNotPrivateFunction', { value: 'hello' })); + +}) + +test('private: default not throws from another acc', async t => { + const { ali, contract } = t.context.accounts; + + await t.notThrowsAsync(ali.call(contract, 'setValueWithNotPrivateFunctionByDefault', { value: 'hello' })); +}) diff --git a/tests/package.json b/tests/package.json index 925d89cdf..437911369 100644 --- a/tests/package.json +++ b/tests/package.json @@ -6,7 +6,7 @@ "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 && yarn build:highlevel-promise", + "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:payable && yarn build:private && 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", @@ -23,7 +23,9 @@ "build:bytes": "near-sdk-js build src/bytes.js build/bytes.wasm", "build:typescript": "near-sdk-js build src/typescript.ts build/typescript.wasm", "build:public-key": "near-sdk-js build src/public-key.js build/public-key.wasm", - "build:near-bindgen": "near-sdk-js build src/near_bindgen/require_init_true.ts build/require_init_true.wasm && near-sdk-js build src/near_bindgen/require_init_false.ts build/require_init_false.wasm", + "build:near-bindgen": "near-sdk-js build src/decorators/require_init_true.ts build/require_init_true.wasm && near-sdk-js build src/decorators/require_init_false.ts build/require_init_false.wasm", + "build:payable": "near-sdk-js build src/decorators/payable.ts build/payable.wasm", + "build:private": "near-sdk-js build src/decorators/private.ts build/private.wasm", "test": "ava", "test:context-api": "ava __tests__/test_context_api.ava.js", "test:math-api": "ava __tests__/test_math_api.ava.js", @@ -40,7 +42,9 @@ "test:bytes": "ava __tests__/bytes.ava.js", "test:typescript": "ava __tests__/typescript.ava.js", "test:public-key": "ava __tests__/test-public-key.ava.js", - "test:near-bindgen": "ava __tests__/near_bindgen.ava.js" + "test:near-bindgen": "ava __tests__/decorators/near_bindgen.ava.js", + "test:payable": "ava __tests__/decorators/payable.ava.js", + "test:private": "ava __tests__/decorators/private.ava.js" }, "author": "Near Inc ", "license": "Apache-2.0", diff --git a/tests/src/decorators/payable.ts b/tests/src/decorators/payable.ts new file mode 100644 index 000000000..d1e6d9819 --- /dev/null +++ b/tests/src/decorators/payable.ts @@ -0,0 +1,38 @@ +import { + near, + NearBindgen, + call, + view, +} from 'near-sdk-js' + +@NearBindgen({}) +class PayableTest { + value: string; + + constructor() { + this.value = ''; + } + + @call({ payableFunction: true }) + setValueWithPayableFunction({ value }: { value: string }): void { + near.log(`payableFunction: ${value}`) + this.value = value; + } + + @call({ payableFunction: false }) + setValueWithNotPayableFunction({ value }: { value: string }): void { + near.log(`notPayableFunction: ${value}`) + this.value = value; + } + + @call({}) + setValueWithNotPayableFunctionByDefault({ value }: { value: string }): void { + near.log(`notPayableFunctionDefault: ${value}`) + this.value = value; + } + + @view({}) + getValue(): string { + return this.value; + } +} diff --git a/tests/src/decorators/private.ts b/tests/src/decorators/private.ts new file mode 100644 index 000000000..f3a6a9018 --- /dev/null +++ b/tests/src/decorators/private.ts @@ -0,0 +1,38 @@ +import { + near, + NearBindgen, + call, + view, +} from 'near-sdk-js' + +@NearBindgen({}) +class PrivateTest { + value: string; + + constructor() { + this.value = ''; + } + + @call({ privateFunction: true }) + setValueWithPrivateFunction({ value }: { value: string }): void { + near.log(`setValueWithPrivateFunction: ${value}`) + this.value = value; + } + + @call({ privateFunction: false }) + setValueWithNotPrivateFunction({ value }: { value: string }): void { + near.log(`setValueWithNotPrivateFunction: ${value}`) + this.value = value; + } + + @call({}) + setValueWithNotPrivateFunctionByDefault({ value }: { value: string }): void { + near.log(`setValueWithNotPrivateFunctionByDefault: ${value}`) + this.value = value; + } + + @view({}) + getValue(): string { + return this.value; + } +} diff --git a/tests/src/near_bindgen/require_init_false.ts b/tests/src/decorators/require_init_false.ts similarity index 92% rename from tests/src/near_bindgen/require_init_false.ts rename to tests/src/decorators/require_init_false.ts index ac348eab9..a8ab954ce 100644 --- a/tests/src/near_bindgen/require_init_false.ts +++ b/tests/src/decorators/require_init_false.ts @@ -14,19 +14,19 @@ class NBTest { this.status = ''; } - @initialize + @initialize({}) init({ status }: { status: string }): void { near.log(`init: ${status}`) this.status = status; } - @view + @view({}) getStatus(): string { near.log(`getStatus: ${this.status}`) return this.status; } - @call + @call({}) setStatus({ status }: { status: string }): void { near.log(`setStatus: ${status}`) this.status = status; diff --git a/tests/src/near_bindgen/require_init_true.ts b/tests/src/decorators/require_init_true.ts similarity index 92% rename from tests/src/near_bindgen/require_init_true.ts rename to tests/src/decorators/require_init_true.ts index 0318086ea..b756f5d8b 100644 --- a/tests/src/near_bindgen/require_init_true.ts +++ b/tests/src/decorators/require_init_true.ts @@ -14,19 +14,19 @@ class NBTest { this.status = ''; } - @initialize + @initialize({}) init({ status }: { status: string }): void { near.log(`init: ${status}`) this.status = status; } - @view + @view({}) getStatus(): string { near.log(`getStatus: ${this.status}`) return this.status; } - @call + @call({}) setStatus({ status }: { status: string }): void { near.log(`setStatus: ${status}`) this.status = status; diff --git a/tests/src/function-params.js b/tests/src/function-params.js index 1156201e2..b6dfa8c02 100644 --- a/tests/src/function-params.js +++ b/tests/src/function-params.js @@ -16,7 +16,7 @@ class FunctionParamsTestContract { this.val3 = 'default3'; } - @call + @call({}) set_values({ param1, param2, param3 }) { near.log(JSON.stringify({ param1, param2, param3 })); this.val1 = param1; @@ -24,7 +24,7 @@ class FunctionParamsTestContract { this.val3 = param3; } - @view + @view({}) get_values() { return { val3: this.val3, val2: this.val2, val1: this.val1 } } diff --git a/tests/src/highlevel-promise.js b/tests/src/highlevel-promise.js index 47e0216c6..702dd154d 100644 --- a/tests/src/highlevel-promise.js +++ b/tests/src/highlevel-promise.js @@ -16,7 +16,7 @@ function arrayN(n) { @NearBindgen({}) class HighlevelPromiseContract { - @call + @call({}) test_promise_batch_stake() { let promise = NearPromise.new('highlevel-promise.test.near') .stake(100000000000000000000000000000n, new PublicKey(near.signerAccountPk())) @@ -24,7 +24,7 @@ class HighlevelPromiseContract { return promise; } - @call + @call({}) test_promise_batch_create_transfer() { let promise = NearPromise.new('a.highlevel-promise.test.near') .createAccount() @@ -32,7 +32,7 @@ class HighlevelPromiseContract { return promise; } - @call + @call({}) test_promise_add_full_access_key() { let promise = NearPromise.new('c.highlevel-promise.test.near') .createAccount() @@ -41,7 +41,7 @@ class HighlevelPromiseContract { return promise; } - @call + @call({}) test_promise_add_function_call_access_key() { let promise = NearPromise.new('d.highlevel-promise.test.near') .createAccount() @@ -50,7 +50,7 @@ class HighlevelPromiseContract { return promise; } - @call + @call({}) test_delete_account() { let promise = NearPromise.new('e.highlevel-promise.test.near') .createAccount() @@ -59,7 +59,7 @@ class HighlevelPromiseContract { return promise; } - @call + @call({}) test_promise_then() { let promise = NearPromise.new('callee-contract.test.near') .functionCall('cross_contract_callee', bytes('abc'), 0, 2 * Math.pow(10, 13)) @@ -67,7 +67,7 @@ class HighlevelPromiseContract { return promise; } - @call + @call({}) test_promise_and() { let promise = NearPromise.new('callee-contract.test.near') .functionCall('cross_contract_callee', bytes('abc'), 0, 2 * Math.pow(10, 13)) @@ -80,7 +80,7 @@ class HighlevelPromiseContract { return retPromise; } - @call + @call({}) cross_contract_callback({callbackArg1}) { return {...callingData(), promiseResults: arrayN(near.promiseResultsCount()).map(i => near.promiseResult(i)), callbackArg1} } diff --git a/tests/src/lookup-map.js b/tests/src/lookup-map.js index a4fb5c795..b57b77b7e 100644 --- a/tests/src/lookup-map.js +++ b/tests/src/lookup-map.js @@ -12,37 +12,37 @@ class LookupMapTestContract { this.lookupMap = new LookupMap('a'); } - @view + @view({}) get({ key }) { return this.lookupMap.get(key); } - @view + @view({}) containsKey({ key }) { return this.lookupMap.containsKey(key); } - @call + @call({}) set({ key, value }) { this.lookupMap.set(key, value); } - @call + @call({}) remove_key({ key }) { this.lookupMap.remove(key); } - @call + @call({}) extend({ kvs }) { this.lookupMap.extend(kvs); } - @call + @call({}) add_house() { this.lookupMap.set('house1', new House('house1', [new Room('room1', '200sqft'), new Room('room2', '300sqft')])) } - @view + @view({}) get_house() { const houseObject = this.lookupMap.get('house1') // restore class object from serialized data diff --git a/tests/src/lookup-set.js b/tests/src/lookup-set.js index e9166e68f..458c3ac87 100644 --- a/tests/src/lookup-set.js +++ b/tests/src/lookup-set.js @@ -12,27 +12,27 @@ class LookupSetTestContract { this.lookupSet = new LookupSet('a'); } - @view + @view({}) contains({ key }) { return this.lookupSet.contains(key); } - @call + @call({}) set({ key }) { this.lookupSet.set(key); } - @call + @call({}) remove_key({ key }) { this.lookupSet.remove(key); } - @call + @call({}) extend({ keys }) { this.lookupSet.extend(keys); } - @call + @call({}) add_house({ name, rooms }) { let house = new House(name, []) for (let r of rooms) { @@ -41,7 +41,7 @@ class LookupSetTestContract { this.lookupSet.set(house) } - @view + @view({}) house_exist({ name, rooms }) { let house = new House(name, []) for (let r of rooms) { diff --git a/tests/src/typescript.ts b/tests/src/typescript.ts index 0ae82c25f..f9478cace 100644 --- a/tests/src/typescript.ts +++ b/tests/src/typescript.ts @@ -5,7 +5,7 @@ import { @NearBindgen({}) class TypeScriptTestContract { - @view + @view({}) bigint() { // JSON.stringify cannot seriaize a BigInt, need manually toString return (1n + 2n).toString() diff --git a/tests/src/unordered-map.js b/tests/src/unordered-map.js index d4bddfaa9..9c8978012 100644 --- a/tests/src/unordered-map.js +++ b/tests/src/unordered-map.js @@ -12,52 +12,52 @@ class UnorderedMapTestContract { this.unorderedMap = new UnorderedMap('a'); } - @view + @view({}) len() { return this.unorderedMap.length; } - @view + @view({}) isEmpty() { return this.unorderedMap.isEmpty(); } - @view + @view({}) get({ key }) { return this.unorderedMap.get(key); } - @call + @call({}) set({ key, value }) { this.unorderedMap.set(key, value); } - @call + @call({}) remove_key({ key }) { this.unorderedMap.remove(key); } - @call + @call({}) clear() { this.unorderedMap.clear(); } - @view + @view({}) toArray() { return this.unorderedMap.toArray(); } - @call + @call({}) extend({ kvs }) { this.unorderedMap.extend(kvs); } - @call + @call({}) add_house() { this.unorderedMap.set('house1', new House('house1', [new Room('room1', '200sqft'), new Room('room2', '300sqft')])) } - @view + @view({}) get_house() { const rawHouse = this.unorderedMap.get('house1') const house = new House(rawHouse.name, rawHouse.rooms) diff --git a/tests/src/unordered-set.js b/tests/src/unordered-set.js index 56a0491a5..b7500c111 100644 --- a/tests/src/unordered-set.js +++ b/tests/src/unordered-set.js @@ -12,48 +12,48 @@ class UnorderedSetTestContract { this.unorderedSet = new UnorderedSet('a'); } - @view + @view({}) len() { return this.unorderedSet.length; } - @view + @view({}) isEmpty() { return this.unorderedSet.isEmpty(); } - @view + @view({}) contains({ element }) { return this.unorderedSet.contains(element); } - @call + @call({}) set({ element }) { this.unorderedSet.set(element); } - @call + @call({}) remove_key({ element }) { this.unorderedSet.remove(element); } - @call + @call({}) clear() { this.unorderedSet.clear(); } - @view + @view({}) toArray() { const res = this.unorderedSet.toArray(); return res; } - @call + @call({}) extend({ elements }) { this.unorderedSet.extend(elements); } - @call + @call({}) add_house({ name, rooms }) { let house = new House(name, []) for (let r of rooms) { @@ -62,7 +62,7 @@ class UnorderedSetTestContract { this.unorderedSet.set(house) } - @view + @view({}) house_exist({ name, rooms }) { let house = new House(name, []) for (let r of rooms) { diff --git a/tests/src/vector.js b/tests/src/vector.js index 07f466b40..ef1570554 100644 --- a/tests/src/vector.js +++ b/tests/src/vector.js @@ -12,62 +12,62 @@ class VectorTestContract { this.vector = new Vector('a'); } - @view + @view({}) len() { return this.vector.length; } - @view + @view({}) isEmpty() { return this.vector.isEmpty(); } - @view + @view({}) get({index}) { return this.vector.get(index); } - @call + @call({}) push({value}) { this.vector.push(value); } - @call + @call({}) pop() { this.vector.pop(); } - @call + @call({}) clear() { this.vector.clear(); } - @view + @view({}) toArray() { return this.vector.toArray(); } - @call + @call({}) extend({kvs}) { this.vector.extend(kvs); } - @call + @call({}) replace({index, value}) { this.vector.replace(index, value); } - @call + @call({}) swapRemove({index}) { this.vector.swapRemove(index); } - @call + @call({}) add_house() { this.vector.push(new House('house1', [new Room('room1', '200sqft'), new Room('room2', '300sqft')])); } - @view + @view({}) get_house() { return this.vector.get(0); }