-
Notifications
You must be signed in to change notification settings - Fork 380
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Write up a step-by-step guide for interacting with NEAR Intents (#2479)
* feat: write up a step-by-step guide for interacting with NEAR Intents * Apply suggestions from code review --------- Co-authored-by: Damián Parrino <bucanero@users.noreply.github.com>
- Loading branch information
Showing
5 changed files
with
945 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
--- | ||
id: introduction | ||
title: Integrate with NEAR Intents | ||
sidebar_label: Introduction | ||
--- | ||
|
||
NEAR Intents is a powerful protocol designed to simplify and streamline interactions with multichain financial products. It enables users to define high-level financial operations without needing to manage the complexity of smart contract interactions across multiple blockchains. | ||
|
||
The protocol abstracts execution details, making it easier for developers | ||
and users to engage in decentralized finance (DeFi) operations seamlessly. | ||
For more in-depth details about the architecture behind NEAR Intents and | ||
the multichain bridge OmniBridge, visit the official | ||
[NEAR documentation](/chain-abstraction/intents/overview). | ||
|
||
## What You Will Learn | ||
|
||
In this tutorial, you will learn how to: | ||
|
||
- [Deposit tokens](1-deposit.mdx) from different chains (NEAR, EVM-compatible, Solana) | ||
- [Execute a swap](2-swap.mdx) using the NEAR Intents protocol | ||
- [Withdraw funds](3-withdraw.mdx) back to the destination chain if needed (NEAR, EVM-compatible, Solana) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,287 @@ | ||
--- | ||
id: deposit | ||
title: Deposit tokens | ||
sidebar_label: Deposit | ||
--- | ||
|
||
import Tabs from "@theme/Tabs"; | ||
import TabItem from "@theme/TabItem"; | ||
|
||
Depositing tokens is the first step in using NEAR Intents. Whether you are transferring assets from NEAR or an external blockchain, this process ensures your funds are accessible within the NEAR ecosystem. The deposit mechanism depends on whether the source chain is NEAR or another blockchain. | ||
|
||
Before making any deposits, it’s essential to check your current token balance. This ensures that your funds are properly accounted for after each transaction. | ||
|
||
## Retrieving Available Tokens | ||
|
||
To check your balance, you first need to obtain the correct `token_id` that corresponds to the asset you are querying. This information can be retrieved by calling the following endpoint: | ||
|
||
```sh | ||
https://api-mng-console.chaindefuser.com/api/tokens | ||
``` | ||
|
||
The request payload is empty. | ||
|
||
This will return a JSON response containing token information. An example response is: | ||
|
||
```json | ||
{ | ||
"tokens": [ | ||
{ | ||
"defuse_asset_id": "nep141:wrap.near", | ||
"decimals": 24, | ||
"blockchain": "near", | ||
"symbol": "wNEAR", | ||
"price": 3.36, | ||
"price_updated_at": "2025-02-15T12:06:00.106Z", | ||
"contract_address": "wrap.near" | ||
}, | ||
{ | ||
"defuse_asset_id": "nep141:eth.omft.near", | ||
"decimals": 18, | ||
"blockchain": "eth", | ||
"symbol": "ETH", | ||
"price": 2671.25, | ||
"price_updated_at": "2025-02-15T12:06:00.106Z" | ||
} | ||
] | ||
} | ||
``` | ||
|
||
Each token has a unique `defuse_asset_id`, which serves as the `token_id` required for querying balances. | ||
|
||
## Checking Balance on NEAR | ||
|
||
Once you have obtained the `defuse_asset_id` for the token, you can retrieve your balance by calling the `mt_batch_balance_of` view function on the `intents.near` contract. The request payload should be structured as follows: | ||
|
||
```json | ||
{ | ||
"account_id": "denbite.near", | ||
"token_ids": ["nep141:wrap.near", "nep141:eth.omft.near"] // this list may include as many tokens as you'd like to query balances of | ||
} | ||
``` | ||
|
||
In this example, `nep141:wrap.near` represents NEAR (as wNEAR FungibleToken) and `nep141:eth.omft.near` represents Ethereum | ||
|
||
<Tabs> | ||
<TabItem value="cli" label="Near CLI" default> | ||
|
||
```sh | ||
near contract call-function as-read-only intents.near mt_batch_balance_of json-args '{"account_id":"<your-account.near>","token_ids":["nep141:wrap.near", "nep141:eth.omft.near"]}' network-config mainnet now | ||
``` | ||
|
||
</TabItem> | ||
<TabItem value="typescript" label="TypeScript"> | ||
|
||
```ts | ||
import { JsonRpcProvider } from "near-api-js/lib/providers"; | ||
import { Connection, InMemorySigner } from "near-api-js"; | ||
import { InMemoryKeyStore } from "near-api-js/lib/key_stores"; | ||
import { viewFunction } from "@near-js/accounts/lib/utils"; | ||
|
||
const provider = new JsonRpcProvider({ | ||
url: "https://rpc.mainnet.near.org", | ||
}); | ||
|
||
// signer without key as we're only reading from contract | ||
const keyStore = new InMemoryKeyStore(); | ||
const signer = new InMemorySigner(keyStore); | ||
|
||
const connection = new Connection("mainnet", provider, signer, ""); | ||
|
||
const args = { | ||
account_id: "<your-account.near>", | ||
token_ids: ["nep141:wrap.near", "nep141:eth.omft.near"], | ||
}; | ||
|
||
const balances = await viewFunction(connection, { | ||
contractId: "intents.near", | ||
methodName: "mt_batch_balance_of", | ||
args: args, | ||
}); | ||
|
||
console.log(balances); | ||
``` | ||
|
||
</TabItem> | ||
</Tabs> | ||
|
||
For the first interaction with NEAR Intents, the response will look like the following, meaning we're empty on NEAR and ETH: | ||
|
||
```json | ||
["0", "0"] | ||
``` | ||
|
||
## Depositing from NEAR | ||
|
||
If the source chain is NEAR, deposits are made by directly transferring tokens using the standard Fungible Token contract. | ||
For example, to deposit NEAR tokens, you must send a signed transaction to `wrap.near` (wNEAR) with the following payload | ||
|
||
```json | ||
{ | ||
"receiver_id": "intents.near", | ||
"amount": "50000000000000000000000", // equivalent of 0.05 NEAR as yoctoNear | ||
"msg": "" | ||
} | ||
``` | ||
|
||
<Tabs> | ||
<TabItem value="cli" label="Near CLI" default> | ||
|
||
```sh | ||
near transaction construct-transaction <your-account.near> wrap.near add-action function-call near_deposit json-args {} prepaid-gas '30.0 Tgas' attached-deposit '0.05 NEAR' add-action function-call ft_transfer_call json-args '{ | ||
"receiver_id": "intents.near", | ||
"amount": "50000000000000000000000", | ||
"msg": "" | ||
}' prepaid-gas '50.0 Tgas' attached-deposit '1 yoctoNEAR' skip network-config mainnet sign-with-legacy-keychain send | ||
``` | ||
|
||
</TabItem> | ||
<TabItem value="typescript" label="TypeScript"> | ||
|
||
```ts | ||
import { JsonRpcProvider } from "near-api-js/lib/providers"; | ||
import { Account, Connection, InMemorySigner, KeyPair } from "near-api-js"; | ||
import { InMemoryKeyStore } from "near-api-js/lib/key_stores"; | ||
import { Action, functionCall } from "near-api-js/lib/transaction"; | ||
|
||
const provider = new JsonRpcProvider({ | ||
url: "https://rpc.mainnet.near.org", | ||
}); | ||
|
||
const privateKey = | ||
"ed25519:1bF8wCjpstE3j5kMS7RASEWz2gw4xj7mTPFsUAUxMC5gqMPKWaTsG2883wW5F5dZ1KUJjmGyaCMw2ym1yRtRSXyn"; | ||
const accountId = "<your-account.near>"; | ||
|
||
const keyPair = KeyPair.fromString(privateKey); | ||
const signer = await InMemorySigner.fromKeyPair("mainnet", accountId, keyPair); | ||
|
||
const connection = new Connection("mainnet", provider, signer, ""); | ||
const account = new Account(connection, accountId); | ||
|
||
const actions: Action[] = [ | ||
functionCall( | ||
"near_deposit", | ||
{}, | ||
BigInt(30_000_000_000_000), // 30 TGas | ||
BigInt(50_000_000_000_000_000_000_000) // 0.05 NEAR | ||
), | ||
functionCall( | ||
"ft_transfer_call", | ||
{ | ||
receiver_id: "intents.near", | ||
amount: "50000000000000000000000", // equivalent of 0.05 NEAR as yoctoNear | ||
msg: "", | ||
}, | ||
BigInt(50_000_000_000_000), // 50 TGas | ||
BigInt(1) // 1 yoctoNear | ||
), | ||
]; | ||
const result = await account.signAndSendTransaction({ | ||
receiverId: "wrap.near", // wNEAR contract | ||
actions: actions, | ||
}); | ||
|
||
console.log(result); | ||
``` | ||
|
||
</TabItem> | ||
</Tabs> | ||
|
||
## Depositing from Different Chains | ||
|
||
Deposits and withdrawals from other chains into NEAR FTs are handled by the bridging service - [Omni-Bridge](../../chain-abstraction/omnibridge/overview.md). | ||
|
||
Since deposits involve the OmniBridge, ensure that the asset you are transferring is supported. To retrieve the full list of supported assets, use the following endpoint: | ||
|
||
```sh | ||
POST https://bridge.chaindefuser.com/rpc | ||
``` | ||
|
||
With the following request JSON payload: | ||
|
||
```json | ||
{ | ||
"id": "dontcare", | ||
"jsonrpc": "2.0", | ||
"method": "supported_tokens", | ||
"params": [ | ||
{ | ||
"chains": [ | ||
"eth:1", // Ethereum Mainnet | ||
"eth:42161", // Arbitrum Mainnet | ||
"solana:mainnet" // Solana Mainnet | ||
] | ||
} | ||
] | ||
} | ||
``` | ||
|
||
This will return a JSON response containing a list of supported tokens. An example response is: | ||
|
||
```json | ||
{ | ||
"id": "dontcare", | ||
"jsonrpc": "2.0", | ||
"result": { | ||
"tokens": [ | ||
{ | ||
"defuse_asset_identifier": "eth:1:native", // CHAIN_TYPE:CHAIN_ID:ADDRESS | ||
"near_token_id": "eth.omft.near", | ||
"decimals": 18, | ||
"asset_name": "ETH", | ||
"min_deposit_amount": "1", | ||
"min_withdrawal_amount": "400000000000000", | ||
"withdrawal_fee": "0" | ||
}, | ||
... | ||
] | ||
} | ||
} | ||
``` | ||
|
||
If the desired asset is in the list, then retrieve a deposit address on the source chain using: | ||
|
||
```sh | ||
POST https://bridge.chaindefuser.com/rpc | ||
``` | ||
|
||
With the following request payload: | ||
|
||
```json | ||
{ | ||
"jsonrpc": "2.0", | ||
"id": "dontcare", | ||
"method": "deposit_address", | ||
"params": [ | ||
{ | ||
"account_id": "<your-account.near>", | ||
"chain": "eth:1" // CHAIN_TYPE:CHAIN_ID | ||
} | ||
] | ||
} | ||
``` | ||
|
||
This will return a JSON response containing an address on the source chain (in this example it's Ethereum Mainnet). An example response is: | ||
|
||
```json | ||
{ | ||
"jsonrpc": "2.0", | ||
"id": "dontcare", | ||
"result": { | ||
"address": "0xF6972DF0809aE0c8AD0bd468d385eE417561F1cB", | ||
"chain": "eth:1" // CHAIN_TYPE:CHAIN_ID | ||
} | ||
} | ||
``` | ||
|
||
Once you receive the deposit address, send the desired asset from the source chain using your wallet (e.g., MetaMask for Ethereum, Phantom for Solana, etc.). | ||
|
||
:::warning | ||
|
||
Keep in mind that the received `address` is unique for each `account_id`. **DO NOT** transfer any tokens to the address shown in this example, as you will lose those funds. | ||
|
||
::: | ||
|
||
After successfully depositing your tokens, query your balance again using the same method described above to confirm the deposit was successful. This time, the response should return non-zero values. | ||
|
||
The next step is to swap them for another asset. Continue to [the next chapter](2-swap.mdx) to learn how. |
Oops, something went wrong.