diff --git a/README.md b/README.md index 1e5c53b..f16df49 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,7 @@ GitHub Pre-release - GitHub Pre-release Date - Published At + GitHub Pre-release Date - Published At

diff --git a/docs/advanced/granting-write-permission.mdx b/docs/advanced/granting-write-permission.mdx index a8b1a4f..fe0dbd7 100644 --- a/docs/advanced/granting-write-permission.mdx +++ b/docs/advanced/granting-write-permission.mdx @@ -32,20 +32,17 @@ Accounts can grant write permission to other accounts for a set of keys. ```js const { Social } = require('@builddao/near-social-js'); - const grantee = await nearConnection.account('alice.near'); - const granter = await nearConnection.account('bob.near'); - const accessKeys = await granter.getAccessKeys(); const social = new Social(); const transaction = await social.grantWritePermission({ - blockHash: accessKeys[0].block_hash, - granteeAccountId: grantee.accountId, + account: { + accountID: 'bob.near', + publicKey: 'ed25519:H9k5eiU4xXS3M4z8HzKJSLaZdqGdGwBG49o7orNC4eZW', + }, + granteeAccountId: 'alice.near', keys: [ 'alice.near/profile/name', 'alice.near/profile/image/url', ], - 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: granter, }); // ...sign the returned transaction and post to the network @@ -56,41 +53,22 @@ Accounts can grant write permission to other accounts for a set of keys. ```js - var accessKeys; - var grantee; - var granter; - var social; - - nearConnection.account('alice.near') - .then((_granter) => { - granter = _granter; - - return nearConnection.account('bob.near'); - }) - .then((_grantee) => { - grantee = _grantee; - - return granter.getAccessKeys(); - }) - .then((_accessKeys) => { - accessKeys = _accessKeys; - social = new NEARSocialSDK(); - - return social.grantWritePermission({ - blockHash: accessKeys[0].block_hash, - granteeAccountId: grantee.accountId, - keys: [ - 'alice.near/profile/name', - 'alice.near/profile/image/url', - ], - 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: granter, - }); - }) - .then((transaction) => { - // ...sign the returned transaction and post to the network - }); + var social = new NEARSocialSDK(); + + social.grantWritePermission({ + account: { + accountID: 'bob.near', + publicKey: 'ed25519:H9k5eiU4xXS3M4z8HzKJSLaZdqGdGwBG49o7orNC4eZW', + }, + granteeAccountId: 'alice.near', + keys: [ + 'alice.near/profile/name', + 'alice.near/profile/image/url' + ] + }) + .then((transaction) => { + // ...sign the returned transaction and post to the network + }); ``` @@ -99,20 +77,17 @@ Accounts can grant write permission to other accounts for a set of keys. ```typescript import { Social } from '@builddao/near-social-js'; - const grantee = await nearConnection.account('alice.near'); - const granter = await nearConnection.account('bob.near'); - const accessKeys = await granter.getAccessKeys(); const social = new Social(); const transaction = await social.grantWritePermission({ - blockHash: accessKeys[0].block_hash, - granteeAccountId: grantee.accountId, + account: { + accountID: 'bob.near', + publicKey: 'ed25519:H9k5eiU4xXS3M4z8HzKJSLaZdqGdGwBG49o7orNC4eZW', + }, + granteeAccountId: 'alice.near', keys: [ 'alice.near/profile/name', 'alice.near/profile/image/url', ], - 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: granter, }); // ...sign the returned transaction and post to the network @@ -124,12 +99,12 @@ Accounts can grant write permission to other accounts for a set of keys. :::caution -If the grantee account ID or the account ID in each key is not a valid account ID then a [`InvalidAccountIdError`](../../api-reference/errors#invalidaccountiderror) is thrown. +If the grantee account ID or the account ID in each key is not a valid account ID then a [`InvalidAccountIdError`](../api-reference/errors#invalidaccountiderror) is thrown. ::: :::caution -If a key does is not owned by the granter, then a [`KeyNotAllowedError`](../../api-reference/errors#keynotallowederror) is thrown. +If a key does is not owned by the granter, then a [`KeyNotAllowedError`](../api-reference/errors#keynotallowederror) is thrown. ::: diff --git a/docs/advanced/reading-data.mdx b/docs/advanced/reading-data.mdx index 2dd04c6..df8d74f 100644 --- a/docs/advanced/reading-data.mdx +++ b/docs/advanced/reading-data.mdx @@ -56,7 +56,6 @@ Getting specific values, like the example from above, you can use a set of keys: 'alice.near/profile/image/url', 'bob.near/profile/name', ], - rpcURL //rpc url for your network. }); console.log(result); @@ -95,7 +94,6 @@ Getting specific values, like the example from above, you can use a set of keys: 'alice.near/profile/image/url', 'bob.near/profile/name', ], - rpcURL //rpc url for your network. }).then((result) => { console.log(result); /* @@ -135,7 +133,6 @@ Getting specific values, like the example from above, you can use a set of keys: 'alice.near/profile/image/url', 'bob.near/profile/name', ], - rpcURL //rpc url for your network. }); console.log(result); @@ -186,7 +183,6 @@ The [`get`](../api-reference/social#getoptions) function also supports wildcard keys: [ 'alice.near/profile/**', ], - rpcURL //rpc url for your network. }); console.log(result); @@ -214,7 +210,6 @@ The [`get`](../api-reference/social#getoptions) function also supports wildcard keys: [ 'alice.near/profile/**', ], - rpcURL, //rpc url for your network. }).then((result) => { console.log(result); /* @@ -243,7 +238,6 @@ The [`get`](../api-reference/social#getoptions) function also supports wildcard keys: [ 'alice.near/profile/**' ], - rpcURL, //rpc url for your network. }); console.log(result); diff --git a/docs/advanced/storage-deposit-withdraw.mdx b/docs/advanced/storage-deposit-withdraw.mdx index 791f880..70e70f3 100644 --- a/docs/advanced/storage-deposit-withdraw.mdx +++ b/docs/advanced/storage-deposit-withdraw.mdx @@ -5,8 +5,8 @@ import TOCInline from '@theme/TOCInline'; # Depositing NEAR for Storage ## Overview @@ -16,167 +16,132 @@ When depositing NEAR to the social DB contract, you can cover the storage cost f The signer account MUST have sufficient NEAR balance to cover the deposit. - + 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 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, + ```js + const { Social } = require('@builddao/near-social-js'); + + const social = new Social(); + const transaction = await social.storageDeposit({ + account: { + accountID: 'alice.near', + publicKey: 'ed25519:H9k5eiU4xXS3M4z8HzKJSLaZdqGdGwBG49o7orNC4eZW', + }, 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 - }); -``` + ``` + + + + + ```js + var social = new NEARSocialSDK(); + + social.storageDeposit({ + account: { + accountID: 'alice.near', + publicKey: 'ed25519:H9k5eiU4xXS3M4z8HzKJSLaZdqGdGwBG49o7orNC4eZW', + }, + account_id: 'bob.near', // optional, defaults to the signer account + deposit: '10000000000000000000000', // the amount to deposit in yoctoNEAR + registration_only: true // set to true if you want to pay only the bare minimum deposit + }) + .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 social = new Social(); + const transaction = await social.storageDeposit({ + account: { + accountID: 'alice.near', + publicKey: 'ed25519:H9k5eiU4xXS3M4z8HzKJSLaZdqGdGwBG49o7orNC4eZW', + }, + account_id: 'bob.near', // optional, defaults to the signer account + deposit: '10000000000000000000000', // the amount to deposit in yoctoNEAR + registration_only: true, // set to true if you want to pay only the bare minimum deposit + }); + // ...sign the returned transaction and post to the network + ``` # 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. The signer account MUST have sufficient NEAR balance available for withdrawal. - - -```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, + 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 transaction = await social.storageWithdraw({ + account: { + accountID: 'alice.near', + publicKey: 'ed25519:H9k5eiU4xXS3M4z8HzKJSLaZdqGdGwBG49o7orNC4eZW', + }, 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 - }); -``` + ``` + + + ```js + var social = new NEARSocialSDK(); + + social.storageWithdraw({ + account: { + accountID: 'alice.near', + publicKey: 'ed25519:H9k5eiU4xXS3M4z8HzKJSLaZdqGdGwBG49o7orNC4eZW', + }, + 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 + }); + ``` + + -```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 social = new Social(); + const transaction = await social.storageWithdraw({ + account: { + accountID: 'alice.near', + publicKey: 'ed25519:H9k5eiU4xXS3M4z8HzKJSLaZdqGdGwBG49o7orNC4eZW', + }, + amount: '5000000000000000000000', // the amount to withdraw in yoctoNEAR, optional, defaults to all available balance + }); + // ...sign the returned transaction and post to the network + ``` diff --git a/docs/advanced/storing-data.mdx b/docs/advanced/storing-data.mdx index 078da87..2361df3 100644 --- a/docs/advanced/storing-data.mdx +++ b/docs/advanced/storing-data.mdx @@ -39,19 +39,19 @@ The signer account automatically has write permissions for their own account. ```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.set({ + account: { + accountID: 'alice.near', + publicKey: 'ed25519:H9k5eiU4xXS3M4z8HzKJSLaZdqGdGwBG49o7orNC4eZW', + }, data: { ['alice.near']: { profile: { - name: 'Alice' - } - } + name: 'Alice', + }, + }, }, - publicKey: accessKeys[0].public_key, - signer, }); // ...sign the returned transaction and post to the network @@ -61,35 +61,24 @@ The signer account automatically has write permissions for their own account. ```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.set({ - data: { - ['alice.near']: { - profile: { - name: 'Alice' - } - } - }, - publicKey: accessKeys[0].public_key, - signer, - }); - }) - .then((transaction) => { - // ...sign the returned transaction and post to the network - }); + var social = new NEARSocialSDK(); + + social.set({ + account: { + accountID: 'alice.near', + publicKey: 'ed25519:H9k5eiU4xXS3M4z8HzKJSLaZdqGdGwBG49o7orNC4eZW', + }, + data: { + ['alice.near']: { + profile: { + name: 'Alice' + } + } + } + }) + .then((transaction) => { + // ...sign the returned transaction and post to the network + }); ``` @@ -98,19 +87,19 @@ The signer account automatically has write permissions for their own account. ```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.set({ + account: { + accountID: 'alice.near', + publicKey: 'ed25519:H9k5eiU4xXS3M4z8HzKJSLaZdqGdGwBG49o7orNC4eZW', + }, data: { ['alice.near']: { profile: { - name: 'Alice' - } - } + name: 'Alice', + }, + }, }, - publicKey: accessKeys[0].public_key, - signer, }); // ...sign the returned transaction and post to the network diff --git a/docs/api-reference/errors.md b/docs/api-reference/errors.md index 435abab..dd5b01a 100644 --- a/docs/api-reference/errors.md +++ b/docs/api-reference/errors.md @@ -2,10 +2,11 @@ ## Summary -| Code | Name | Summary | -|------|---------------------------------------------------|--------------------------------| -| 2000 | [`InvalidAccountIdError`](#invalidaccountiderror) | When an account ID is invalid. | -| 3000 | [`KeyNotAllowedError`](#keynotallowederror) | When a key is not allowed. | +| Code | Name | Summary | +|------|---------------------------------------------------|-----------------------------------| +| 2000 | [`InvalidAccountIdError`](#invalidaccountiderror) | When an account ID is invalid. | +| 3000 | [`KeyNotAllowedError`](#keynotallowederror) | When a key is not allowed. | +| 4000 | [`UnknownNetworkError`](#unknownnetworkerror) | When the network ID is not known. | ## `InvalidAccountIdError` @@ -30,3 +31,15 @@ This error is thrown when a key is not allowed, usually when an account has not | code | `number` | 3000 | A canonical code for this error. | | key | `string` | - | The key that is not allowed. | | message | `string` | - | A human readable message. | + +## `UnknownNetworkError` + +This error is thrown when initializing the SDK and the network ID supplied, is not known. + +#### Properties + +| Name | Type | Value | Description | +|-----------|----------|-------|----------------------------------| +| code | `number` | 4000 | A canonical code for this error. | +| message | `string` | - | A human readable message. | +| networkID | `string` | - | The network ID that is invalid. | diff --git a/docs/api-reference/index.md b/docs/api-reference/index.md index f453095..2f8363c 100644 --- a/docs/api-reference/index.md +++ b/docs/api-reference/index.md @@ -3,3 +3,4 @@ * [`Social`](api-reference/social) - The main client used to interact with the social contract. * [`Types`](api-reference/types) - Various types used within the SDK. * [`Errors`](api-reference/errors) - Various error responses that can be thrown. +* [`Networks`](api-reference/networks) - The default RPC networks used by their network ID. diff --git a/docs/api-reference/networks.md b/docs/api-reference/networks.md new file mode 100644 index 0000000..2dd65e1 --- /dev/null +++ b/docs/api-reference/networks.md @@ -0,0 +1,10 @@ +# Networks + +Below are the URLs of the default RPC networks that are used, referenced by the network ID. + +| Network ID | RPC URL | +|------------|--------------------------------------------------------------| +| `betanet` | [https://rpc.betanet.near.org](https://rpc.betanet.near.org) | +| `localnet` | [http://localhost:3030](http://localhost:3030) | +| `mainnet` | [https://rpc.mainnet.near.org](https://rpc.mainnet.near.org) | +| `testnet` | [https://rpc.testnet.near.org](https://rpc.testnet.near.org) | diff --git a/docs/api-reference/social.mdx b/docs/api-reference/social.mdx index f2972d4..5a01103 100644 --- a/docs/api-reference/social.mdx +++ b/docs/api-reference/social.mdx @@ -15,9 +15,9 @@ import TOCInline from '@theme/TOCInline'; #### Parameters -| Name | Type | Required | Default | Description | -|---------|------------------------------------------------|----------|---------|----------------------------------| -| options | [`INewSocialOptions`](types#inewsocialoptions) | no | - | Options that initialize the SDK. | +| Name | Type | Required | Default | Description | +|---------|------------------------------------------------|----------|---------|---------------------------------------------------------------------------------------------------------------------------| +| options | [`INewSocialOptions`](types#inewsocialoptions) | no | - | Options that initialize the SDK such as the social contract account ID and the network ID or custom RPC provider details. | #### Returns @@ -39,8 +39,8 @@ import TOCInline from '@theme/TOCInline'; #### Parameters -| Name | Type | Required | Default | Description | -|---------|------------------------------------|----------|---------|------------------------------------------------------------| +| Name | Type | Required | Default | Description | +|---------|------------------------------------|----------|---------|-----------------------------------------------------| | options | [`IGetOptions`](types#igetoptions) | yes | - | Options that include the rpc url and a set of keys. | #### Returns @@ -111,9 +111,9 @@ Accounts that match the signer's account ID automatically have write permission #### Returns -| Type | Description | -|---------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------| -| [`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. | +| 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 update the specified data. | ### `storageDeposit(options)` @@ -129,14 +129,14 @@ 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. | @@ -153,12 +153,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 412ab15..1386ff9 100644 --- a/docs/api-reference/types.mdx +++ b/docs/api-reference/types.mdx @@ -7,26 +7,31 @@ import TOCInline from '@theme/TOCInline'; toc={toc} /> +### `IAccount` + +| Name | Type | Required | Default | Description | +|-----------|--------------------------------------------------------------------------------------------------------|----------|---------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| accountID | `string` | yes | - | The account ID of the account used to sign the transaction. | +| publicKey | [`PublicKey`](https://near.github.io/near-api-js/classes/near_api_js.utils.PublicKey.html) \| `string` | yes | - | The public key of the access key that will be used to sign the transaction. The key must have write access for the account. For details on managing keys see the NEAR API [docs](https://docs.near.org/tools/near-api-js/account#access-keys). | + ### `IGetOptions` | Name | Type | Required | Default | Description | |-----------------|------------------------------------------------------------------------------------------|----------|---------|--------------------------------------------------------------------------------------------------------------------------------------------------------------| | keys | `string[]` | yes | - | A set of key patterns to return. Each key is in the form of a pattern to return data from. For example `alice.near/profile/**` or `alice.near/profile/name`. | -| rpcURL | `string` | yes | - | URL to your current network's RPC node, for example on mainnet, you connect to https://rpc.mainnet.near.org/ | | returnDeleted | `boolean` | no | `false` | If true, will include deleted keys with the value `null`. | | withBlockHeight | `boolean` | no | `false` | If true, for every value and a node will add the block height of the data with the key `:block`. | | withNodeId | `boolean` | no | `false` | If true, for every node will add the node index with the key `:node`. | ### `IGrantWritePermissionOptions` -| Name | Type | Required | Default | Description | -|------------------|--------------------------------------------------------------------------------------------------------|----------|---------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| blockHash | `string` | yes | - | The block hash that is returned from [`getAccessKeys()`](https://near.github.io/near-api-js/classes/near_api_js.account.Account.html#getAccessKeys). See the [`AccessKeyView`](https://near.github.io/near-api-js/interfaces/near_api_js.providers_provider.AccessKeyView.html) object for more information. | -| granteeAccountId | `string` | yes | - | The account ID to give write permission to. | -| keys | `string[]` | yes | - | A set of keys to give the grantee write permission. For example `alice.near/profile/**` or `alice.near/profile/name`. | -| nonce | `bigint` | yes | - | The access key's nonce. See the [`AccessKeyView`](https://near.github.io/near-api-js/interfaces/near_api_js.providers_provider.AccessKeyView.html) object for more information. | -| 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. The key must have write access for the account. For details on managing keys see the NEAR API [docs](https://docs.near.org/tools/near-api-js/account#access-keys). | -| 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 | +|------------------|-------------------------|----------|---------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| account | [`IAccount`](#iaccount) | yes | - | An object that contains the account ID and the public key that will be used to sign the transaction. | +| blockHash | `string` | yes | - | The block hash that is returned from [`getAccessKeys()`](https://near.github.io/near-api-js/classes/near_api_js.account.Account.html#getAccessKeys). See the [`AccessKeyView`](https://near.github.io/near-api-js/interfaces/near_api_js.providers_provider.AccessKeyView.html) object for more information. | +| granteeAccountId | `string` | yes | - | The account ID to give write permission to. | +| keys | `string[]` | yes | - | A set of keys to give the grantee write permission. For example `alice.near/profile/**` or `alice.near/profile/name`. | +| nonce | `bigint` | yes | - | The access key's nonce. See the [`AccessKeyView`](https://near.github.io/near-api-js/interfaces/near_api_js.providers_provider.AccessKeyView.html) object for more information. | ### `IIsWritePermissionGrantedOptions` @@ -34,41 +39,47 @@ import TOCInline from '@theme/TOCInline'; |------------------|------------------------------------------------------------------------------------------|----------|---------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | granteeAccountId | `string` | yes | - | The account ID to check if it has write permissions for a key. | | key | `string` | yes | - | The key to check if the grantee has write permission. | -| rpcURL | `string` | yes | - | URL to your current network's RPC node, for example on mainnet, you connect to https://rpc.mainnet.near.org/ | ### `INewSocialOptions` -| Name | Type | Required | Default | Description | -|------------|----------|----------|---------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------| -| contractId | `string` | no | `social.near` | The account ID of the social contract. This defaults to the mainnet social contract account ID: [`social.near`](https://nearblocks.io/address/social.near). | +| Name | Type | Required | Default | Description | +|------------|-------------------------------------------|----------|---------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| contractId | `string` | no | `social.near` | The account ID of the social contract. This defaults to the mainnet social contract account ID: [`social.near`](https://nearblocks.io/address/social.near). | +| network | `string` \| [`IRPCOptions`](#irpcoptions) | no | `mainnet` | This can be a network ID string (`betanet`, `localnet`, `mainnet` or `testnet`) which will use a public RPC provider, or you can use a custom RPC URL with an API key. | + +### `IRPCOptions` + +| Name | Type | Required | Default | Description | +|--------|----------|----------|---------|----------------------------------------------------------------------------------| +| apiKey | `string` | no | - | An API key that is used in the `X-Api-Key` header for all RPC provider requests. | +| url | `string` | yes | - | The RPC provider URL. | ### `ISetOptions` -| Name | Type | Required | Default | Description | -|---------------------|--------------------------------------------------------------------------------------------------------|----------|---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| blockHash | `string` | no | - | A current block hash (within 24 hours). Defaults to the latest block hash. | -| data | `object` | yes | - | Each top-level property must be the account ID. The nested objects/properties will be written to the contract, however, if any nested properties are `null` values, this signals a deletion of that key. | -| nonce | `bigint` | no | - | The access key's nonce. See the [`AccessKeyView`](https://near.github.io/near-api-js/interfaces/near_api_js.providers_provider.AccessKeyView.html) object for more information. 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. The key must have write access for the account. For details on managing keys see the NEAR API [docs](https://docs.near.org/tools/near-api-js/account#access-keys). | -| 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). | +| Name | Type | Required | Default | Description | +|---------------------|-------------------------|----------|---------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| account | [`IAccount`](#iaccount) | yes | - | An object that contains the account ID and the public key that will be used to sign the transaction. | +| blockHash | `string` | no | - | A current block hash (within 24 hours). Defaults to the latest block hash. | +| data | `object` | yes | - | Each top-level property must be the account ID. The nested objects/properties will be written to the contract, however, if any nested properties are `null` values, this signals a deletion of that key. | +| nonce | `bigint` | no | - | The access key's nonce. See the [`AccessKeyView`](https://near.github.io/near-api-js/interfaces/near_api_js.providers_provider.AccessKeyView.html) object for more information. Defaults to the current access key nonce incremented by 1. | +| refundUnusedDeposit | `boolean` | no | `false` | If true, will refund any left over deposit to the signer's 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). | + +| Name | Type | Required | Default | Description | +|-------------------|--------------------------------|----------|---------|------------------------------------------------------------------------------------------------------| +| account | [`IAccount`](#iaccount) | yes | - | An object that contains the account ID and the public key that will be used to sign the transaction. | +| 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. | ### `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 | +|-----------|-------------------------|----------|---------|------------------------------------------------------------------------------------------------------| +| account | [`IAccount`](#iaccount) | yes | - | An object that contains the account ID and the public key that will be used to sign the transaction. | +| 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. | diff --git a/docs/scripts/sidebars.js b/docs/scripts/sidebars.js index 8b68478..f7cb855 100644 --- a/docs/scripts/sidebars.js +++ b/docs/scripts/sidebars.js @@ -32,6 +32,7 @@ const sidebars = { 'api-reference/social', 'api-reference/types', 'api-reference/errors', + 'api-reference/networks', ], label: 'API Reference', link: { diff --git a/docs/usage/getting-started.mdx b/docs/usage/getting-started.mdx index da2884a..4e63540 100644 --- a/docs/usage/getting-started.mdx +++ b/docs/usage/getting-started.mdx @@ -72,13 +72,13 @@ To initialize the SDK, simply instantiate the [`Social`](../api-reference/social :::note -By default, the Social SDK is initialized for mainnet's social contract at account ID: [`social.near`](https://nearblocks.io/address/social.near). +By default, the Social SDK is initialized for the mainnet social contract ([`social.near`](https://nearblocks.io/address/social.near)) and the mainnet RPC provider (https://rpc.mainnet.near.org). ::: :::note -See [`INewSocialOptions`](../../api-reference/types#inewsocialoptions) for more information on what options are supported. +See [`INewSocialOptions`](../api-reference/types#inewsocialoptions) for more information on what options are supported. ::: @@ -86,6 +86,50 @@ See [`INewSocialOptions`](../../api-reference/types#inewsocialoptions) for more You can initialize the SDK with a different social contract account by specifying it in the options: + + + + ```js + const { Social } = require('@builddao/near-social-js'); + + const social = new Social({ + contractId: 'mysocialcontract.near', + }); + ``` + + + + + ```js + var social = new NEARSocialSDK({ + contractId: 'mysocialcontract.near', + }); + ``` + + + + + ```typescript + import { Social } from '@builddao/near-social-js'; + + const social = new Social({ + contractId: 'mysocialcontract.near', + }); + ``` + + + + +## Initialization with a different network ID + +You can use a specific network by initializing the SDK with a known network ID. See [networks](../api-reference/networks) on the supported networks and the RPC URLs they point to. + ```typescript - import { Social } from '@builddao/near-social-js'; + import { NetworkIDEnum, Social } from '@builddao/near-social-js'; const social = new Social({ contractId: 'v1.social08.testnet', + network: NetworkIDEnum.Testnet, + }); + ``` + + + + +:::caution + +If using the network ID, make sure you provide the correct social contract for that network. + +::: + +:::note + +An [`UnknownNetworkError`](../api-reference/errors#unkownnetworkerror) will be thrown if the supplied network ID is not known. + +::: + +## Initialization with a custom RPC provider + +If you want to use your own RPC provider, you can initialize the SDK by specifying it in the options: + + + + + ```js + const { Social } = require('@builddao/near-social-js'); + + const social = new Social({ + network: { + apiKey: 'some key', + url: 'https://custom-rpc.near.org', + }, + }); + ``` + + + + + ```js + var social = new NEARSocialSDK({ + network: { + apiKey: 'some key', + url: 'https://custom-rpc.near.org' + } + }); + ``` + + + + + ```typescript + import { Social } from '@builddao/near-social-js'; + + const social = new Social({ + network: { + apiKey: 'some key', + url: 'https://custom-rpc.near.org', + }, }); ``` diff --git a/src/controllers/Social.get.test.ts b/src/controllers/Social.get.test.ts index f101758..f801df5 100644 --- a/src/controllers/Social.get.test.ts +++ b/src/controllers/Social.get.test.ts @@ -3,18 +3,20 @@ import { account_id as socialContractAccountId } from '@test/credentials/localne // controllers import Social from './Social'; -import { networkRPCs } from '@app/constants'; + +// enums +import { NetworkIDEnum } from '@app/enums'; describe(`${Social.name}#get`, () => { it('should return an empty object when the contract does not know the account', async () => { // arrange const client = new Social({ contractId: socialContractAccountId, + network: NetworkIDEnum.Localnet, }); // act const result = await client.get({ keys: ['unknown.test.near/profile/name'], - rpcURL: networkRPCs.localnet, }); // assert diff --git a/src/controllers/Social.getVersion.test.ts b/src/controllers/Social.getVersion.test.ts index 1e6f84e..60ebbeb 100644 --- a/src/controllers/Social.getVersion.test.ts +++ b/src/controllers/Social.getVersion.test.ts @@ -3,18 +3,19 @@ import { account_id as socialContractAccountId } from '@test/credentials/localne // controllers import Social from './Social'; -import { networkRPCs } from '@app/constants'; + +// enums +import { NetworkIDEnum } from '@app/enums'; describe(`${Social.name}#getVersion`, () => { it('should return the version of the social contract', async () => { // arrange const client = new Social({ contractId: socialContractAccountId, + network: NetworkIDEnum.Localnet, }); // act - const version = await client.getVersion({ - rpcURL: networkRPCs.localnet, - }); + const version = await client.getVersion(); // assert expect(version).toMatchSnapshot(); diff --git a/src/controllers/Social.grantWritePermission.test.ts b/src/controllers/Social.grantWritePermission.test.ts index 800f02e..00f4466 100644 --- a/src/controllers/Social.grantWritePermission.test.ts +++ b/src/controllers/Social.grantWritePermission.test.ts @@ -7,10 +7,8 @@ import { account_id as socialContractAccountId } from '@test/credentials/localne // controllers import Social from './Social'; -import { networkRPCs } from '@app/constants'; - // enums -import { ErrorCodeEnum } from '@app/enums'; +import { ErrorCodeEnum, NetworkIDEnum } from '@app/enums'; // errors import { InvalidAccountIdError, KeyNotAllowedError } from '@app/errors'; @@ -49,6 +47,7 @@ describe(`${Social.name}#grantWritePermission`, () => { client = new Social({ contractId: socialContractAccountId, + network: NetworkIDEnum.Localnet, }); key = `${granterAccount.accountId}/profile/name`; granterKeyResponse = await accountAccessKey( @@ -68,8 +67,10 @@ describe(`${Social.name}#grantWritePermission`, () => { }, }, nonce: BigInt(granterNonce), - publicKey: granterKeyPair.publicKey, - signer: granterAccount, + account: { + accountID: granterAccount.accountId, + publicKey: granterKeyPair.publicKey, + }, }); await signAndSendTransaction({ @@ -85,12 +86,14 @@ describe(`${Social.name}#grantWritePermission`, () => { // act try { await client.grantWritePermission({ + account: { + accountID: granterAccount.accountId, + publicKey: granterKeyPair.publicKey, + }, blockHash: granterKeyResponse.block_hash, granteeAccountId: invalidGranteeAccountId, keys: [key], nonce: BigInt(granterNonce + 1), - publicKey: granterKeyPair.publicKey, - signer: granterAccount, }); } catch (error) { // assert @@ -110,12 +113,14 @@ describe(`${Social.name}#grantWritePermission`, () => { // act try { await client.grantWritePermission({ + account: { + accountID: granterAccount.accountId, + publicKey: granterKeyPair.publicKey, + }, blockHash: granterKeyResponse.block_hash, granteeAccountId: granteeAccount.accountId, keys: [`${invalidKeyAccountId}/profile/name`], nonce: BigInt(granterNonce + 1), - publicKey: granterKeyPair.publicKey, - signer: granterAccount, }); } catch (error) { // assert @@ -135,12 +140,14 @@ describe(`${Social.name}#grantWritePermission`, () => { // act try { await client.grantWritePermission({ + account: { + accountID: granterAccount.accountId, + publicKey: granterKeyPair.publicKey, + }, blockHash: granterKeyResponse.block_hash, granteeAccountId: granteeAccount.accountId, keys: [key], nonce: BigInt(granterNonce + 1), - publicKey: granterKeyPair.publicKey, - signer: granterAccount, }); } catch (error) { // assert @@ -158,12 +165,14 @@ describe(`${Social.name}#grantWritePermission`, () => { // act transaction = await client.grantWritePermission({ + account: { + accountID: granterAccount.accountId, + publicKey: granterKeyPair.publicKey, + }, blockHash: granterKeyResponse.block_hash, granteeAccountId: granteeAccount.accountId, keys: [key], nonce: BigInt(granterNonce + 1), - publicKey: granterKeyPair.publicKey, - signer: granterAccount, }); await signAndSendTransaction({ @@ -175,7 +184,6 @@ describe(`${Social.name}#grantWritePermission`, () => { result = await client.isWritePermissionGranted({ granteeAccountId: granteeAccount.accountId, key, - rpcURL: networkRPCs.localnet, }); expect(result).toBe(true); @@ -188,12 +196,14 @@ describe(`${Social.name}#grantWritePermission`, () => { // act transaction = await client.grantWritePermission({ + account: { + accountID: granterAccount.accountId, + publicKey: granterKeyPair.publicKey, + }, blockHash: granterKeyResponse.block_hash, - granteePublicKey: granteeKeyPair.getPublicKey(), + granteePublicKey: granteeKeyPair.publicKey, keys: [key], nonce: BigInt(granterNonce + 1), - publicKey: granterKeyPair.getPublicKey(), - signer: granterAccount, }); await signAndSendTransaction({ @@ -203,9 +213,8 @@ describe(`${Social.name}#grantWritePermission`, () => { // assert result = await client.isWritePermissionGranted({ - granteePublicKey: granteeKeyPair.getPublicKey(), + granteePublicKey: granteeKeyPair.publicKey, key, - rpcURL: networkRPCs.localnet, }); expect(result).toBe(true); diff --git a/src/controllers/Social.isWritePermissionGranted.test.ts b/src/controllers/Social.isWritePermissionGranted.test.ts index 8afbbeb..0520c78 100644 --- a/src/controllers/Social.isWritePermissionGranted.test.ts +++ b/src/controllers/Social.isWritePermissionGranted.test.ts @@ -7,10 +7,8 @@ import { account_id as socialContractAccountId } from '@test/credentials/localne // controllers import Social from './Social'; -import { networkRPCs } from '@app/constants'; - // enums -import { ErrorCodeEnum } from '@app/enums'; +import { ErrorCodeEnum, NetworkIDEnum } from '@app/enums'; // errors import { InvalidAccountIdError } from '@app/errors'; @@ -51,6 +49,7 @@ describe(`${Social.name}#isWritePermissionGranted`, () => { client = new Social({ contractId: socialContractAccountId, + network: NetworkIDEnum.Localnet, }); key = `${granterAccount.accountId}/profile/name`; granterKeyResponse = await accountAccessKey( @@ -61,6 +60,10 @@ describe(`${Social.name}#isWritePermissionGranted`, () => { // set the granter transaction = await client.set({ + account: { + accountID: granterAccount.accountId, + publicKey: granterKeyPair.publicKey, + }, blockHash: granterKeyResponse.block_hash, data: { [granterAccount.accountId]: { @@ -70,8 +73,6 @@ describe(`${Social.name}#isWritePermissionGranted`, () => { }, }, nonce: BigInt(granterNonce), - publicKey: granterKeyPair.publicKey, - signer: granterAccount, }); await signAndSendTransaction({ @@ -89,7 +90,6 @@ describe(`${Social.name}#isWritePermissionGranted`, () => { await client.isWritePermissionGranted({ granteeAccountId: invalidGranteeAccountId, key, - rpcURL: networkRPCs.localnet, }); } catch (error) { // assert @@ -108,7 +108,6 @@ describe(`${Social.name}#isWritePermissionGranted`, () => { const result = await client.isWritePermissionGranted({ granteeAccountId: granterAccount.accountId, key, - rpcURL: networkRPCs.localnet, }); // assert @@ -121,7 +120,6 @@ describe(`${Social.name}#isWritePermissionGranted`, () => { const result = await client.isWritePermissionGranted({ granteeAccountId: granteeAccount.accountId, key, - rpcURL: networkRPCs.localnet, }); // assert @@ -131,10 +129,12 @@ describe(`${Social.name}#isWritePermissionGranted`, () => { it('should return true if the grantee has been given permission (using account id)', async () => { // arrange const transaction = await client.grantWritePermission({ - granteeAccountId: granteeAccount.accountId, + account: { + accountID: granterAccount.accountId, + publicKey: granterKeyPair.publicKey, + }, keys: [key], - publicKey: granterKeyPair.getPublicKey(), - signer: granterAccount, + granteeAccountId: granteeAccount.accountId, }); await signAndSendTransaction({ @@ -146,7 +146,6 @@ describe(`${Social.name}#isWritePermissionGranted`, () => { const result = await client.isWritePermissionGranted({ granteeAccountId: granteeAccount.accountId, key, - rpcURL: networkRPCs.localnet, }); // assert @@ -156,10 +155,12 @@ describe(`${Social.name}#isWritePermissionGranted`, () => { it('should return true if the grantee has been given permission (using public key)', async () => { // arrange const transaction = await client.grantWritePermission({ - granteePublicKey: granteeKeyPair.getPublicKey(), + account: { + accountID: granterAccount.accountId, + publicKey: granterKeyPair.publicKey, + }, + granteePublicKey: granteeKeyPair.publicKey, keys: [key], - publicKey: granterKeyPair.getPublicKey(), - signer: granterAccount, }); await signAndSendTransaction({ @@ -169,9 +170,8 @@ describe(`${Social.name}#isWritePermissionGranted`, () => { // act const result = await client.isWritePermissionGranted({ - granteePublicKey: granteeKeyPair.getPublicKey(), + granteePublicKey: granteeKeyPair.publicKey, key, - rpcURL: networkRPCs.localnet, }); // assert diff --git a/src/controllers/Social.set.test.ts b/src/controllers/Social.set.test.ts index 46651f4..bc27b71 100644 --- a/src/controllers/Social.set.test.ts +++ b/src/controllers/Social.set.test.ts @@ -1,19 +1,17 @@ import { Account, providers, transactions, utils } from 'near-api-js'; import { randomBytes } from 'node:crypto'; -// credentials -import { account_id as socialContractAccountId } from '@test/credentials/localnet/social.test.near.json'; - // constants import { MINIMUM_STORAGE_IN_BYTES } from '@app/constants'; // controllers import Social from './Social'; -import { networkRPCs } from '@app/constants'; +// credentials +import { account_id as socialContractAccountId } from '@test/credentials/localnet/social.test.near.json'; // enums -import { ErrorCodeEnum } from '@app/enums'; +import { ErrorCodeEnum, NetworkIDEnum } from '@app/enums'; // errors import { KeyNotAllowedError } from '@app/errors'; @@ -47,6 +45,7 @@ async function sendTransaction( } describe(`${Social.name}#set`, () => { + let client: Social; let keyPair: utils.KeyPairEd25519; let signer: Account; let signerAccessKeyResponse: IAccessKeyResponse; @@ -55,6 +54,10 @@ describe(`${Social.name}#set`, () => { beforeEach(async () => { const result = await createEphemeralAccount(convertNEARToYoctoNEAR('100')); + client = new Social({ + contractId: socialContractAccountId, + network: NetworkIDEnum.Localnet, + }); keyPair = result.keyPair; signer = result.account; signerAccessKeyResponse = await accountAccessKey(signer, keyPair.publicKey); @@ -63,13 +66,13 @@ describe(`${Social.name}#set`, () => { it('should throw an error if the public key does not have write permission', async () => { // arrange - const client = new Social({ - contractId: socialContractAccountId, - }); - try { // act await client.set({ + account: { + accountID: signer.accountId, + publicKey: keyPair.publicKey, + }, blockHash: signerAccessKeyResponse.block_hash, data: { ['iamnotthesigner.test.near']: { @@ -79,8 +82,6 @@ describe(`${Social.name}#set`, () => { }, }, nonce: BigInt(signerNonce + 1), - publicKey: keyPair.publicKey, - signer, }); } catch (error) { // assert @@ -96,9 +97,6 @@ describe(`${Social.name}#set`, () => { it('should add some arbitrary data', async () => { // arrange - const client = new Social({ - contractId: socialContractAccountId, - }); const data: Record> = { [signer.accountId]: { profile: { @@ -111,9 +109,11 @@ describe(`${Social.name}#set`, () => { // act transaction = await client.set({ + account: { + accountID: signer.accountId, + publicKey: keyPair.publicKey, + }, data, - publicKey: keyPair.publicKey, - signer, }); // assert @@ -121,7 +121,6 @@ describe(`${Social.name}#set`, () => { result = await client.get({ keys: [`${signer.accountId}/profile/name`], - rpcURL: networkRPCs.localnet, }); expect(result).toEqual(data); @@ -129,9 +128,6 @@ describe(`${Social.name}#set`, () => { it('should add data that exceeds the minimum storage amount', async () => { // arrange - const client = new Social({ - contractId: socialContractAccountId, - }); const data: Record> = { [signer.accountId]: { profile: { @@ -146,9 +142,11 @@ describe(`${Social.name}#set`, () => { // act transaction = await client.set({ + account: { + accountID: signer.accountId, + publicKey: keyPair.publicKey, + }, data, - publicKey: keyPair.publicKey, - signer, }); // assert @@ -156,7 +154,6 @@ describe(`${Social.name}#set`, () => { result = await client.get({ keys: [`${signer.accountId}/profile/name`], - rpcURL: networkRPCs.localnet, }); expect(result).toEqual(data); diff --git a/src/controllers/Social.storageDeposit.test.ts b/src/controllers/Social.storageDeposit.test.ts index 48bf7bf..1f11949 100644 --- a/src/controllers/Social.storageDeposit.test.ts +++ b/src/controllers/Social.storageDeposit.test.ts @@ -1,12 +1,13 @@ import { Account, providers, transactions, utils } from 'near-api-js'; -//import { randomBytes } from 'node:crypto'; -import { ViewMethodEnum } from '@app/enums'; + +// controllers +import Social from './Social'; // credentials import { account_id as socialContractAccountId } from '@test/credentials/localnet/social.test.near.json'; -// controllers -import Social from './Social'; +// enums +import { NetworkIDEnum, ViewMethodEnum } from '@app/enums'; // helpers import accountAccessKey, { @@ -31,6 +32,7 @@ describe(`${Social.name}#storageDeposit`, () => { // arrange const client = new Social({ contractId: socialContractAccountId, + network: NetworkIDEnum.Localnet, }); let result: Record; let transaction: transactions.Transaction; @@ -41,10 +43,12 @@ describe(`${Social.name}#storageDeposit`, () => { let deposit = '2000000000000000000000000'; //testing optional blockhash and nonce too transaction = await client.storageDeposit({ - publicKey: keyPair.publicKey, - signer, accountId, deposit, + account: { + accountID: signer.accountId, + publicKey: keyPair.publicKey, + }, }); // assert @@ -90,9 +94,11 @@ describe(`${Social.name}#storageDeposit`, () => { transaction = await client.storageDeposit({ blockHash: signerAccessKeyResponse.block_hash, nonce: BigInt(signerAccessKeyResponse.nonce + 1), - publicKey: keyPair.publicKey, - signer, deposit, + account: { + accountID: signer.accountId, + publicKey: keyPair.publicKey, + }, }); // assert @@ -139,10 +145,12 @@ describe(`${Social.name}#storageDeposit`, () => { transaction = await client.storageDeposit({ blockHash: signerAccessKeyResponse.block_hash, nonce: BigInt(signerAccessKeyResponse.nonce + 1), - publicKey: keyPair.publicKey, - signer, accountId, deposit, + account: { + accountID: signer.accountId, + publicKey: keyPair.publicKey, + }, }); // assert diff --git a/src/controllers/Social.storageWithdraw.test.ts b/src/controllers/Social.storageWithdraw.test.ts index 0f1f514..f7a0de0 100644 --- a/src/controllers/Social.storageWithdraw.test.ts +++ b/src/controllers/Social.storageWithdraw.test.ts @@ -1,5 +1,4 @@ import { Account, providers, transactions, utils } from 'near-api-js'; -//import { randomBytes } from 'node:crypto'; import { ViewMethodEnum } from '@app/enums'; // credentials @@ -8,6 +7,9 @@ import { account_id as socialContractAccountId } from '@test/credentials/localne // controllers import Social from './Social'; +// enums +import { NetworkIDEnum } from '@app/enums'; + // helpers import accountAccessKey, { IAccessKeyResponse, @@ -31,6 +33,7 @@ describe(`${Social.name}#storageWithdraw`, () => { // arrange const client = new Social({ contractId: socialContractAccountId, + network: NetworkIDEnum.Localnet, }); let resultBefore: Record; let resultAfter: Record; @@ -45,10 +48,12 @@ describe(`${Social.name}#storageWithdraw`, () => { //2N deposit let deposit = '2000000000000000000000000'; transaction = await client.storageDeposit({ + account: { + accountID: signer.accountId, + publicKey: keyPair.publicKey, + }, blockHash: signerAccessKeyResponse.block_hash, nonce: BigInt(signerAccessKeyResponse.nonce + 1), - publicKey: keyPair.publicKey, - signer, accountId, deposit, }); @@ -85,11 +90,13 @@ describe(`${Social.name}#storageWithdraw`, () => { //1N withdraw let withdraw_amount = '1000000000000000000000000'; transaction = await client.storageWithdraw({ + account: { + accountID: signer.accountId, + publicKey: keyPair.publicKey, + }, + amount: withdraw_amount, blockHash: signerAccessKeyResponse.block_hash, nonce: BigInt(signerAccessKeyResponse.nonce + 1 + 1), - publicKey: keyPair.publicKey, - signer, - amount: withdraw_amount, }); // assert @@ -145,10 +152,12 @@ describe(`${Social.name}#storageWithdraw`, () => { //2N deposit let deposit = '2000000000000000000000000'; transaction = await client.storageDeposit({ + account: { + accountID: signer.accountId, + publicKey: keyPair.publicKey, + }, blockHash: signerAccessKeyResponse.block_hash, nonce: BigInt(signerAccessKeyResponse.nonce + 1), - publicKey: keyPair.publicKey, - signer, accountId, deposit, }); @@ -184,10 +193,12 @@ describe(`${Social.name}#storageWithdraw`, () => { //No withdrawal amount specified transaction = await client.storageWithdraw({ + account: { + accountID: signer.accountId, + publicKey: keyPair.publicKey, + }, blockHash: signerAccessKeyResponse.block_hash, nonce: BigInt(signerAccessKeyResponse.nonce + 1 + 1), - publicKey: keyPair.publicKey, - signer, }); // assert diff --git a/src/controllers/Social.ts b/src/controllers/Social.ts index 81edae5..027e6c2 100644 --- a/src/controllers/Social.ts +++ b/src/controllers/Social.ts @@ -1,11 +1,6 @@ import type { AccessKeyView } from '@near-js/types'; import BigNumber from 'bignumber.js'; -import { - type Account, - type Connection, - transactions, - utils, -} from 'near-api-js'; +import { providers, transactions, utils } from 'near-api-js'; // constants import { @@ -22,17 +17,18 @@ import { AccountNotFoundError, InvalidAccountIdError, KeyNotAllowedError, + UnknownNetworkError, } from '@app/errors'; // types import type { IGetOptions, - IGetVersionOptions, IGrantWritePermissionWithAccountIdOptions, IGrantWritePermissionWithPublicKeyOptions, IIsWritePermissionGrantedWithAccountIdOptions, IIsWritePermissionGrantedWithPublicKeyOptions, INewSocialOptions, + IRPCOptions, ISetOptions, IStorageDepositOptions, IStorageWithdrawOptions, @@ -40,24 +36,74 @@ import type { ISocialDBContractGrantWritePermissionArgs, ISocialDBContractSetArgs, ISocialDBContractStorageBalance, - IStorageBalanceOfOptions, ISocialDBContractIsWritePermissionGrantedArgs, ISocialDBContractStorageWithdrawArgs, ISocialDBContractStorageDepositArgs, - NetworkIds, + IAccount, } from '@app/types'; // utils import calculateRequiredDeposit from '@app/utils/calculateRequiredDeposit'; import parseKeysFromData from '@app/utils/parseKeysFromData'; +import rpcURLFromNetworkID from '@app/utils/rpcURLFromNetworkID'; import validateAccountId from '@app/utils/validateAccountId'; +import viewAccessKeyList from '@app/utils/rpcQueries/viewAccessKeyList'; import viewFunction from '@app/utils/rpcQueries/viewFunction'; export default class Social { - private contractId: string; + // private variables + private readonly _contractId: string; + private readonly _provider: providers.JsonRpcProvider; constructor(options?: INewSocialOptions) { - this.contractId = options?.contractId || 'social.near'; + this._contractId = options?.contractId || 'social.near'; + this._provider = Social._initializeProvider(options?.network); + } + + /** + * private static methods + */ + + /** + * Initializes the provider with the supplied network options. If the network options are empty, the default mainnet + * is used. + * @param {string | IRPCOptions} networkIDOrRPCOptions - [optional] a network ID or the RPC options to initialize a + * provider. + * @returns {providers.JsonRpcProvider} an initialized provider to query the network with. + * @throws {UnknownNetworkError} if a network ID is supplied, but is not known. + * @private + * @static + */ + private static _initializeProvider( + networkIDOrRPCOptions?: string | IRPCOptions + ): providers.JsonRpcProvider { + let url: string | null; + + // if there is no network id/rpc details, default to mainnet + if (!networkIDOrRPCOptions) { + return new providers.JsonRpcProvider({ url: networkRPCs.mainnet }); + } + + // if there is a network id, attempt to get the rpc url + if (typeof networkIDOrRPCOptions === 'string') { + url = rpcURLFromNetworkID(networkIDOrRPCOptions); + + if (!url) { + throw new UnknownNetworkError(networkIDOrRPCOptions); + } + + return new providers.JsonRpcProvider({ url }); + } + + // otherwise, use the rpc details + return new providers.JsonRpcProvider({ + url: networkIDOrRPCOptions.url, + ...(networkIDOrRPCOptions.apiKey && { + headers: { + ['X-Api-Key']: networkIDOrRPCOptions.apiKey, + }, + }), + }); } /** @@ -66,17 +112,19 @@ export default class Social { /** * Gets the access key view. - * @param {Account} account - an initialized account. - * @param {string | utils.PublicKey} publicKey - the public key of the access key to query. + * @param {IAccount} account - the account ID and public key of the account. * @returns {Promise} a promise that resolves to the access key view or null if the access key * for the given public key does not exist. * @private */ - private async _accessKeyView( - account: Account, - publicKey: string | utils.PublicKey - ): Promise { - const accessKeys = await account.getAccessKeys(); + private async _accessKeyView({ + accountID, + publicKey, + }: IAccount): Promise { + const accessKeys = await viewAccessKeyList({ + accountID, + provider: this._provider, + }); return ( accessKeys.find((value) => value.public_key === publicKey.toString()) @@ -86,27 +134,25 @@ export default class Social { /** * Queries the node to get the latest block hash. - * @param {Connection} connection - an initialized NEAR connection. * @returns {Promise} a promise that resolves to the latest block hash. The hash will be a base58 encoded string. * @private */ - private async _latestBlockHash(connection: Connection): Promise { - const { sync_info } = await connection.provider.status(); + private async _latestBlockHash(): Promise { + const { sync_info } = await this._provider.status(); return sync_info.latest_block_hash; } - private async _storageBalanceOf({ - accountId, - rpcURL, - }: IStorageBalanceOfOptions): Promise { + private async _storageBalanceOf( + accountID: string + ): Promise { const result = await viewFunction({ - contractId: this.contractId, - method: ViewMethodEnum.StorageBalanceOf, args: { - account_id: accountId, + account_id: accountID, }, - rpcURL, + contractId: this._contractId, + method: ViewMethodEnum.StorageBalanceOf, + provider: this._provider, }); if (this._isStorageBalance(result)) { @@ -149,13 +195,13 @@ export default class Social { * Reads the data for given set of keys. * @param {IGetOptions} options - the set of keys to read and other options. * @returns {Promise>} a promise that resolves to the given data. + * @public */ public async get({ keys, returnDeleted, withBlockHeight, withNodeId, - rpcURL, }: IGetOptions): Promise> { const args: ISocialDBContractGetArgs = { keys, @@ -169,23 +215,23 @@ export default class Social { }; return (await viewFunction({ - contractId: this.contractId, - method: ViewMethodEnum.Get, args, - rpcURL, + contractId: this._contractId, + method: ViewMethodEnum.Get, + provider: this._provider, })) as Record; } /** * Gets the current version of the social contract. - * @param {IGetVersionOptions} options - Optional parameters including rpcURL. * @returns {Promise} a promise that resolves to the current version of the contract. + * @public */ - public async getVersion({ rpcURL }: IGetVersionOptions): Promise { + public async getVersion(): Promise { const version = await viewFunction({ - contractId: this.contractId, + contractId: this._contractId, method: ViewMethodEnum.GetVersion, - rpcURL, + provider: this._provider, }); if (typeof version !== 'string') { @@ -204,13 +250,14 @@ export default class Social { * and sent to the network. * @throws {InvalidAccountIdError} if the grantee account ID or the account ID specified in the keys is invalid. * @throws {KeyNotAllowedError} if account IDs specified in the keys does not match the signer (granter) account ID. + * @public */ public async grantWritePermission( options: | IGrantWritePermissionWithAccountIdOptions | IGrantWritePermissionWithPublicKeyOptions ): Promise { - const { blockHash, keys, nonce, publicKey, signer } = options; + const { account, blockHash, keys, nonce } = options; let accessKeyView: AccessKeyView | null; let _blockHash: string | null = blockHash || null; let _nonce: bigint | null = nonce || null; @@ -236,25 +283,25 @@ export default class Social { } // if the key does not belong to the signer (granter) it cannot give grant permission - if (accountId !== signer.accountId) { + if (accountId !== account.accountID) { throw new KeyNotAllowedError( value, - `key "${value}" does not belong to granter "${signer.accountId}"` + `key "${value}" does not belong to granter "${account.accountID}"` ); } }); if (!_blockHash) { - _blockHash = await this._latestBlockHash(signer.connection); + _blockHash = await this._latestBlockHash(); } if (!_nonce) { - accessKeyView = await this._accessKeyView(signer, publicKey); + accessKeyView = await this._accessKeyView(account); if (!accessKeyView) { throw new AccountNotFoundError( - signer.accountId, - `failed to get nonce for access key for "${signer.accountId}" with public key "${publicKey.toString()}"` + account.accountID, + `failed to get nonce for access key for "${account.accountID}" with public key "${account.publicKey.toString()}"` ); } @@ -262,9 +309,9 @@ export default class Social { } return transactions.createTransaction( - signer.accountId, - utils.PublicKey.fromString(publicKey.toString()), - this.contractId, + account.accountID, + utils.PublicKey.fromString(account.publicKey.toString()), + this._contractId, _nonce, [ transactions.functionCall( @@ -299,13 +346,14 @@ export default class Social { * @returns {Promise} a promise that resolves to true, if the grantee account ID has write access for the * given key, or false. * @throws {InvalidAccountIdError} if the grantee account ID is not a valid account ID. + * @public */ public async isWritePermissionGranted( options: | IIsWritePermissionGrantedWithAccountIdOptions | IIsWritePermissionGrantedWithPublicKeyOptions ): Promise { - const { key, rpcURL } = options; + const { key } = options; if ( (options as IIsWritePermissionGrantedWithAccountIdOptions) @@ -335,8 +383,6 @@ export default class Social { } const result = await viewFunction({ - contractId: this.contractId, - method: ViewMethodEnum.IsWritePermissionGranted, args: { key, ...((options as IIsWritePermissionGrantedWithAccountIdOptions) @@ -352,7 +398,9 @@ export default class Social { ).granteePublicKey.toString(), }), } as ISocialDBContractIsWritePermissionGrantedArgs, - rpcURL, + contractId: this._contractId, + method: ViewMethodEnum.IsWritePermissionGranted, + provider: this._provider, }); if (typeof result !== 'boolean') { @@ -370,49 +418,46 @@ export default class Social { * @param {ISetOptions} options - the necessary options to set some data. * @returns {Promise} a promise that resolves to a transaction that is ready to be signed * and sent to the network. + * @public */ public async set({ + account, blockHash, data, nonce, - publicKey, refundUnusedDeposit, - signer, }: ISetOptions): Promise { const keys = parseKeysFromData(data); - let _blockHash: string | null = blockHash || null; - let _nonce: bigint | null = nonce || null; + let _blockHash = blockHash || null; + let _nonce = nonce || null; let accessKeyView: AccessKeyView | null; let deposit: BigNumber = new BigNumber('1'); let storageBalance: ISocialDBContractStorageBalance | null; if (!_blockHash) { - _blockHash = await this._latestBlockHash(signer.connection); + _blockHash = await this._latestBlockHash(); } if (!_nonce) { - accessKeyView = await this._accessKeyView(signer, publicKey); + accessKeyView = await this._accessKeyView(account); if (!accessKeyView) { throw new AccountNotFoundError( - signer.accountId, - `failed to get nonce for access key for "${signer.accountId}" with public key "${publicKey.toString()}"` + account.accountID, + `failed to get nonce for access key for "${account.accountID}" with public key "${account.publicKey.toString()}"` ); } _nonce = accessKeyView.nonce + BigInt(1); // increment nonce as this will be a new transaction for the access key } - const networkId = signer.connection.networkId as NetworkIds; - const rpcURL = networkRPCs[networkId]; // for each key, check if the signer has been granted write permission for the key for (let i = 0; i < keys.length; i++) { if ( - (keys[i].split('/')[0] || '') !== signer.accountId && + (keys[i].split('/')[0] || '') !== account.accountID && !(await this.isWritePermissionGranted({ - granteePublicKey: publicKey, + granteePublicKey: account.publicKey, key: keys[i], - rpcURL, })) ) { throw new KeyNotAllowedError( @@ -425,13 +470,10 @@ export default class Social { // if the signer is updating their own data, calculate storage deposit if ( this._uniqueAccountIdsFromKeys(keys).find( - (value) => value === signer.accountId + (value) => value === account.accountID ) ) { - storageBalance = await this._storageBalanceOf({ - accountId: signer.accountId, - rpcURL, - }); + storageBalance = await this._storageBalanceOf(account.accountID); deposit = calculateRequiredDeposit({ data, @@ -440,9 +482,9 @@ export default class Social { } return transactions.createTransaction( - signer.accountId, - utils.PublicKey.fromString(publicKey.toString()), - this.contractId, + account.accountID, + utils.PublicKey.fromString(account.publicKey.toString()), + this._contractId, _nonce, [ transactions.functionCall( @@ -469,12 +511,12 @@ export default class Social { * @param {IStorageDepositOptions} options - the necessary options to deposit NEAR for covering storage for the account_id or the signer. * @returns {Promise} a promise that resolves to a transaction that is ready to be signed * and sent to the network. + * @public */ public async storageDeposit({ + account, blockHash, nonce, - publicKey, - signer, registrationOnly, accountId, deposit, @@ -499,16 +541,16 @@ export default class Social { let accessKeyView: AccessKeyView | null; if (!_blockHash) { - _blockHash = await this._latestBlockHash(signer.connection); + _blockHash = await this._latestBlockHash(); } if (!_nonce) { - accessKeyView = await this._accessKeyView(signer, publicKey); + accessKeyView = await this._accessKeyView(account); if (!accessKeyView) { throw new AccountNotFoundError( - signer.accountId, - `failed to get nonce for access key for "${signer.accountId}" with public key "${publicKey.toString()}"` + account.accountID, + `failed to get nonce for access key for "${account.accountID}" with public key "${account.publicKey.toString()}"` ); } @@ -516,9 +558,9 @@ export default class Social { } return transactions.createTransaction( - signer.accountId, - utils.PublicKey.fromString(publicKey.toString()), - this.contractId, + account.accountID, + utils.PublicKey.fromString(account.publicKey.toString()), + this._contractId, _nonce, actions, utils.serialize.base_decode(_blockHash) @@ -530,13 +572,13 @@ export default class Social { * @param {IStorageWithdrawOptions} options - define the amount to be withdrawn. * @returns {Promise} a promise that resolves to a transaction that is ready to be signed * and sent to the network. + * @public */ public async storageWithdraw({ + account, blockHash, amount, nonce, - publicKey, - signer, }: IStorageWithdrawOptions): Promise { const actions: transactions.Action[] = []; @@ -557,16 +599,16 @@ export default class Social { let accessKeyView: AccessKeyView | null; if (!_blockHash) { - _blockHash = await this._latestBlockHash(signer.connection); + _blockHash = await this._latestBlockHash(); } if (!_nonce) { - accessKeyView = await this._accessKeyView(signer, publicKey); + accessKeyView = await this._accessKeyView(account); if (!accessKeyView) { throw new AccountNotFoundError( - signer.accountId, - `failed to get nonce for access key for "${signer.accountId}" with public key "${publicKey.toString()}"` + account.accountID, + `failed to get nonce for access key for "${account.accountID}" with public key "${account.publicKey.toString()}"` ); } @@ -574,19 +616,12 @@ export default class Social { } return transactions.createTransaction( - signer.accountId, - utils.PublicKey.fromString(publicKey.toString()), - this.contractId, + account.accountID, + utils.PublicKey.fromString(account.publicKey.toString()), + this._contractId, _nonce, actions, 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/enums/ErrorCodeEnum.ts b/src/enums/ErrorCodeEnum.ts index 99075a6..04fabb5 100644 --- a/src/enums/ErrorCodeEnum.ts +++ b/src/enums/ErrorCodeEnum.ts @@ -5,6 +5,9 @@ enum ErrorCodeEnum { // keys KeyNotAllowedError = 3000, + + // network + UnknownNetworkError = 4000, } export default ErrorCodeEnum; diff --git a/src/enums/NetworkIDEnum.ts b/src/enums/NetworkIDEnum.ts new file mode 100644 index 0000000..99cc2ad --- /dev/null +++ b/src/enums/NetworkIDEnum.ts @@ -0,0 +1,8 @@ +enum NetworkIDEnum { + Betanet = 'betanet', + Localnet = 'localnet', + Mainnet = 'mainnet', + Testnet = 'testnet', +} + +export default NetworkIDEnum; diff --git a/src/enums/index.ts b/src/enums/index.ts index dc3b207..3154a17 100644 --- a/src/enums/index.ts +++ b/src/enums/index.ts @@ -1,3 +1,4 @@ export { default as ChangeMethodEnum } from './ChangeMethodEnum'; export { default as ErrorCodeEnum } from './ErrorCodeEnum'; +export { default as NetworkIDEnum } from './NetworkIDEnum'; export { default as ViewMethodEnum } from './ViewMethodEnum'; diff --git a/src/errors/UnknownNetworkError.ts b/src/errors/UnknownNetworkError.ts new file mode 100644 index 0000000..c2ebf05 --- /dev/null +++ b/src/errors/UnknownNetworkError.ts @@ -0,0 +1,17 @@ +// enums +import { ErrorCodeEnum } from '@app/enums'; + +// errors +import BaseError from './BaseError'; + +export default class UnknownNetworkError extends BaseError { + public readonly networkID: string; + public readonly code = ErrorCodeEnum.UnknownNetworkError; + public readonly name: string = 'UnknownNetworkError'; + + constructor(networkID: string, message?: string) { + super(message || `network ID "${networkID}" not known`); + + this.networkID = networkID; + } +} diff --git a/src/errors/index.ts b/src/errors/index.ts index 79f5064..cac0fdd 100644 --- a/src/errors/index.ts +++ b/src/errors/index.ts @@ -2,3 +2,4 @@ export { default as AccountNotFoundError } from './AccountNotFoundError'; export { default as BaseError } from './BaseError'; export { default as InvalidAccountIdError } from './InvalidAccountIdError'; export { default as KeyNotAllowedError } from './KeyNotAllowedError'; +export { default as UnknownNetworkError } from './UnknownNetworkError'; diff --git a/src/types/IAccount.ts b/src/types/IAccount.ts new file mode 100644 index 0000000..3d58d2d --- /dev/null +++ b/src/types/IAccount.ts @@ -0,0 +1,8 @@ +import { utils } from 'near-api-js'; + +interface IAccount { + accountID: string; + publicKey: string | utils.PublicKey; +} + +export default IAccount; diff --git a/src/types/IDefaultChangeOptions.ts b/src/types/IDefaultChangeOptions.ts index 14acc85..363e3e2 100644 --- a/src/types/IDefaultChangeOptions.ts +++ b/src/types/IDefaultChangeOptions.ts @@ -1,12 +1,10 @@ -import { utils } from 'near-api-js'; - // types -import type IDefaultOptions from './IDefaultOptions'; +import type IAccount from './IAccount'; -interface IDefaultChangeOptions extends IDefaultOptions { +interface IDefaultChangeOptions { + account: IAccount; blockHash?: string; nonce?: bigint; - publicKey: utils.PublicKey | string; } export default IDefaultChangeOptions; diff --git a/src/types/IDefaultOptions.ts b/src/types/IDefaultOptions.ts deleted file mode 100644 index ce7166e..0000000 --- a/src/types/IDefaultOptions.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { Account } from 'near-api-js'; - -interface IDefaultOptions { - signer: Account; -} - -export default IDefaultOptions; diff --git a/src/types/IDefaultViewOptions.ts b/src/types/IDefaultViewOptions.ts deleted file mode 100644 index 371c556..0000000 --- a/src/types/IDefaultViewOptions.ts +++ /dev/null @@ -1,5 +0,0 @@ -interface IDefaultViewOptions { - rpcURL: string; -} - -export default IDefaultViewOptions; diff --git a/src/types/IGetOptions.ts b/src/types/IGetOptions.ts index 4c90399..cda5139 100644 --- a/src/types/IGetOptions.ts +++ b/src/types/IGetOptions.ts @@ -1,7 +1,4 @@ -// types -import type IDefaultViewOptions from './IDefaultViewOptions'; - -interface IGetOptions extends IDefaultViewOptions { +interface IGetOptions { keys: string[]; returnDeleted?: boolean; withBlockHeight?: boolean; diff --git a/src/types/IGetVersionOptions.ts b/src/types/IGetVersionOptions.ts deleted file mode 100644 index 0eeb5ae..0000000 --- a/src/types/IGetVersionOptions.ts +++ /dev/null @@ -1,5 +0,0 @@ -import type IDefaultViewOptions from './IDefaultViewOptions'; - -type IGetVersionOptions = IDefaultViewOptions; - -export default IGetVersionOptions; diff --git a/src/types/IIsWritePermissionGrantedWithAccountIdOptions.ts b/src/types/IIsWritePermissionGrantedWithAccountIdOptions.ts index f1dafbe..7894366 100644 --- a/src/types/IIsWritePermissionGrantedWithAccountIdOptions.ts +++ b/src/types/IIsWritePermissionGrantedWithAccountIdOptions.ts @@ -1,11 +1,8 @@ -// types -import type IDefaultViewOptions from './IDefaultViewOptions'; - /** * @property {string} granteeAccountId - the account ID to check if it has write permissions for a key. * @property {string} key - the key to check if the grantee has write permission. */ -interface IIsWritePermissionGrantedOptions extends IDefaultViewOptions { +interface IIsWritePermissionGrantedOptions { granteeAccountId: string; key: string; } diff --git a/src/types/IIsWritePermissionGrantedWithPublicKeyOptions.ts b/src/types/IIsWritePermissionGrantedWithPublicKeyOptions.ts index a9d0dd6..390f026 100644 --- a/src/types/IIsWritePermissionGrantedWithPublicKeyOptions.ts +++ b/src/types/IIsWritePermissionGrantedWithPublicKeyOptions.ts @@ -1,15 +1,11 @@ import { utils } from 'near-api-js'; -// types -import type IDefaultViewOptions from './IDefaultViewOptions'; - /** * @property {utils.PublicKey | string} granteePublicKey - the public key the account to check if it has write * permissions for a key. * @property {string} key - the key to check if the grantee has write permission. */ -interface IIsWritePermissionGrantedWithPublicKeyOptions - extends IDefaultViewOptions { +interface IIsWritePermissionGrantedWithPublicKeyOptions { granteePublicKey: utils.PublicKey | string; key: string; } diff --git a/src/types/INewSocialOptions.ts b/src/types/INewSocialOptions.ts index a64ecb0..6de596e 100644 --- a/src/types/INewSocialOptions.ts +++ b/src/types/INewSocialOptions.ts @@ -1,5 +1,9 @@ +// types +import type IRPCOptions from './IRPCOptions'; + interface INewSocialOptions { contractId?: string; + network?: string | IRPCOptions; } export default INewSocialOptions; diff --git a/src/types/IRPCOptions.ts b/src/types/IRPCOptions.ts new file mode 100644 index 0000000..8588448 --- /dev/null +++ b/src/types/IRPCOptions.ts @@ -0,0 +1,6 @@ +interface IRPCOptions { + apiKey?: string; + url: string; +} + +export default IRPCOptions; diff --git a/src/types/IStorageBalanceOfOptions.ts b/src/types/IStorageBalanceOfOptions.ts deleted file mode 100644 index 366c822..0000000 --- a/src/types/IStorageBalanceOfOptions.ts +++ /dev/null @@ -1,8 +0,0 @@ -// types -import type IDefaultViewOptions from './IDefaultViewOptions'; - -interface IStorageBalanceOfOptions extends IDefaultViewOptions { - accountId: string; -} - -export default IStorageBalanceOfOptions; diff --git a/src/types/index.ts b/src/types/index.ts index 06cb7f6..38ba774 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,14 +1,13 @@ +export type { default as IAccount } from './IAccount'; export type { default as IDefaultChangeOptions } from './IDefaultChangeOptions'; -export type { default as IDefaultOptions } from './IDefaultOptions'; -export type { default as IDefaultViewOptions } from './IDefaultViewOptions'; export type { default as IGetOptions } from './IGetOptions'; export type { default as NetworkIds } from './NetworkIds'; export type { default as IGrantWritePermissionWithAccountIdOptions } from './IGrantWritePermissionWithAccountIdOptions'; export type { default as IGrantWritePermissionWithPublicKeyOptions } from './IGrantWritePermissionWithPublicKeyOptions'; export type { default as IIsWritePermissionGrantedWithAccountIdOptions } from './IIsWritePermissionGrantedWithAccountIdOptions'; export type { default as IIsWritePermissionGrantedWithPublicKeyOptions } from './IIsWritePermissionGrantedWithPublicKeyOptions'; -export type { default as IGetVersionOptions } from './IGetVersionOptions'; export type { default as INewSocialOptions } from './INewSocialOptions'; +export type { default as IRPCOptions } from './IRPCOptions'; export type { default as ISetOptions } from './ISetOptions'; export type { default as IStorageDepositOptions } from './IStorageDepositOptions'; export type { default as IStorageWithdrawOptions } from './IStorageWithdrawOptions'; @@ -25,4 +24,3 @@ export type { default as ISocialDBContractStorageBalanceOfArgs } from './ISocial export type { default as ISocialDBContractStorageDepositArgs } from './ISocialDBContractStorageDepositArgs'; export type { default as ISocialDBContractStorageWithdrawArgs } from './ISocialDBContractStorageWithdrawArgs'; export type { default as ISocialDBContractStorageTracker } from './ISocialDBContractStorageTracker'; -export type { default as IStorageBalanceOfOptions } from './IStorageBalanceOfOptions'; diff --git a/src/utils/rpcQueries/viewAccessKeyList/index.ts b/src/utils/rpcQueries/viewAccessKeyList/index.ts new file mode 100644 index 0000000..bbdb66f --- /dev/null +++ b/src/utils/rpcQueries/viewAccessKeyList/index.ts @@ -0,0 +1,2 @@ +export { default } from './viewAccessKeyList'; +export * from './types'; diff --git a/src/utils/rpcQueries/viewAccessKeyList/types/IAccessKeyInfoViewRaw.ts b/src/utils/rpcQueries/viewAccessKeyList/types/IAccessKeyInfoViewRaw.ts new file mode 100644 index 0000000..699be14 --- /dev/null +++ b/src/utils/rpcQueries/viewAccessKeyList/types/IAccessKeyInfoViewRaw.ts @@ -0,0 +1,8 @@ +import type { AccessKeyViewRaw } from '@near-js/types'; + +interface IAccessKeyInfoViewRaw { + access_key: AccessKeyViewRaw; + public_key: string; +} + +export default IAccessKeyInfoViewRaw; diff --git a/src/utils/rpcQueries/viewAccessKeyList/types/IOptions.ts b/src/utils/rpcQueries/viewAccessKeyList/types/IOptions.ts new file mode 100644 index 0000000..9d255e5 --- /dev/null +++ b/src/utils/rpcQueries/viewAccessKeyList/types/IOptions.ts @@ -0,0 +1,8 @@ +import { providers } from 'near-api-js'; + +interface IOptions { + accountID: string; + provider: providers.JsonRpcProvider; +} + +export default IOptions; diff --git a/src/utils/rpcQueries/viewAccessKeyList/types/IResponse.ts b/src/utils/rpcQueries/viewAccessKeyList/types/IResponse.ts new file mode 100644 index 0000000..3d8db6e --- /dev/null +++ b/src/utils/rpcQueries/viewAccessKeyList/types/IResponse.ts @@ -0,0 +1,10 @@ +import type { QueryResponseKind } from '@near-js/types'; + +// types +import type IAccessKeyInfoViewRaw from './IAccessKeyInfoViewRaw'; + +interface IResponse extends QueryResponseKind { + keys: IAccessKeyInfoViewRaw[]; +} + +export default IResponse; diff --git a/src/utils/rpcQueries/viewAccessKeyList/types/index.ts b/src/utils/rpcQueries/viewAccessKeyList/types/index.ts new file mode 100644 index 0000000..91119e0 --- /dev/null +++ b/src/utils/rpcQueries/viewAccessKeyList/types/index.ts @@ -0,0 +1,3 @@ +export type { default as IAccessKeyInfoViewRaw } from './IAccessKeyInfoViewRaw'; +export type { default as IOptions } from './IOptions'; +export type { default as IResponse } from './IResponse'; diff --git a/src/utils/rpcQueries/viewAccessKeyList/viewAccessKeyList.ts b/src/utils/rpcQueries/viewAccessKeyList/viewAccessKeyList.ts new file mode 100644 index 0000000..e95f629 --- /dev/null +++ b/src/utils/rpcQueries/viewAccessKeyList/viewAccessKeyList.ts @@ -0,0 +1,29 @@ +import type { AccessKeyInfoView } from '@near-js/types'; + +// types +import type { IOptions, IResponse } from './types'; + +/** + * Convenience function to get an account's access keys details. + * @param {IOptions} options - the account ID and a provider to direct to which RPC to query. + * @returns {Promise} a promise that resolves to the account's access keys details. + */ +export default async function viewAccessKeyList({ + accountID, + provider, +}: IOptions): Promise { + const response = await provider.query({ + account_id: accountID, + finality: 'optimistic', + request_type: 'view_access_key_list', + }); + + // convert the nonces into bigint + return response.keys.map(({ access_key, public_key }) => ({ + public_key, + access_key: { + ...access_key, + nonce: BigInt(access_key.nonce), + }, + })); +} diff --git a/src/utils/rpcQueries/index.ts b/src/utils/rpcQueries/viewFunction/index.ts similarity index 100% rename from src/utils/rpcQueries/index.ts rename to src/utils/rpcQueries/viewFunction/index.ts diff --git a/src/utils/rpcQueries/types/IOptions.ts b/src/utils/rpcQueries/viewFunction/types/IOptions.ts similarity index 56% rename from src/utils/rpcQueries/types/IOptions.ts rename to src/utils/rpcQueries/viewFunction/types/IOptions.ts index 1b0e354..f2e0e67 100644 --- a/src/utils/rpcQueries/types/IOptions.ts +++ b/src/utils/rpcQueries/viewFunction/types/IOptions.ts @@ -1,8 +1,10 @@ +import { providers } from 'near-api-js'; + interface IOptions { + args?: unknown; contractId: string; method: string; - rpcURL?: string; - args?: unknown; + provider: providers.JsonRpcProvider; } export default IOptions; diff --git a/src/utils/rpcQueries/types/index.ts b/src/utils/rpcQueries/viewFunction/types/index.ts similarity index 100% rename from src/utils/rpcQueries/types/index.ts rename to src/utils/rpcQueries/viewFunction/types/index.ts diff --git a/src/utils/rpcQueries/viewFunction.test.ts b/src/utils/rpcQueries/viewFunction/viewFunction.test.ts similarity index 67% rename from src/utils/rpcQueries/viewFunction.test.ts rename to src/utils/rpcQueries/viewFunction/viewFunction.test.ts index cac2f2f..ebe3bae 100644 --- a/src/utils/rpcQueries/viewFunction.test.ts +++ b/src/utils/rpcQueries/viewFunction/viewFunction.test.ts @@ -1,4 +1,5 @@ import { providers } from 'near-api-js'; +import type { IOptions } from './types'; import viewFunction from './viewFunction'; // Adjust the import path as needed // Mock the near-api-js providers @@ -11,6 +12,7 @@ jest.mock('near-api-js', () => ({ })); describe('viewFunction', () => { + let defaultOptions: IOptions; let mockQuery: jest.Mock; beforeEach(() => { @@ -18,6 +20,14 @@ describe('viewFunction', () => { (providers.JsonRpcProvider as jest.Mock).mockImplementation(() => ({ query: mockQuery, })); + + defaultOptions = { + contractId: 'test.near', + method: 'get_value', + provider: new providers.JsonRpcProvider({ + url: 'https://a.query.to.nowhere', + }), + }; }); it('should call the provider with correct parameters and return parsed result', async () => { @@ -26,17 +36,11 @@ describe('viewFunction', () => { }; mockQuery.mockResolvedValue(mockResult); - const options = { - contractId: 'test.near', - method: 'get_value', + const result = await viewFunction({ + ...defaultOptions, args: { key: 'someKey' }, - }; - - const result = await viewFunction(options); - - expect(providers.JsonRpcProvider).toHaveBeenCalledWith({ - url: 'https://rpc.mainnet.near.org', }); + expect(mockQuery).toHaveBeenCalledWith({ request_type: 'call_function', account_id: 'test.near', @@ -49,35 +53,12 @@ describe('viewFunction', () => { expect(result).toEqual({ value: 'test' }); }); - it('should use custom RPC URL if provided', async () => { - mockQuery.mockResolvedValue({ - result: Buffer.from('{}').toString('base64'), - }); - - const options = { - contractId: 'test.near', - method: 'get_value', - rpcURL: 'https://custom-rpc.near.org', - }; - - await viewFunction(options); - - expect(providers.JsonRpcProvider).toHaveBeenCalledWith({ - url: 'https://custom-rpc.near.org', - }); - }); - it('should handle empty args', async () => { mockQuery.mockResolvedValue({ result: Buffer.from('{}').toString('base64'), }); - const options = { - contractId: 'test.near', - method: 'get_value', - }; - - await viewFunction(options); + await viewFunction(defaultOptions); expect(mockQuery).toHaveBeenCalledWith( expect.objectContaining({ diff --git a/src/utils/rpcQueries/viewFunction.ts b/src/utils/rpcQueries/viewFunction/viewFunction.ts similarity index 87% rename from src/utils/rpcQueries/viewFunction.ts rename to src/utils/rpcQueries/viewFunction/viewFunction.ts index 1e01f74..d919e7a 100644 --- a/src/utils/rpcQueries/viewFunction.ts +++ b/src/utils/rpcQueries/viewFunction/viewFunction.ts @@ -1,4 +1,3 @@ -import { providers } from 'near-api-js'; import { printTxOutcomeLogs } from '@near-js/utils'; // types @@ -26,14 +25,11 @@ function base64Encode(str: string): string { } export default async function viewFunction({ + args = {}, contractId, method, - rpcURL, - args = {}, + provider, }: IOptions): Promise { - const url = rpcURL || `https://rpc.mainnet.near.org`; - const provider = new providers.JsonRpcProvider({ url }); - const res = await provider.query({ request_type: 'call_function', account_id: contractId, diff --git a/src/utils/rpcURLFromNetworkID/index.ts b/src/utils/rpcURLFromNetworkID/index.ts new file mode 100644 index 0000000..c220a3d --- /dev/null +++ b/src/utils/rpcURLFromNetworkID/index.ts @@ -0,0 +1 @@ +export { default } from './rpcURLFromNetworkID'; diff --git a/src/utils/rpcURLFromNetworkID/rpcURLFromNetworkID.ts b/src/utils/rpcURLFromNetworkID/rpcURLFromNetworkID.ts new file mode 100644 index 0000000..bc88bc9 --- /dev/null +++ b/src/utils/rpcURLFromNetworkID/rpcURLFromNetworkID.ts @@ -0,0 +1,25 @@ +// constants +import { networkRPCs } from '@app/constants'; + +// enums +import { NetworkIDEnum } from '@app/enums'; + +/** + * Convenience function that gets the RPC URL for a given network ID. If the network ID is unknown, null is returned. + * @param {string} networkID - a network ID. Should be one of betanet, localnet, mainnet or testnet. + * @returns {string | null} the RPC URL for a given network ID, or null if the network ID is unknown. + */ +export default function rpcURLFromNetworkID(networkID: string): string | null { + switch (networkID) { + case NetworkIDEnum.Betanet: + return networkRPCs.betanet; + case NetworkIDEnum.Localnet: + return networkRPCs.localnet; + case NetworkIDEnum.Mainnet: + return networkRPCs.mainnet; + case NetworkIDEnum.Testnet: + return networkRPCs.testnet; + default: + return null; + } +}