Integrating Contracts
To integrate NEAR to your frontend, you will leverage two tools:
Wallet Selector
: Enables the user to select their preferred NEAR wallet in your dApp.NEAR API JS
: A suite of tools to interact with the NEAR RPC.
Using those tools you will implement the following flow:
- Setup a wallet selector.
- Load the wallet selector on start-up.
- Ask the user to sign-in using a NEAR wallet.
- Call methods in the contract.
Naxiosโ
You can optionally use Naxios. A promise-based NEAR Contract and NEAR Wallet Client for browser.
Naxios was designed to facilitate the React / Next.js integration with NEAR Blockchain and avoid the boilerplate of setting up a wallet and contract.
Adding NEAR API JS and Wallet Selectorโ
In order to use near-api-js
and the wallet-selector
you will need to first add them to your project.
The wallet selector has multiple wallet packages to select from, see in their website.
npm install \
near-api-js \
@near-wallet-selector/core \
@near-wallet-selector/my-near-wallet \
@near-wallet-selector/ledger \
@near-wallet-selector/modal-ui
Create a Wallet Objectโ
In our examples, we implement a ./wallets/near.js
module, where we abstracted the wallet selector
into a Wallet
object to simplify using it.
To create a wallet, simply import the Wallet
object from the module and initialize it. This wallet
will later allow the user to call any contract in NEAR.
- ๐ Javascript
- _app.js
- near.js
Loading...
Loading...
Under the hood (check the near
tab) you can see that we are actually setting up the wallet selector, and asking it if the user logged-in already. During the setup, we pass a hook to the wallet selector, which will be called each time a user logs in or out.
Setting customs RPC endpoints
If you want to use a user-defined RPC endpoint with the Wallet Selector, you need to set up a network options object with the custom URLs. For example:
- ๐ Javascript
const CONTRACT_ADDRESS = process.env.CONTRACT_NAME;
const my_network = {
networkId: "my-custom-network",
nodeUrl: "https://rpc.custom-rpc.com",
helperUrl: "https://helper.custom-helper.com",
explorerUrl: "https://custom-explorer.com",
indexerUrl: "https://api.custom-indexer.com",
};
const wallet = new Wallet({ createAccessKeyFor: CONTRACT_ADDRESS, network: my_network });
You can find the entire Wallet Selector API reference here.
Function Call Keyโ
When instantiating the wallet you can choose if you want to create a FunctionCall Key.
If you create the key, your dApp will be able to automatically sign non-payable transactions for the user on the specified contract.
Calling View Methodsโ
Once the wallet is up we can start calling view methods, i.e. the methods that perform read-only operations.
Because of their read-only nature, view methods are free to call, and do not require the user to be logged in.
- ๐ Javascript
- index.js
- near.js
Loading...
Loading...
The snippet above shows how we call view methods in our examples. Switch to the near-wallet
tab to see under the hood: we are actually making a direct call to the RPC using near-api-js
.
View methods have by default 200 TGAS for execution
User Sign-In / Sign-Outโ
In order to interact with non-view methods it is necessary for the user to first sign in using a NEAR wallet.
Signing in is as simple as requesting the wallet
object to signIn
, the same simplicity applies to signing out.
- ๐ Javascript
- index.js
- near.js
Loading...
Loading...
When the user clicks the login button, they will be asked to select a wallet and use it to log in.
Function Call Keyโ
If you instantiated the Wallet
passing an account for the createAccessKeyFor
parameter, then the wallet will create a FunctionCall Key and store it in the web's local storage.
const wallet = new Wallet({
createAccessKeyFor: HelloNearContract,
networkId: NetworkId,
});
By default, such key enables to expend a maximum of 0.25โ
on GAS calling methods in the specified contract without prompting the user to sign them.
If, on the contrary, you do not create an access key, then the user will be asked to sign every single transaction (except calls to view methods
, since those are always free).
Please notice that this only applies to non-payable methods, if you attach money to any call the user will always be redirected to the wallet to confirm the transaction.
Calling Change Methodsโ
Once the user logs in they can start calling change methods. Programmatically, calling change methods is similar to calling view methods, only that now you can attach money to the call, and specify how much GAS you want to use.
- ๐ Javascript
- index.js
- near.js
Loading...
Loading...
Under the hood (see near-wallet
tab) we can see that we are actually asking the wallet to sign a FunctionCall transaction for us.
Remember that you can use the wallet
to call methods in any contract. If you did not ask for a function key to be created, the user will simply be prompted to confirm the transaction.
Wallet Redirectionโ
When calling a change call with attached deposit (or any change call if no function call key was created), then the user will be prompted to sign the transaction in the wallet.
If using a web wallet, as opposed to an extension, the user will be redirected to the wallet's website to sign the transaction.
After accepting, the user will be brought back to your application, with the resulting transaction hash being passed as part of the URL (i.e. your-website.com/?transactionHashes=...
).
If the method invoked returned a result, you can use the transaction hash to retrieve the result from the network. You can fetch the transaction hash via:
const txHash = new URLSearchParams(window.location.search).get('transactionHashes');
Assuming you created the near
object as in the example above, then you query the result by utilizing:
- ๐ Javascript
Loading...
Sending Multiple Transactionsโ
The Wallet class also exposes a method that can be used to send multiple transactions.
- ๐ Javascript
Loading...
Transactions can either be sent as multiple separate transactions simultaneously or as a batch transaction made up of actions where if one of the actions fails, they are all reverted. An example of both can be seen here
Querying Account Balanceโ
By calling the getBalance
method the user can get the balance of the account that is currently logged in.
- ๐ Javascript
Loading...
Get Access Keysโ
The final method the Wallet class exposes is getAccessKeys
which is used to return an object of all the access keys on the account that is currently logged in.
- ๐ Javascript
Loading...
Handling Data Typesโ
When calling methods in a contract, or receiving results from them, you will need to correctly encode/decode parameters. For this, it is important to know how the contracts encode timestamps (u64) and money amounts (u128).
Timeโ
The block timestamp in a smart contract is encoded using nanoseconds (i.e. 19 digits: 1655373910837593990
). In contrast, Date.now()
from javascript returns a timestamp in milliseconds (i.e 13 digits: 1655373910837
). Make sure to convert between milliseconds and nanoseconds to properly handle time variables.
Moneyโ
Smart contracts speak in yocto NEAR, where 1โ = 10^24yocto, and the values are always encoded as strings
.
- Convert from NEAR to yocto before sending it to the contract using
near-api-js.utils.format.parseNearAmount(amount.toString())
. - Convert a response in yoctoNEAR to NEAR using
near-api-js.utils.format.formatNearAmount(amount)
If the contract returns a Balance
instead of a U128
, you will get a "scientific notation" number
instead of a string
(e.g. 10^6
instead of "1000000"
). In this case, you can convert the value to NEAR by doing:
function formatAmount(amount) {
let formatted = amount.toLocaleString('fullwide', { useGrouping: false })
formatted = utils.format.formatNearAmount(formatted)
return Math.floor(formatted * 100) / 100
}
Leveraging NEAR API JSโ
NEAR API JS does not limit itself to simply calling methods in a contract. In fact, you can use it to transform your web-app into a rich user experience. While we will not cover these topics in depth, it is important for you to know that with NEAR API JS you can also:
- Sign and verify messages: this is very useful to prove that a message was created by the user.
- Create batch transactions: this enables to link multiple actions (e.g. multiple function calls). If one of the transactions fails, then they are all reverted.
- Create accounts: deploy accounts for your users!
Check the cookbook to learn how to supercharge your web-app.