From 346646d232f83438db0a43641f39ae6fedd7939c Mon Sep 17 00:00:00 2001 From: Kieran O'Neill Date: Mon, 24 Jun 2024 10:40:02 +0100 Subject: [PATCH 1/6] feat: move storagebalanceof to a public function and add tests --- docs/api-reference/social.mdx | 39 +++++--- docs/api-reference/types.mdx | 47 ++++++---- .../Social.storageBalanceOf.test.ts | 89 +++++++++++++++++++ src/controllers/Social.ts | 67 +++++++++----- src/types/IStorageBalanceOfResult.ts | 6 ++ src/types/index.ts | 5 +- 6 files changed, 200 insertions(+), 53 deletions(-) create mode 100644 src/controllers/Social.storageBalanceOf.test.ts create mode 100644 src/types/IStorageBalanceOfResult.ts diff --git a/docs/api-reference/social.mdx b/docs/api-reference/social.mdx index 8425ecc..9654b17 100644 --- a/docs/api-reference/social.mdx +++ b/docs/api-reference/social.mdx @@ -117,10 +117,28 @@ Accounts that match the signer's account ID automatically have write permission | [`Promise`](https://near.github.io/near-api-js/classes/near_api_js.transaction.Transaction.html) | A promise that resolves to an unsigned trasnaction that contiains the function call to update the specified data. | +### `storageBalanceOf(options)` + +> Gets the storage balance for a given account ID. + + +#### Parameters + +| Name | Type | Required | Default | Description | +|---------|--------------------------------------------------------------|----------|---------|------------------------------------------------------------------------------------------------------| +| options | [`IStorageBalanceOfOptions`](types#istoragebalanceofoptions) | yes | - | Options that include the account ID to check and a signer account to use to check read the contract. | + +#### Returns + +| Type | Description | +|-----------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------| +| [`Promise`](types#istoragebalanceofresult) | A promise that resolves the total and available balance or null if the account ID does not have a balance. | + + + ### `storageDeposit(options)` > Deposit NEAR to the social DB contract to cover storage costs for a given `account_id` or the signer if `account_id` is not provided. Optionally, you can choose to pay only the bare minimum deposit for registering the account in the Social DB contract without any additional storage fees. -> :::note @@ -130,21 +148,20 @@ The signer account must have sufficient NEAR balance to cover the deposit. #### Parameters -| Name | Type | Required | Default | Description | -|-----------------|--------------------------------------------|----------|---------|-----------------------------------------------------------------------------| -| options | [`IStorageDepositOptions`](types#istorage-deposit-options) | yes | - | Options that include the deposit details, the signer's account and key details. | +| Name | Type | Required | Default | Description | +|---------|------------------------------------------------------------|----------|---------|---------------------------------------------------------------------------------| +| options | [`IStorageDepositOptions`](types#istorage-deposit-options) | yes | - | Options that include the deposit details, the signer's account and key details. | #### Returns -| Type | Description | -|---------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------| +| Type | Description | +|---------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------| | [`Promise`](https://near.github.io/near-api-js/classes/near_api_js.transaction.Transaction.html) | A promise that resolves to an unsigned transaction that contains the function call to deposit the specified amount. | ### `storageWithdraw(options)` > Withdraw NEAR from the social DB contract for covering storage. If the `amount` is not specified, all available NEAR is withdrawn. -> :::note @@ -154,12 +171,12 @@ The signer account must have sufficient NEAR balance available for withdrawal. #### Parameters -| Name | Type | Required | Default | Description | -|---------|--------------------------------------------|----------|---------|-----------------------------------------------------------------------------| +| Name | Type | Required | Default | Description | +|---------|--------------------------------------------------------------|----------|---------|------------------------------------------------------------------------------------| | options | [`IStorageWithdrawOptions`](types#istorage-withdraw-options) | yes | - | Options that include the withdrawal details, the signer's account and key details. | #### Returns -| Type | Description | -|---------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------| +| Type | Description | +|---------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------| | [`Promise`](https://near.github.io/near-api-js/classes/near_api_js.transaction.Transaction.html) | A promise that resolves to an unsigned transaction that contains the function call to withdraw the specified amount. | diff --git a/docs/api-reference/types.mdx b/docs/api-reference/types.mdx index b3f47df..5525373 100644 --- a/docs/api-reference/types.mdx +++ b/docs/api-reference/types.mdx @@ -53,22 +53,37 @@ import TOCInline from '@theme/TOCInline'; | refundUnusedDeposit | `boolean` | no | `false` | If true, will refund any left over deposit to the signer's account. | | signer | [`Account`](https://near.github.io/near-api-js/classes/near_api_js.account.Account.html) | yes | - | An account that will read the data. For details on getting the account object see the NEAR API [docs](https://docs.near.org/tools/near-api-js/account). | -### `IStorageDepositOptions` -| Name | Type | Required | Default | Description | -|---------------------|--------------------------------------------------------------------------------------------------------|----------|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| account_id | `string` | no | - | The account ID for which to deposit storage. Defaults to the signer account if not provided. -| registration_only| `boolean` | no | `false` | If true, deposits the minimum amount required for account registration without additional storage.| -| deposit | `string` | yes | - | The amount of NEAR to deposit for storage, in yoctoNEAR. | | blockHash | `string` | no | - | A current block hash (within 24 hours). Defaults to the latest block hash. | -| nonce | `bigint` | no | - | The access key's nonce. Defaults to the current access key nonce incremented by 1. | -| publicKey | [`PublicKey`](https://near.github.io/near-api-js/classes/near_api_js.utils.PublicKey.html) \| `string` | yes | - | The signer's public key for the access key that will be used to write to the contract. | -| signer | [`Account`](https://near.github.io/near-api-js/classes/near_api_js.account.Account.html) | yes | - | An account that will read the data. For details on getting the account object see the NEAR API [docs](https://docs.near.org/tools/near-api-js/account). | +### `IStorageBalanceOfOptions` + +| Name | Type | Required | Default | Description | +|-----------|------------------------------------------------------------------------------------------|----------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------| +| accountId | `string` | yes | - | The account ID for which to check the balance of. | +| signer | [`Account`](https://near.github.io/near-api-js/classes/near_api_js.account.Account.html) | yes | - | An account that will read the data. For details on getting the account object see the NEAR API [docs](https://docs.near.org/tools/near-api-js/account). | + +### `IStorageBalanceOfResult` + +| Name | Type | Required | Default | Description | +|-----------|----------------------|----------|---------|-------------------------------------------| +| available | `string` | yes | - | The yotoNEAR amount of deposit available. | +| total | `string` | yes | - | The total yotoNEAR amount deposited. | + +### `IStorageDepositResult` + +| Name | Type | Required | Default | Description | +|-------------------|--------------------------------------------------------------------------------------------------------|----------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------| +| account_id | `string` | no | - | The account ID for which to deposit storage. Defaults to the signer account if not provided. | +| registration_only | `boolean` | no | `false` | If true, deposits the minimum amount required for account registration without additional storage. | +| deposit | `string` | yes | - | The amount of NEAR to deposit for storage, in yoctoNEAR. | | blockHash | `string` | no | - | A current block hash (within 24 hours). Defaults to the latest block hash. | +| nonce | `bigint` | no | - | The access key's nonce. Defaults to the current access key nonce incremented by 1. | +| publicKey | [`PublicKey`](https://near.github.io/near-api-js/classes/near_api_js.utils.PublicKey.html) \| `string` | yes | - | The signer's public key for the access key that will be used to write to the contract. | +| signer | [`Account`](https://near.github.io/near-api-js/classes/near_api_js.account.Account.html) | yes | - | An account that will read the data. For details on getting the account object see the NEAR API [docs](https://docs.near.org/tools/near-api-js/account). | ### `IStorageWithdrawOptions` -| Name | Type | Required | Default | Description | -|------------------|--------------------------------------------------------------------------------------------------------|----------|---------|----------------------------------------------------------------------------------------------| -| amount | `string` | no | - | The amount of NEAR to withdraw, in yoctoNEAR. If not specified, withdraws all available NEAR.| -| blockHash | `string` | no | - | A current block hash (within 24 hours). Defaults to the latest block hash. | -| nonce | `bigint` | no | - | The access key's nonce. Defaults to the current access key nonce incremented by 1. | -| publicKey | [`PublicKey`](https://near.github.io/near-api-js/classes/near_api_js.utils.PublicKey.html) \| `string` | yes | - | The signer's public key for the access key that will be used to write to the contract. | -| signer | [`Account`](https://near.github.io/near-api-js/classes/near_api_js.account.Account.html) | yes | - | An account that will read the data. For details on getting the account object see the NEAR API [docs](https://docs.near.org/tools/near-api-js/account). | +| Name | Type | Required | Default | Description | +|-----------|--------------------------------------------------------------------------------------------------------|----------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------| +| amount | `string` | no | - | The amount of NEAR to withdraw, in yoctoNEAR. If not specified, withdraws all available NEAR. | +| blockHash | `string` | no | - | A current block hash (within 24 hours). Defaults to the latest block hash. | +| nonce | `bigint` | no | - | The access key's nonce. Defaults to the current access key nonce incremented by 1. | +| publicKey | [`PublicKey`](https://near.github.io/near-api-js/classes/near_api_js.utils.PublicKey.html) \| `string` | yes | - | The signer's public key for the access key that will be used to write to the contract. | +| signer | [`Account`](https://near.github.io/near-api-js/classes/near_api_js.account.Account.html) | yes | - | An account that will read the data. For details on getting the account object see the NEAR API [docs](https://docs.near.org/tools/near-api-js/account). | diff --git a/src/controllers/Social.storageBalanceOf.test.ts b/src/controllers/Social.storageBalanceOf.test.ts new file mode 100644 index 0000000..f2b94b5 --- /dev/null +++ b/src/controllers/Social.storageBalanceOf.test.ts @@ -0,0 +1,89 @@ +import type { ExecutionError } from '@near-js/types'; +import { type Account, providers, transactions, utils } from 'near-api-js'; + +// credentials +import { account_id as socialContractAccountId } from '@test/credentials/localnet/social.test.near.json'; + +// controllers +import Social from './Social'; + +// helpers +import accountAccessKey, { + type IAccessKeyResponse, +} from '@test/helpers/accountAccessKey'; +import createEphemeralAccount from '@test/helpers/createEphemeralAccount'; + +// types +import type { IStorageBalanceOfResult } from '@app/types'; + +// utils +import convertNEARToYoctoNEAR from '@app/utils/convertNEARToYoctoNEAR'; + +describe(`${Social.name}#getVersion`, () => { + let keyPair: utils.KeyPairEd25519; + let signer: Account; + let signerAccessKeyResponse: IAccessKeyResponse; + + beforeEach(async () => { + const result = await createEphemeralAccount(convertNEARToYoctoNEAR('100')); + + keyPair = result.keyPair; + signer = result.account; + }); + + it('should return null if the contract does not have a storage balance', async () => { + // arrange + const client = new Social({ + contractId: socialContractAccountId, + }); + // act + const result = await client.storageBalanceOf({ + accountId: signer.accountId, + signer, + }); + + // assert + expect(result).toBeNull(); + }); + + it('should return the storage balance', async () => { + // arrange + const client = new Social({ + contractId: socialContractAccountId, + }); + const deposit = convertNEARToYoctoNEAR('1'); + let failure: ExecutionError | null; + let result: IStorageBalanceOfResult | null; + let transaction: transactions.Transaction; + + signerAccessKeyResponse = await accountAccessKey(signer, keyPair.publicKey); + transaction = await client.storageDeposit({ + publicKey: keyPair.publicKey, + signer, + accountId: signer.accountId, + deposit, + }); + const [_, signedTransaction] = await transactions.signTransaction( + transaction, + signer.connection.signer, + signer.accountId, + signer.connection.networkId + ); + const { status } = + await signer.connection.provider.sendTransaction(signedTransaction); + failure = (status as providers.FinalExecutionStatus)?.Failure || null; + + if (failure) { + throw new Error(`${failure.error_type}: ${failure.error_message}`); + } + + // act + result = await client.storageBalanceOf({ + accountId: signer.accountId, + signer, + }); + + // assert + expect(result?.total).toEqual(deposit); + }); +}); diff --git a/src/controllers/Social.ts b/src/controllers/Social.ts index 623654c..5be3535 100644 --- a/src/controllers/Social.ts +++ b/src/controllers/Social.ts @@ -35,16 +35,17 @@ import type { IIsWritePermissionGrantedWithPublicKeyOptions, INewSocialOptions, ISetOptions, - IStorageDepositOptions, - IStorageWithdrawOptions, ISocialDBContractGetArgs, ISocialDBContractGrantWritePermissionArgs, ISocialDBContractSetArgs, ISocialDBContractStorageBalance, - IStorageBalanceOfOptions, ISocialDBContractStorageDepositArgs, ISocialDBContractIsWritePermissionGrantedArgs, ISocialDBContractStorageWithdrawArgs, + IStorageBalanceOfOptions, + IStorageBalanceOfResult, + IStorageDepositOptions, + IStorageWithdrawOptions, } from '@app/types'; // utils @@ -93,19 +94,6 @@ export default class Social { return sync_info.latest_block_hash; } - private async _storageBalanceOf({ - accountId, - signer, - }: IStorageBalanceOfOptions): Promise { - return await signer.viewFunction({ - args: { - account_id: accountId, - }, - contractId: this.contractId, - methodName: ViewMethodEnum.StorageBalanceOf, - }); - } - private _uniqueAccountIdsFromKeys(keys: string[]): string[] { return keys.reduce((acc, currentValue) => { const accountId = currentValue.split('/')[0] || ''; @@ -368,7 +356,7 @@ export default class Social { // for each account, check if there is storage, if there isn't, add an action to deposit the minimum storage for (let i = 0; i < uniqueAccountIds.length; i++) { if ( - !(await this._storageBalanceOf({ + !(await this.storageBalanceOf({ accountId: uniqueAccountIds[i], signer, })) @@ -419,6 +407,44 @@ export default class Social { ); } + /** + * Sets the new social contract ID. + * @param {string} contractId - the account of the new social contract ID. + */ + public setContractId(contractId: string): void { + this.contractId = contractId; + } + + /** + * Gets the storage balance for a given account ID. + * @param {IStorageBalanceOfOptions} options - the account ID to check and the signer that is used to call the view + * method. + * @returns {Promise} a promise that resolves the total & available balance or null + * if the account ID does not have a balance. + */ + public async storageBalanceOf({ + accountId, + signer, + }: IStorageBalanceOfOptions): Promise { + const result: ISocialDBContractStorageBalance | null = + await signer.viewFunction({ + args: { + account_id: accountId, + }, + contractId: this.contractId, + methodName: ViewMethodEnum.StorageBalanceOf, + }); + + if (!result) { + return null; + } + + return { + available: String(result.available), + total: String(result.total), + }; + } + /** * Deposit NEAR to the social DB contract for covering storage for the given account_id or the signer if acount_id is not provided. * It also let you choose the option to pay bare minimum deposit for registering the account in the Social DB contract without any additional storage fees. @@ -538,11 +564,4 @@ export default class Social { utils.serialize.base_decode(_blockHash) ); } - /** - * Sets the new social contract ID. - * @param {string} contractId - the account of the new social contract ID. - */ - public setContractId(contractId: string): void { - this.contractId = contractId; - } } diff --git a/src/types/IStorageBalanceOfResult.ts b/src/types/IStorageBalanceOfResult.ts new file mode 100644 index 0000000..04ce353 --- /dev/null +++ b/src/types/IStorageBalanceOfResult.ts @@ -0,0 +1,6 @@ +interface IStorageBalanceOfResult { + available: string; + total: string; +} + +export default IStorageBalanceOfResult; diff --git a/src/types/index.ts b/src/types/index.ts index 20f7e67..8700956 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -9,8 +9,6 @@ export type { default as IIsWritePermissionGrantedWithPublicKeyOptions } from '. export type { default as IGetVersionOptions } from './IGetVersionOptions'; export type { default as INewSocialOptions } from './INewSocialOptions'; export type { default as ISetOptions } from './ISetOptions'; -export type { default as IStorageDepositOptions } from './IStorageDepositOptions'; -export type { default as IStorageWithdrawOptions } from './IStorageWithdrawOptions'; export type { default as ISocialDBContractAccount } from './ISocialDBContractAccount'; export type { default as ISocialDBContractAccountSharedStorage } from './ISocialDBContractAccountSharedStorage'; export type { default as ISocialDBContractGetArgs } from './ISocialDBContractGetArgs'; @@ -25,3 +23,6 @@ export type { default as ISocialDBContractStorageDepositArgs } from './ISocialDB export type { default as ISocialDBContractStorageWithdrawArgs } from './ISocialDBContractStorageWithdrawArgs'; export type { default as ISocialDBContractStorageTracker } from './ISocialDBContractStorageTracker'; export type { default as IStorageBalanceOfOptions } from './IStorageBalanceOfOptions'; +export type { default as IStorageBalanceOfResult } from './IStorageBalanceOfResult'; +export type { default as IStorageDepositOptions } from './IStorageDepositOptions'; +export type { default as IStorageWithdrawOptions } from './IStorageWithdrawOptions'; From 16be4b8e54a39ccd777948a39ba8fcdfae32cd86 Mon Sep 17 00:00:00 2001 From: Kieran O'Neill Date: Mon, 24 Jun 2024 10:40:35 +0100 Subject: [PATCH 2/6] refactor: update storage deposit tests with new storagbalanceof function --- src/controllers/Social.storageDeposit.test.ts | 53 ++++++++----------- 1 file changed, 23 insertions(+), 30 deletions(-) diff --git a/src/controllers/Social.storageDeposit.test.ts b/src/controllers/Social.storageDeposit.test.ts index 2eae83a..157676e 100644 --- a/src/controllers/Social.storageDeposit.test.ts +++ b/src/controllers/Social.storageDeposit.test.ts @@ -1,6 +1,4 @@ -import { Account, providers, transactions, utils } from 'near-api-js'; -//import { randomBytes } from 'node:crypto'; -import { ViewMethodEnum } from '@app/enums'; +import { type Account, providers, transactions, utils } from 'near-api-js'; // credentials import { account_id as socialContractAccountId } from '@test/credentials/localnet/social.test.near.json'; @@ -10,11 +8,16 @@ import Social from './Social'; // helpers import accountAccessKey, { - IAccessKeyResponse, + type IAccessKeyResponse, } from '@test/helpers/accountAccessKey'; -import convertNEARToYoctoNEAR from '@app/utils/convertNEARToYoctoNEAR'; import createEphemeralAccount from '@test/helpers/createEphemeralAccount'; +// types +import type { IStorageBalanceOfResult } from '@app/types'; + +// utils +import convertNEARToYoctoNEAR from '@app/utils/convertNEARToYoctoNEAR'; + describe(`${Social.name}#storageDeposit`, () => { let keyPair: utils.KeyPairEd25519; let signer: Account; @@ -32,7 +35,7 @@ describe(`${Social.name}#storageDeposit`, () => { const client = new Social({ contractId: socialContractAccountId, }); - let result: Record; + let result: IStorageBalanceOfResult | null; let transaction: transactions.Transaction; signerAccessKeyResponse = await accountAccessKey(signer, keyPair.publicKey); @@ -65,14 +68,11 @@ describe(`${Social.name}#storageDeposit`, () => { throw new Error(`${failure.error_type}: ${failure.error_message}`); } - result = await signer.viewFunction({ - args: { - account_id: signer.accountId, - }, - contractId: socialContractAccountId, - methodName: ViewMethodEnum.StorageBalanceOf, + result = await client.storageBalanceOf({ + accountId: signer.accountId, + signer, }); - expect(result.total).toEqual(deposit); + expect(result?.total).toEqual(deposit); }); it('should deposit storage for the signer account without account_id', async () => { @@ -80,7 +80,7 @@ describe(`${Social.name}#storageDeposit`, () => { const client = new Social({ contractId: socialContractAccountId, }); - let result: Record; + let result: IStorageBalanceOfResult | null; let transaction: transactions.Transaction; signerAccessKeyResponse = await accountAccessKey(signer, keyPair.publicKey); @@ -113,14 +113,11 @@ describe(`${Social.name}#storageDeposit`, () => { throw new Error(`${failure.error_type}: ${failure.error_message}`); } - result = await signer.viewFunction({ - args: { - account_id: signer.accountId, - }, - contractId: socialContractAccountId, - methodName: ViewMethodEnum.StorageBalanceOf, + result = await client.storageBalanceOf({ + accountId: signer.accountId, + signer, }); - expect(result.total).toEqual(deposit); + expect(result?.total).toEqual(deposit); }); it('should deposit storage for some third person account', async () => { @@ -128,7 +125,7 @@ describe(`${Social.name}#storageDeposit`, () => { const client = new Social({ contractId: socialContractAccountId, }); - let result: Record; + let result: IStorageBalanceOfResult | null; let transaction: transactions.Transaction; signerAccessKeyResponse = await accountAccessKey(signer, keyPair.publicKey); @@ -163,14 +160,10 @@ describe(`${Social.name}#storageDeposit`, () => { throw new Error(`${failure.error_type}: ${failure.error_message}`); } - result = await signer.viewFunction({ - args: { - account_id: accountId, - }, - contractId: socialContractAccountId, - methodName: ViewMethodEnum.StorageBalanceOf, + result = await client.storageBalanceOf({ + accountId: signer.accountId, + signer, }); - console.log(result); - expect(result.total).toEqual(deposit); + expect(result?.total).toEqual(deposit); }); }); From d9ac6b04fa916b756722084d44dd108cc63727d2 Mon Sep 17 00:00:00 2001 From: Kieran O'Neill Date: Mon, 24 Jun 2024 10:53:10 +0100 Subject: [PATCH 3/6] docs: add checking storage balance of example to the storage deposit docs --- docs/advanced/storage-deposit-withdraw.mdx | 362 +++++++++++++-------- 1 file changed, 221 insertions(+), 141 deletions(-) diff --git a/docs/advanced/storage-deposit-withdraw.mdx b/docs/advanced/storage-deposit-withdraw.mdx index 791f880..5e1d64d 100644 --- a/docs/advanced/storage-deposit-withdraw.mdx +++ b/docs/advanced/storage-deposit-withdraw.mdx @@ -10,173 +10,253 @@ toc={toc} /> ## Overview -When depositing NEAR to the social DB contract, you can cover the storage cost for a specific account_id or the signer if account_id is not provided. You can also choose to pay the bare minimum deposit required for registering the account in the Social DB contract without any additional storage fees. +When depositing NEAR to the social DB contract, you can cover the storage cost for a specific account_id or the signer if account_id is not provided. You can also choose to pay the bare minimum deposit required for registering the account in the Social DB contract without any additional storage fees. The signer account MUST have sufficient NEAR balance to cover the deposit. +## Checking Storage Balance + + defaultValue="javascript-via-package-manager" + values={[ + { label: 'JavaScript (via package manager)', value: 'javascript-via-package-manager' }, + { label: 'JavaScript (via CDN)', value: 'javascript-via-cdn' }, + { label: 'TypeScript', value: 'typescript' }, + ]} +> + + + ```js + const { Social } = require('@builddao/near-social-js'); + + const social = new Social(); + const result = await social.storageBalanceOf({ + accountId: 'alice.near', + signer, // an initialized near-api-js account + }); + console.log(result); + /* + { + "available": "1000000000000000000000000", + "total": "1000000000000000000000000" + } + */ + ``` + + + + + + ```js + var social = new NEARSocialSDK(); + + social.storageBalanceOf({ + accountId: 'alice.near', + signer, // an initialized near-api-js account + }).then((result) => { + console.log(result); + /* + { + "available": "1000000000000000000000000", + "total": "1000000000000000000000000" + } + */ + }); + ``` + + + + + ```typescript + import { Social } from '@builddao/near-social-js'; + + const social = new Social(); + const result = await social.storageBalanceOf({ + accountId: 'alice.near', + signer, // an initialized near-api-js account + }); + console.log(result); + /* + { + "available": "1000000000000000000000000", + "total": "1000000000000000000000000" + } + */ + ``` + + + + +## Depositing NEAR To Storage + + + ```js -const { Social } = require('@builddao/near-social-js'); - -const signer = await nearConnection.account('alice.near'); -const accessKeys = await signer.getAccessKeys(); -const social = new Social(); -const transaction = await social.storageDeposit({ - blockHash: accessKeys[0].block_hash, - nonce: BigInt(accessKeys[0].nonce + 1), // the nonce to be used for the transaction, must be greater than the access key nonce - publicKey: accessKeys[0].public_key, - signer, - registration_only: true, // set to true if you want to pay only the bare minimum deposit - account_id: 'bob.near', // optional, defaults to the signer account - deposit: '10000000000000000000000', // the amount to deposit in yoctoNEAR -}); -// ...sign the returned transaction and post to the network -``` + const { Social } = require('@builddao/near-social-js'); + + const signer = await nearConnection.account('alice.near'); + const accessKeys = await signer.getAccessKeys(); + const social = new Social(); + const transaction = await social.storageDeposit({ + blockHash: accessKeys[0].block_hash, + nonce: BigInt(accessKeys[0].nonce + 1), // the nonce to be used for the transaction, must be greater than the access key nonce + publicKey: accessKeys[0].public_key, + signer, + registration_only: true, // set to true if you want to pay only the bare minimum deposit + account_id: 'bob.near', // optional, defaults to the signer account + deposit: '10000000000000000000000', // the amount to deposit in yoctoNEAR + }); + // ...sign the returned transaction and post to the network + ``` + -```js -var accessKeys; -var signer; -var social; - -nearConnection.account('alice.near') - .then((_signer) => { - signer = _signer; - - return signer.getAccessKeys(); - }) - .then((_accessKeys) => { - accessKeys = _accessKeys; - social = new NEARSocialSDK(); - - return social.storageDeposit({ - blockHash: accessKeys[0].block_hash, - nonce: BigInt(accessKeys[0].nonce + 1), // the nonce to be used for the transaction, must be greater than the access key nonce - publicKey: accessKeys[0].public_key, - signer, - registration_only: true, // set to true if you want to pay only the bare minimum deposit - account_id: 'bob.near', // optional, defaults to the signer account - deposit: '10000000000000000000000', // the amount to deposit in yoctoNEAR + + ```js + var accessKeys; + var signer; + var social; + + nearConnection.account('alice.near') + .then((_signer) => { + signer = _signer; + + return signer.getAccessKeys(); + }) + .then((_accessKeys) => { + accessKeys = _accessKeys; + social = new NEARSocialSDK(); + + return social.storageDeposit({ + blockHash: accessKeys[0].block_hash, + nonce: BigInt(accessKeys[0].nonce + 1), // the nonce to be used for the transaction, must be greater than the access key nonce + publicKey: accessKeys[0].public_key, + signer, + registration_only: true, // set to true if you want to pay only the bare minimum deposit + account_id: 'bob.near', // optional, defaults to the signer account + deposit: '10000000000000000000000', // the amount to deposit in yoctoNEAR + }); + }) + .then((transaction) => { + // ...sign the returned transaction and post to the network }); - }) - .then((transaction) => { - // ...sign the returned transaction and post to the network - }); -``` + ``` + -```typescript -import { Social } from '@builddao/near-social-js'; - -const signer = await nearConnection.account('alice.near'); -const accessKeys = await signer.getAccessKeys(); -const social = new Social(); -const transaction = await social.storageDeposit({ - blockHash: accessKeys[0].block_hash, - nonce: BigInt(accessKeys[0].nonce + 1), // the nonce to be used for the transaction, must be greater than the access key nonce - publicKey: accessKeys[0].public_key, - signer, - registration_only: true, // set to true if you want to pay only the bare minimum deposit - account_id: 'bob.near', // optional, defaults to the signer account - deposit: '10000000000000000000000', // the amount to deposit in yoctoNEAR -}); -// ...sign the returned transaction and post to the network -``` + + ```typescript + import { Social } from '@builddao/near-social-js'; + + const signer = await nearConnection.account('alice.near'); + const accessKeys = await signer.getAccessKeys(); + const social = new Social(); + const transaction = await social.storageDeposit({ + blockHash: accessKeys[0].block_hash, + nonce: BigInt(accessKeys[0].nonce + 1), // the nonce to be used for the transaction, must be greater than the access key nonce + publicKey: accessKeys[0].public_key, + signer, + registration_only: true, // set to true if you want to pay only the bare minimum deposit + account_id: 'bob.near', // optional, defaults to the signer account + deposit: '10000000000000000000000', // the amount to deposit in yoctoNEAR + }); + // ...sign the returned transaction and post to the network + ``` + -# Withdrawing NEAR from Storage +## Withdrawing NEAR From Storage - + + -## Overview -When withdrawing NEAR from the social DB contract, you can specify the amount to withdraw. If no amount is specified, all available NEAR is withdrawn. + ```js + const { Social } = require('@builddao/near-social-js'); -The signer account MUST have sufficient NEAR balance available for withdrawal. + const signer = await nearConnection.account('alice.near'); + const accessKeys = await signer.getAccessKeys(); + const social = new Social(); + const transaction = await social.storageWithdraw({ + blockHash: accessKeys[0].block_hash, + nonce: BigInt(accessKeys[0].nonce + 1), // the nonce to be used for the transaction, must be greater than the access key nonce + publicKey: accessKeys[0].public_key, + signer, + amount: '5000000000000000000000', // the amount to withdraw in yoctoNEAR, optional, defaults to all available balance + }); + // ...sign the returned transaction and post to the network + ``` - - - -```js -const { Social } = require('@builddao/near-social-js'); - -const signer = await nearConnection.account('alice.near'); -const accessKeys = await signer.getAccessKeys(); -const social = new Social(); -const transaction = await social.storageWithdraw({ - blockHash: accessKeys[0].block_hash, - nonce: BigInt(accessKeys[0].nonce + 1), // the nonce to be used for the transaction, must be greater than the access key nonce - publicKey: accessKeys[0].public_key, - signer, - amount: '5000000000000000000000', // the amount to withdraw in yoctoNEAR, optional, defaults to all available balance -}); -// ...sign the returned transaction and post to the network -``` + -```js -var accessKeys; -var signer; -var social; - -nearConnection.account('alice.near') - .then((_signer) => { - signer = _signer; - - return signer.getAccessKeys(); - }) - .then((_accessKeys) => { - accessKeys = _accessKeys; - social = new NEARSocialSDK(); - - return social.storageWithdraw({ - blockHash: accessKeys[0].block_hash, - nonce: BigInt(accessKeys[0].nonce + 1), // the nonce to be used for the transaction, must be greater than the access key nonce - publicKey: accessKeys[0].public_key, - signer, - amount: '5000000000000000000000', // the amount to withdraw in yoctoNEAR, optional, defaults to all available balance + + ```js + var accessKeys; + var signer; + var social; + + nearConnection.account('alice.near') + .then((_signer) => { + signer = _signer; + + return signer.getAccessKeys(); + }) + .then((_accessKeys) => { + accessKeys = _accessKeys; + social = new NEARSocialSDK(); + + return social.storageWithdraw({ + blockHash: accessKeys[0].block_hash, + nonce: BigInt(accessKeys[0].nonce + 1), // the nonce to be used for the transaction, must be greater than the access key nonce + publicKey: accessKeys[0].public_key, + signer, + amount: '5000000000000000000000', // the amount to withdraw in yoctoNEAR, optional, defaults to all available balance + }); + }) + .then((transaction) => { + // ...sign the returned transaction and post to the network }); - }) - .then((transaction) => { - // ...sign the returned transaction and post to the network - }); -``` + ``` + + -```typescript -import { Social } from '@builddao/near-social-js'; - -const signer = await nearConnection.account('alice.near'); -const accessKeys = await signer.getAccessKeys(); -const social = new Social(); -const transaction = await social.storageWithdraw({ - blockHash: accessKeys[0].block_hash, - nonce: BigInt(accessKeys[0].nonce + 1), // the nonce to be used for the transaction, must be greater than the access key nonce - publicKey: accessKeys[0].public_key, - signer, - amount: '5000000000000000000000', // the amount to withdraw in yoctoNEAR, optional, defaults to all available balance -}); -// ...sign the returned transaction and post to the network -``` + + ```typescript + import { Social } from '@builddao/near-social-js'; + + const signer = await nearConnection.account('alice.near'); + const accessKeys = await signer.getAccessKeys(); + const social = new Social(); + const transaction = await social.storageWithdraw({ + blockHash: accessKeys[0].block_hash, + nonce: BigInt(accessKeys[0].nonce + 1), // the nonce to be used for the transaction, must be greater than the access key nonce + publicKey: accessKeys[0].public_key, + signer, + amount: '5000000000000000000000', // the amount to withdraw in yoctoNEAR, optional, defaults to all available balance + }); + // ...sign the returned transaction and post to the network + ``` + From 12a30f00b14ca1b7ea5ac83ecef2b519aef06b40 Mon Sep 17 00:00:00 2001 From: Kieran O'Neill Date: Mon, 24 Jun 2024 10:59:43 +0100 Subject: [PATCH 4/6] refactor: add storagebalanceof function to storagewithdraw tests --- .../Social.storageWithdraw.test.ts | 72 +++++++++---------- 1 file changed, 33 insertions(+), 39 deletions(-) diff --git a/src/controllers/Social.storageWithdraw.test.ts b/src/controllers/Social.storageWithdraw.test.ts index 0f1f514..95bbd21 100644 --- a/src/controllers/Social.storageWithdraw.test.ts +++ b/src/controllers/Social.storageWithdraw.test.ts @@ -1,6 +1,5 @@ -import { Account, providers, transactions, utils } from 'near-api-js'; -//import { randomBytes } from 'node:crypto'; -import { ViewMethodEnum } from '@app/enums'; +import BigNumber from 'bignumber.js'; +import { type Account, providers, transactions, utils } from 'near-api-js'; // credentials import { account_id as socialContractAccountId } from '@test/credentials/localnet/social.test.near.json'; @@ -10,11 +9,16 @@ import Social from './Social'; // helpers import accountAccessKey, { - IAccessKeyResponse, + type IAccessKeyResponse, } from '@test/helpers/accountAccessKey'; -import convertNEARToYoctoNEAR from '@app/utils/convertNEARToYoctoNEAR'; import createEphemeralAccount from '@test/helpers/createEphemeralAccount'; +// types +import type { IStorageBalanceOfResult } from '@app/types'; + +// utils +import convertNEARToYoctoNEAR from '@app/utils/convertNEARToYoctoNEAR'; + describe(`${Social.name}#storageWithdraw`, () => { let keyPair: utils.KeyPairEd25519; let signer: Account; @@ -32,8 +36,8 @@ describe(`${Social.name}#storageWithdraw`, () => { const client = new Social({ contractId: socialContractAccountId, }); - let resultBefore: Record; - let resultAfter: Record; + let resultBefore: IStorageBalanceOfResult | null; + let resultAfter: IStorageBalanceOfResult | null; let transaction: transactions.Transaction; signerAccessKeyResponse = await accountAccessKey(signer, keyPair.publicKey); @@ -71,16 +75,13 @@ describe(`${Social.name}#storageWithdraw`, () => { throw new Error(`${failure.error_type}: ${failure.error_message}`); } - resultBefore = await signer.viewFunction({ - args: { - account_id: signer.accountId, - }, - contractId: socialContractAccountId, - methodName: ViewMethodEnum.StorageBalanceOf, + resultBefore = await client.storageBalanceOf({ + accountId: signer.accountId, + signer, }); // Test if the deposit was successful - expect(resultBefore.total).toEqual(deposit); + expect(resultBefore?.total).toEqual(deposit); //1N withdraw let withdraw_amount = '1000000000000000000000000'; @@ -111,19 +112,18 @@ describe(`${Social.name}#storageWithdraw`, () => { throw new Error(`${failure.error_type}: ${failure.error_message}`); } - resultAfter = await signer.viewFunction({ - args: { - account_id: signer.accountId, - }, - contractId: socialContractAccountId, - methodName: ViewMethodEnum.StorageBalanceOf, + resultAfter = await client.storageBalanceOf({ + accountId: signer.accountId, + signer, }); // expect(BigInt(resultAfter?.total)).toEqual( // BigInt(resultBefore?.total) - BigInt(withdraw_amount) // ); - expect(BigInt(resultAfter?.total as string)).toEqual( - BigInt(resultBefore?.total as string) - BigInt(withdraw_amount) + expect(resultAfter?.total).toBe( + new BigNumber(resultBefore?.total || '0') + .minus(new BigNumber(withdraw_amount)) + .toFixed() ); }); @@ -132,8 +132,8 @@ describe(`${Social.name}#storageWithdraw`, () => { const client = new Social({ contractId: socialContractAccountId, }); - let resultBefore: Record; - let resultAfter: Record; + let resultBefore: IStorageBalanceOfResult | null; + let resultAfter: IStorageBalanceOfResult | null; let transaction: transactions.Transaction; signerAccessKeyResponse = await accountAccessKey(signer, keyPair.publicKey); @@ -143,7 +143,7 @@ describe(`${Social.name}#storageWithdraw`, () => { //Make deposit to the account //2N deposit - let deposit = '2000000000000000000000000'; + let deposit = convertNEARToYoctoNEAR('2'); transaction = await client.storageDeposit({ blockHash: signerAccessKeyResponse.block_hash, nonce: BigInt(signerAccessKeyResponse.nonce + 1), @@ -171,16 +171,13 @@ describe(`${Social.name}#storageWithdraw`, () => { throw new Error(`${failure.error_type}: ${failure.error_message}`); } - resultBefore = await signer.viewFunction({ - args: { - account_id: signer.accountId, - }, - contractId: socialContractAccountId, - methodName: ViewMethodEnum.StorageBalanceOf, + resultBefore = await client.storageBalanceOf({ + accountId: signer.accountId, + signer, }); // Test if the deposit was successful - expect(resultBefore.total).toEqual(deposit); + expect(resultBefore?.total).toEqual(deposit); //No withdrawal amount specified transaction = await client.storageWithdraw({ @@ -209,14 +206,11 @@ describe(`${Social.name}#storageWithdraw`, () => { throw new Error(`${failure.error_type}: ${failure.error_message}`); } - resultAfter = await signer.viewFunction({ - args: { - account_id: signer.accountId, - }, - contractId: socialContractAccountId, - methodName: ViewMethodEnum.StorageBalanceOf, + resultAfter = await client.storageBalanceOf({ + accountId: signer.accountId, + signer, }); - expect(resultAfter.available).toEqual('0'); + expect(resultAfter?.available).toBe('0'); }); }); From a96fb2f8b895954f6a2faf328c1c1ced2095317e Mon Sep 17 00:00:00 2001 From: Kieran O'Neill Date: Mon, 24 Jun 2024 11:05:18 +0100 Subject: [PATCH 5/6] chore: squash --- src/controllers/Social.storageBalanceOf.test.ts | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/controllers/Social.storageBalanceOf.test.ts b/src/controllers/Social.storageBalanceOf.test.ts index f2b94b5..d113a6a 100644 --- a/src/controllers/Social.storageBalanceOf.test.ts +++ b/src/controllers/Social.storageBalanceOf.test.ts @@ -8,9 +8,6 @@ import { account_id as socialContractAccountId } from '@test/credentials/localne import Social from './Social'; // helpers -import accountAccessKey, { - type IAccessKeyResponse, -} from '@test/helpers/accountAccessKey'; import createEphemeralAccount from '@test/helpers/createEphemeralAccount'; // types @@ -22,7 +19,6 @@ import convertNEARToYoctoNEAR from '@app/utils/convertNEARToYoctoNEAR'; describe(`${Social.name}#getVersion`, () => { let keyPair: utils.KeyPairEd25519; let signer: Account; - let signerAccessKeyResponse: IAccessKeyResponse; beforeEach(async () => { const result = await createEphemeralAccount(convertNEARToYoctoNEAR('100')); @@ -52,17 +48,14 @@ describe(`${Social.name}#getVersion`, () => { contractId: socialContractAccountId, }); const deposit = convertNEARToYoctoNEAR('1'); - let failure: ExecutionError | null; - let result: IStorageBalanceOfResult | null; - let transaction: transactions.Transaction; - - signerAccessKeyResponse = await accountAccessKey(signer, keyPair.publicKey); - transaction = await client.storageDeposit({ + const transaction = await client.storageDeposit({ publicKey: keyPair.publicKey, signer, accountId: signer.accountId, deposit, }); + let failure: ExecutionError | null; + let result: IStorageBalanceOfResult | null; const [_, signedTransaction] = await transactions.signTransaction( transaction, signer.connection.signer, From 5045fac7ad9713126e9be95df12917914d0bf7b8 Mon Sep 17 00:00:00 2001 From: Kieran O'Neill Date: Mon, 24 Jun 2024 11:17:17 +0100 Subject: [PATCH 6/6] test: fix tests --- src/controllers/Social.storageDeposit.test.ts | 8 ++++---- src/controllers/Social.storageWithdraw.test.ts | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/controllers/Social.storageDeposit.test.ts b/src/controllers/Social.storageDeposit.test.ts index 157676e..4e52251 100644 --- a/src/controllers/Social.storageDeposit.test.ts +++ b/src/controllers/Social.storageDeposit.test.ts @@ -41,7 +41,7 @@ describe(`${Social.name}#storageDeposit`, () => { signerAccessKeyResponse = await accountAccessKey(signer, keyPair.publicKey); let accountId = signer.accountId; - let deposit = '2000000000000000000000000'; + let deposit = convertNEARToYoctoNEAR('2'); //testing optional blockhash and nonce too transaction = await client.storageDeposit({ publicKey: keyPair.publicKey, @@ -86,7 +86,7 @@ describe(`${Social.name}#storageDeposit`, () => { signerAccessKeyResponse = await accountAccessKey(signer, keyPair.publicKey); // In the absence of account_id, the deposit is made to the signer - let deposit = '2000000000000000000000000'; + let deposit = convertNEARToYoctoNEAR('2'); transaction = await client.storageDeposit({ blockHash: signerAccessKeyResponse.block_hash, nonce: BigInt(signerAccessKeyResponse.nonce + 1), @@ -132,7 +132,7 @@ describe(`${Social.name}#storageDeposit`, () => { // act let accountId = String(Math.random()) + '.near'; - let deposit = '2000000000000000000000000'; + let deposit = convertNEARToYoctoNEAR('2'); transaction = await client.storageDeposit({ blockHash: signerAccessKeyResponse.block_hash, nonce: BigInt(signerAccessKeyResponse.nonce + 1), @@ -161,7 +161,7 @@ describe(`${Social.name}#storageDeposit`, () => { } result = await client.storageBalanceOf({ - accountId: signer.accountId, + accountId, signer, }); expect(result?.total).toEqual(deposit); diff --git a/src/controllers/Social.storageWithdraw.test.ts b/src/controllers/Social.storageWithdraw.test.ts index 95bbd21..ff05d2c 100644 --- a/src/controllers/Social.storageWithdraw.test.ts +++ b/src/controllers/Social.storageWithdraw.test.ts @@ -47,7 +47,7 @@ describe(`${Social.name}#storageWithdraw`, () => { //Make deposit to the account //2N deposit - let deposit = '2000000000000000000000000'; + let deposit = convertNEARToYoctoNEAR('2'); transaction = await client.storageDeposit({ blockHash: signerAccessKeyResponse.block_hash, nonce: BigInt(signerAccessKeyResponse.nonce + 1), @@ -84,7 +84,7 @@ describe(`${Social.name}#storageWithdraw`, () => { expect(resultBefore?.total).toEqual(deposit); //1N withdraw - let withdraw_amount = '1000000000000000000000000'; + let withdraw_amount = convertNEARToYoctoNEAR('1'); transaction = await client.storageWithdraw({ blockHash: signerAccessKeyResponse.block_hash, nonce: BigInt(signerAccessKeyResponse.nonce + 1 + 1),