Skip to content
This repository was archived by the owner on Nov 10, 2025. It is now read-only.
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
381 changes: 381 additions & 0 deletions intents/dip-0002.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,381 @@
## Overview

> **NOTE:** Optional fields are marked as `(optional)`, otherwise it's required.

### Intent

To query existing intent by its ID, one can call `get_intent` with following arguments:

```json
{
"id": "<INTENT_ID>"
}
```

This method returns an intent with following structure:

```json
{
// Provided asset as an input.
"asset_in": <ASSET>,
// Desired asset as an output.
"asset_out": <ASSET>,
// Optional lockup period for `asset_in` when initiator cannot rollback
// the intent.
// NOTE: MUST come before `expiration`
"lockup_until": <DEADLINE>, // (optional)
// Deadline to execute the swap.
// NOTE: intent can still be rollbacked at any time unless
// `lockup_until` is specified
"expiration": <DEADLINE>,
// Current status of the intent
"status": "available", // other possible values: "executed", "rolled_back"
"referral": "referral.near", // optional
// Lost asset in case the intent has already been executed/rollbacked
// but we failed to transfer an asset to recipient/initiator.
// This can happen due to recipient/initiator is not registered
// on the target asset contract or does not have enough storage
// deposited according to Storage Management standard (NEP-145).
// Anyone can call `lost_found(intent_id)` to retry the transfer.
"lost": <LOST_ASSET>, // (optional)
// indicates whether the intent is in progress of execution some Action
"locked": true, // (optional)
}
```

Example:

```json
{
"asset_in": {
"type": "nep141",
"token": "ft1.test.near",
"amount": "500",
"account": "user1.test.near"
},
"asset_out": {
"type": "nep141",
"token": "ft2.test.near",
"amount": "1000",
"account": "user1.test.near"
},
"expiration": {
"timestamp": 1721743851
},
"status": "available"
}
```

### Asset

