From 84d949e9050eba48a0b3f129869462576bc9af0c Mon Sep 17 00:00:00 2001 From: De Fuse Date: Tue, 23 Jul 2024 18:54:14 +0300 Subject: [PATCH 1/4] draft: dip-0002 --- intents/dip-0002.md | 349 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 349 insertions(+) create mode 100644 intents/dip-0002.md diff --git a/intents/dip-0002.md b/intents/dip-0002.md new file mode 100644 index 0000000..e82a250 --- /dev/null +++ b/intents/dip-0002.md @@ -0,0 +1,349 @@ +## Overview + +> **NOTE:** Optional fields are marked as `(optional)`, otherwise it's required. + +### Intent + +To query existing intent by its ID, one can call `get_swap_intent` with following arguments: + +```json +{ + "id": "" +} +``` + +This method returns an intent with following structure: + +```json +``` + +Example: + +```json +{ + // Provided asset as an input. + "asset_in": , + // Desired asset as an output. + "asset_out": , + // Optional lockup period for `asset_in` when initiator cannot rollback + // the intent. + // NOTE: MUST come before `expiration` + "lockup_until": , // (optional) + // Deadline to execute the swap. + // NOTE: intent can still be rollbacked at any time unless + // `lockup_until` is specified + "expiration": , + // 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": , // (optional) + // indicates whether the intent is in progress of execution some Action + "locked": true, // (optional) +} +``` + +### 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": "" + // ... 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_action` with following arguments: + +```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 `on_cross_chain_transfer` +with following arguments: + +```json +{ + // universal cross-chain asset identifier + "asset": "", + "amount": "1000", + "msg": "" // 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: `::`. +Format of latter components depends on the precedent values. Here are few examples: + +* EVM: `eth:{decimal chain_id}:{ "native" | "0x" .. }` + * ETH (Ethereum Mainnet): `eth:1:native` + * USDT (Ethereum Mainnet): `eth:1:0xdAC17F958D2ee523a2206206994597C13D831ec7` + * USDC (Base mainnet): `eth:8453:0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` +* TON: `ton:{decimal workchain_id}:{ "native" | }` + * 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" | }` + * 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": "", + "asset_out": , + "lockup_until": , // (optional) + "expiration": , + "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": "", + "proof": "", // (optional) + "recipient": , +} +``` + +### 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, +} +``` + + + + +### 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": "", +} +``` + +#### Lost Asset + +```json +{ + "direction": "asset_in", // or "asset_out" + // "recipient" is present only in case of "asset_in" direction, + // omitted otherwise + "recipient": , // (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", + "asset": { + "token": "ft1.test.near", + "amount": "500" + }, + "account": "user1.test.near" + }, + "asset_out": { + "type": "nep141", + "asset": { + "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 + +```json +{ + "standard": "dip2", + "version": "0.1.0", + "event": "rolled_back", + "data": "872ab398-a27d-4673-9412-a4bf7cd2553e", // intent ID +} +``` + +#### `lost` Event + +```json +{ + "standard": "dip2", + "version": "0.1.0", + "event": "lost", + "data": { + "intent_id": "872ab398-a27d-4673-9412-a4bf7cd2553e", + // .. other fields + }, +} +``` + From d08c0ae18ffcfd3bbce93162abf311632e07d3d8 Mon Sep 17 00:00:00 2001 From: De Fuse Date: Tue, 23 Jul 2024 19:20:49 +0300 Subject: [PATCH 2/4] typo --- intents/dip-0002.md | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/intents/dip-0002.md b/intents/dip-0002.md index e82a250..fc91317 100644 --- a/intents/dip-0002.md +++ b/intents/dip-0002.md @@ -14,11 +14,6 @@ To query existing intent by its ID, one can call `get_swap_intent` with followin This method returns an intent with following structure: -```json -``` - -Example: - ```json { // Provided asset as an input. @@ -48,6 +43,33 @@ Example: } ``` +Example: + +```json +{ + "asset_in": { + "type": "nep141", + "asset": { + "token": "ft1.test.near", + "amount": "500" + }, + "account": "user1.test.near" + }, + "asset_out": { + "type": "nep141", + "asset": { + "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 From e20d4fe9e5e2b93f3fd5c269c9143a0817c09540 Mon Sep 17 00:00:00 2001 From: De Fuse Date: Fri, 26 Jul 2024 10:59:42 +0300 Subject: [PATCH 3/4] fix: naming, add section for rollback_intent() --- intents/dip-0002.md | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/intents/dip-0002.md b/intents/dip-0002.md index fc91317..ce62c89 100644 --- a/intents/dip-0002.md +++ b/intents/dip-0002.md @@ -4,7 +4,7 @@ ### Intent -To query existing intent by its ID, one can call `get_swap_intent` with following arguments: +To query existing intent by its ID, one can call `get_intent` with following arguments: ```json { @@ -85,11 +85,11 @@ to the intent shard and corresponding [action](#actions) must be attached. #### `native` Asset To execute an [action](#actions) by sending native NEAR, one should send a transaction attaching NEAR as deposit -and call `native_action` with following arguments: +and call `native_on_transfer` with action serialized to JSON string passed to `msg` argument: ```json { - "action": + "msg": "" } ``` @@ -140,7 +140,7 @@ and attach the action serialized to JSON in `msg` parameter. #### `cross_chain` Asset -To execute an [action](#actions) by sending cross-chain asset, one should call `on_cross_chain_transfer` +To execute an [action](#actions) by sending cross-chain asset, one should call `cross_chain_on_transfer` with following arguments: ```json @@ -225,6 +225,8 @@ Transferred asset will be considered as `asset_out`. } ``` +> **NOTE:** If exactly one of `asset_in` or `asset_out` fails due to + ### Generic Account #### `near` Account @@ -265,7 +267,19 @@ UNIX Timestamp in seconds ``` +### 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": "" +} +``` +The return value is `bool` indicating whether the `asset_in` was [lost](#lost-asset) during the rollback. ### Lost Assets @@ -346,6 +360,8 @@ Example: #### `rolled_back` Event +Example: + ```json { "standard": "dip2", @@ -357,6 +373,8 @@ Example: #### `lost` Event +Example: + ```json { "standard": "dip2", From 6e4c005f489a264748982fb6e563cf6a4e48c577 Mon Sep 17 00:00:00 2001 From: De Fuse Date: Tue, 30 Jul 2024 17:07:01 +0400 Subject: [PATCH 4/4] fix: asset flattening in example --- intents/dip-0002.md | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/intents/dip-0002.md b/intents/dip-0002.md index ce62c89..58a0e33 100644 --- a/intents/dip-0002.md +++ b/intents/dip-0002.md @@ -49,18 +49,14 @@ Example: { "asset_in": { "type": "nep141", - "asset": { - "token": "ft1.test.near", - "amount": "500" - }, + "token": "ft1.test.near", + "amount": "500", "account": "user1.test.near" }, "asset_out": { "type": "nep141", - "asset": { - "token": "ft2.test.near", - "amount": "1000" - }, + "token": "ft2.test.near", + "amount": "1000", "account": "user1.test.near" }, "expiration": { @@ -323,18 +319,14 @@ Example: "id": "872ab398-a27d-4673-9412-a4bf7cd2553e", "asset_in": { "type": "nep141", - "asset": { - "token": "ft1.test.near", - "amount": "500" - }, + "token": "ft1.test.near", + "amount": "500", "account": "user1.test.near" }, "asset_out": { "type": "nep141", - "asset": { - "token": "ft2.test.near", - "amount": "1000" - }, + "token": "ft2.test.near", + "amount": "1000", "account": "user1.test.near" }, "expiration": {