Skip to content

DEXs on the engine

A DEX on Intear DEX is a WebAssembly module stored in the engine contract. The engine runs it in an interpreter when someone swaps on it or calls one of its methods. The DEX has its own inner balances and its own storage, and can’t touch those of other DEXs or users.

A DEX ID is <deployer>/<name>: the account that deployed the code, and a name the deployer chose. For example, slimedragon.near/xyk is the DEX that Intear Plach runs on. The same deployer can have several DEXs with different names.

DEX code is deployed with deploy_dex_code, or with a DeployDexCode operation in execute_operations. Only the trusted code deployer can call it (see below), so here are only its arguments:

// deploy_dex_code, deposit: 1 yoctoNEAR
{
"last_part_of_id": "xyk",
"code_base64": "<base64 of the .wasm>"
}

This creates or replaces the code of the DEX <caller>/<last_part_of_id>, pays for the code from the DEX’s storage balance, and logs a dex_deployed event with the SHA-256 of the code. Make a storage deposit for the DEX with dex_storage_deposit first.

Besides swap, a DEX can have any other methods: adding and removing liquidity, creating pools, settings for its owner, reads of its state. Reach them with dex_call and dex_view. Arguments and results are bytes, in base64, in whatever format the DEX defines.

This registers alice.near for the liquidity shares of Plach’s pool 221. args is the pool ID in Borsh (221 as a little-endian u32), and the attached NEAR pays for the storage, from alice.near’s inner balance. The DEX uses what it needs, and sends the rest back to alice.near’s wallet. It runs after a storage deposit, registering near, and a deposit of 0.01 NEAR, as in this script.

Terminal window
near contract call-function as-transaction dex.intear.near dex_call \
json-args '{
"dex_id": "slimedragon.near/xyk",
"method": "register_liquidity",
"args": "3QAAAA==",
"attached_assets": {"near": "10000000000000000000000"}
}' \
prepaid-gas '100.0 Tgas' attached-deposit '1 yoctoNEAR' \
sign-as alice.near network-config mainnet sign-with-keychain send
Argument Description
dex_id The DEX
method The method to call. Can’t be swap
args Base64 arguments, in the DEX’s format
attached_assets Assets to give to the DEX with the call, from your inner balance. The DEX sees them and their amounts, and the engine moves them to the DEX’s inner balance. Can be {}
referrer Optional, passed to the DEX

It returns the DEX’s response, in base64. The DEX can also, in its response:

  • send assets from its inner balance to the inner balance of an account or another DEX,
  • withdraw assets from its inner balance to a wallet,
  • turn NEAR from its inner balance into its storage balance.

The same call is available as a DexCall operation.

A view method. The DEX can read its storage but can’t change anything.

This reads Plach’s pool 221. Like with dex_call, args is the pool ID in Borsh:

Terminal window
near contract call-function as-read-only dex.intear.near dex_view \
json-args '{
"dex_id": "slimedragon.near/xyk",
"method": "get_pool",
"args": "3QAAAA=="
}' \
network-config mainnet now

It returns the DEX’s response in base64, or "" if the DEX returned nothing.

swap dex_call dex_view
Input Borsh SwapRequest: message, assets, amount, referrer Borsh DexCallRequest: attached_assets and args args as is
Expected output Borsh SwapResponse: amount_in, amount_out Borsh DexCallResponse, or nothing Any bytes
predecessor_account_id The alleged trader The caller Not available
attached_deposit 0 1 yoctoNEAR if authorized, 0 otherwise 0
Can write storage Yes Yes No

A call is authorized when the caller made it directly: dex_call, or a DexCall operation in execute_operations. A DexCall in the operations of a deposit is not authorized, because the caller there is whoever the token contract says sent the tokens. DEXs use attached_deposit to tell these apart, the same way NEAR contracts check for 1 yoctoNEAR.

The trader of a swap is alleged for the same reason. A swap in the operations of a deposit is for whoever the token contract names as the sender, and a forged token contract can call ft_on_transfer with any sender_id. A DEX must not give the trader of a swap anything it wouldn’t give anyone, such as access to their liquidity or fees. Use a dex_call for that.

To fail a swap or a call, the DEX panics. The whole engine call fails with an error that contains [<dex id>] Dex panicked: <message>, and no balances change.

A DEX runs inside the engine’s receipt, so it can’t make cross-contract calls. It can use storage, logs, block height and timestamp, gas counters, the random seed, and hash and signature functions (SHA-256, Keccak, RIPEMD-160, ecrecover, ed25519_verify). Text a DEX logs appears in the receipt logs prefixed with [<dex id>], and events it logs are wrapped in engine events.