To [create](#create-action) or [execute](#execute-action) an intent, an asset must be transferred
to the intent shard and corresponding [action](#actions) must be attached.

```json
{
"type": "<ASSET_TYPE>"
// ... other type-specific fields
}
```

#### `native` Asset

To execute an [action](#actions) by sending native NEAR, one should send a transaction attaching NEAR as deposit
and call `native_on_transfer` with action serialized to JSON string passed to `msg` argument:

```json
{
"msg": "<JSON_ACTION>"
}
```

`native` asset is represented as follows:

```json
{
"type": "native",
"amount": "1000",
// sender in context of `asset_in`, recipient for `asset_out`
"account": "example.near",
}
```

#### [`nep141`](https://nomicon.io/Standards/Tokens/FungibleToken/Core) Asset

To execute an [action](#actions) by sending NEP-141 tokens, one should call `ft_transfer_call`
and attach the action serialized to JSON in `msg` parameter.

`nep141` asset is represented as follows:

```json
{
"type": "nep141",
"token": "dac17f958d2ee523a2206206994597c13d831ec7.factory.bridge.near",
"amount": "1000",
// sender in context of `asset_in`, recipient for `asset_out`
"account": "example.near",
}
```

#### [`nep171`](https://nomicon.io/Standards/Tokens/NonFungibleToken/Core) Asset

To execute an [action](#actions) by sending NEP-171 token, one should call `nft_transfer_call`
and attach the action serialized to JSON in `msg` parameter.

`nep171` asset is represented as follows:

```json
{
"type": "nep171",
"collection": "nft.herewallet.near",
"token_id": "10011",
// sender in context of `asset_in`, recipient for `asset_out`
"account": "example.near",
}
```

#### `cross_chain` Asset

To execute an [action](#actions) by sending cross-chain asset, one should call `cross_chain_on_transfer`
with following arguments:

```json
{
// universal cross-chain asset identifier
"asset": "<UNIVERSAL_ASSET_ID>",
"amount": "1000",
"msg": "<JSON_ACTION>" // ACTION is serialized to JSON string here
}
```

`cross_chain` asset is represented as follows:

```json
{
"type": "cross_chain",
// where to expect transfer notification from
"oracle": "oracle.near",
// universal cross-chain asset identifier
"asset": "eth:1:0xdAC17F958D2ee523a2206206994597C13D831ec7",
"amount": "1000",
// sender in context of `asset_in`, recipient for `asset_out`
"account": "0xF977814e90dA44bFA03b6295A0616a897441aceC",
}
```

Caller of `on_cross_chain_transfer` will be considered as an `oracle`.

While we don't have the whole infrastructure of light-clients implemented, a user can specify `"oracle": "solver.near"`,
so it will become a fully trusted setup where `solver.near` will be able to send these cross-chain transfer notifications
by himself.

##### Universal Cross-Chain Asset Identifier

Assets are identified using the following format: `<CHAIN_TYPE>:<CHAIN_ID>:<ASSET_ADDRESS>`.
Format of latter components depends on the precedent values. Here are few examples:

* EVM: `eth:{decimal chain_id}:{ "native" | "0x" .. <hex address> }`
* ETH (Ethereum Mainnet): `eth:1:native`
* USDT (Ethereum Mainnet): `eth:1:0xdAC17F958D2ee523a2206206994597C13D831ec7`
* USDC (Base mainnet): `eth:8453:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`
* TON: `ton:{decimal workchain_id}:{ "native" | <hex address> }`
* TON (TON basechain): `ton:0:native`
* USDT (TON basechain): `ton:0:b113a994b5024a16719f69139328eb759596c38a25f59028b146fecdc3621dfe`
* Solana: `solana:{ "mainnet" | "testnet" | "devnet" }:{ base58 address }`
* SOL (Solana mainnet): `solana:mainnet:native`
* USDT (Solana mainnet): `solana:mainnet:Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB`
* NEAR: `near:{ "mainnet" | "testnet" }:{ "native" | <account_id> }`
* NEAR (Near mainnet) : `near:mainnet:native`
* USDT (Near mainnet): `near:mainnet:dac17f958d2ee523a2206206994597c13d831ec7.factory.bridge.near`


### Actions

#### `create` Action

To create an intent, one should send an [asset](#asset) and attach `create` action.
Transferred asset will be considered as `asset_in`.

```json
{
"type": "create",
"id": "<INTENT_ID>",
"asset_out": <ASSET>,
"lockup_until": <DEADLINE>, // (optional)
"expiration": <DEADLINE>,
"referral": "referral.near", // (optional)
}
```

#### `execute` Action

To execute the intent, one should send an [asset](#asset) and attach `execute` action.
Transferred asset will be considered as `asset_out`.

```json5
{
"type": "execute",
"id": "<INTENT_ID>",
"proof": "<TX_HASH>", // (optional)
"recipient": <GENERIC_ACCOUNT>,
}
```

> **NOTE:** If exactly one of `asset_in` or `asset_out` fails due to

### Generic Account

#### `near` Account

```json
{
"type": "near",
"address": "example.near",
}
```

#### `cross_chain` Account
```json
{
"type": "cross_chain",
"address": "0xF977814e90dA44bFA03b6295A0616a897441aceC",
}
```

### Deadline

#### UNIX Timestamp

UNIX Timestamp in seconds

```json
{
"timestamp": 1721745168,
}
```

#### Block number

```json
{
"block_number": 124077326,
}
```


### Rollback

The initiator of the intent can rollback intent at any time unless `lockup_until` was specified on [creation](#create-action).
To rollback the intent, one should call `rollback_intent` and attach exactly 1 yⓃ for security purposes.
Arguments for `rollback_intent`:

```json
{
"id": "<INTENT_ID>"
}
```

The return value is `bool` indicating whether the `asset_in` was [lost](#lost-asset) during the rollback.

### Lost Assets

If an assets transfer fails, it is considered as "lost".
It can happen due to multiple reasons, including:
* No storage deposit for recipient on NEP141 token
* Insufficient gas

In case an asset transfer fails, [`lost` event](#lost-event) is emitted.
The transfer can then be retried by sending permission-less transaction calling `lost_found` method
with following arguments:
```json
{
"id": "<INTEND_ID>",
}
```

#### Lost Asset

```json
{
"direction": "asset_in", // or "asset_out"
// "recipient" is present only in case of "asset_in" direction,
// omitted otherwise
"recipient": <GENERIC_ACCOUNT>, // (optional)
}
```

### Events

#### `created` Event

Example:

```json
{
"standard": "dip2",
"version": "0.1.0",
"event": "created",
"data": {
"id": "872ab398-a27d-4673-9412-a4bf7cd2553e",
"asset_in": {
"type": "nep141",
"token": "ft1.test.near",
"amount": "500",
"account": "user1.test.near"
},
"asset_out": {
"type": "nep141",
"token": "ft2.test.near",
"amount": "1000",
"account": "user1.test.near"
},
"expiration": {
"timestamp": 1721743851
},
"status": "available"
}
}
```

#### `executed` Event

Example:

```json
{
"standard": "dip2",
"version": "0.1.0",
"event": "executed",
"data": "872ab398-a27d-4673-9412-a4bf7cd2553e", // intent ID
}
```

#### `rolled_back` Event

Example:

```json
{
"standard": "dip2",
"version": "0.1.0",
"event": "rolled_back",
"data": "872ab398-a27d-4673-9412-a4bf7cd2553e", // intent ID
}
```

#### `lost` Event

Example:

```json
{
"standard": "dip2",
"version": "0.1.0",
"event": "lost",
"data": {
"intent_id": "872ab398-a27d-4673-9412-a4bf7cd2553e",
// .. other <LOST_ASSET> fields
},
}
```