Swaps
This page is also Markdown, for agents: /intear-dex/guides/swaps.md, and /llms.txt lists every page.
A swap trades one asset for another on one DEX. The DEX decides the amounts, the engine moves the assets: amount_in from the trader to the DEX, amount_out from the DEX to the trader.
The near CLI examples on this page swap USDt from alice.near’s inner balance, after a storage deposit, these registrations, and a deposit of 10 USDt. Together they’re one script.
near contract call-function as-transaction dex.intear.near register_assets \ json-args '{ "asset_ids": [ "near", "nep141:usdt.tether-token.near", "nep141:17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1" ] }' \ prepaid-gas '30.0 Tgas' attached-deposit '1 yoctoNEAR' \ sign-as alice.near network-config mainnet sign-with-keychain sendSimulate
Section titled “Simulate”simulate_swap_simple is a view method that runs a swap without saving anything. It takes the same arguments as swap_simple plus trader, the account the DEX should see as the trader, and without constraint. It returns [amount_in, amount_out].
This one asks how much USDt it takes to get exactly 0.1 NEAR, and allows 1% more for the swap:
AMOUNT_IN=$(near contract call-function as-read-only dex.intear.near simulate_swap_simple \ json-args '{ "dex_id": "slimedragon.near/xyk", "message": "AQAAAEBCDwABAAAA3QAAAAA=", "trader": "alice.near", "asset_in": "nep141:usdt.tether-token.near", "asset_out": "near", "amount": {"ExactOut": "100000000000000000000000"} }' \ network-config mainnet now | jq -r '.[0]')# Pay up to 1% more than the simulationMAX_AMOUNT_IN=$((AMOUNT_IN * 101 / 100))The simulation doesn’t check balances or registrations, so a swap that simulates fine can still fail for those reasons.
swap_simple
Section titled “swap_simple”near contract call-function as-transaction dex.intear.near swap_simple \ json-args "$(jq -n --arg max_amount_in "$MAX_AMOUNT_IN" '{ "dex_id": "slimedragon.near/xyk", "message": "AQAAAEBCDwABAAAA3QAAAAA=", "asset_in": "nep141:usdt.tether-token.near", "asset_out": "near", "amount": {"ExactOut": "100000000000000000000000"}, "constraint": $max_amount_in }')" \ 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 to swap on |
message |
Base64 bytes passed to the DEX as is. Each DEX defines its own format, usually the pool or route. For Plach, AQAAAEBCDwABAAAA3QAAAAA= is pool 221 (NEAR/USDt) and AQAAAEBCDwABAAAAVQAAAAA= is pool 85 (NEAR/USDC). See Plach routes |
asset_in, asset_out |
The assets to swap |
amount |
{"ExactIn": "<amount>"} to pay an exact amount, or {"ExactOut": "<amount>"} to receive an exact amount |
constraint |
Optional. With ExactIn, the minimum amount_out. With ExactOut, the maximum amount_in. The swap fails if it’s not met |
referrer |
Optional. Passed to the DEX in the swap request, and logged in the swap event and with the events the DEX logs. It doesn’t charge anything, and Plach ignores it. Pass the same referrer to the simulation, in case a DEX uses it |
referral_fees |
Optional. Fees for your app, out of the input, like [["myapp.near", 5000]] for 0.5%. See Referral fees. Pass the same fees to the simulation |
It returns [amount_in, amount_out]. amount_in includes the referral fees.
Before swapping:
- Your inner balance must have at least
amount_inofasset_in. asset_outmust be registered for you, or the output can’t be credited.
If anything fails, including the constraint, the whole call fails and no balances change.
What the engine checks
Section titled “What the engine checks”The DEX returns amount_in and amount_out. The engine then checks that:
- with
ExactIn, the DEX’samount_inequals the requested amount, minus the referral fees (Amount in does not matchotherwise), - with
ExactOut, the DEX’samount_outequals the requested amount (Amount out does not matchotherwise), - the
constraintholds, with the referral fees included in the input, - the DEX has enough
asset_outin its inner balance.
The DEX can’t take more than amount_in from you or give out tokens it doesn’t hold.
Several swaps in one call
Section titled “Several swaps in one call”To swap through several pools or DEXs, use execute_operations with several SwapSimple operations. Each one can take the output of the previous one as input with "amount": "OutputOfLastIn".
This swaps 1 USDt to USDC through NEAR, with two Plach pools. To get the least USDC to accept, simulate each swap with the output of the one before:
NEAR_OUT=$(near contract call-function as-read-only dex.intear.near simulate_swap_simple \ json-args '{ "dex_id": "slimedragon.near/xyk", "message": "AQAAAEBCDwABAAAA3QAAAAA=", "trader": "alice.near", "asset_in": "nep141:usdt.tether-token.near", "asset_out": "near", "amount": {"ExactIn": "1000000"} }' \ network-config mainnet now | jq -r '.[1]')USDC_OUT=$(near contract call-function as-read-only dex.intear.near simulate_swap_simple \ json-args "$(jq -n --arg near_out "$NEAR_OUT" '{ "dex_id": "slimedragon.near/xyk", "message": "AQAAAEBCDwABAAAAVQAAAAA=", "trader": "alice.near", "asset_in": "near", "asset_out": "nep141:17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1", "amount": {"ExactIn": $near_out} }')" \ network-config mainnet now | jq -r '.[1]')MIN_USDC_OUT=$((USDC_OUT * 99 / 100))near contract call-function as-transaction dex.intear.near execute_operations \ json-args "$(jq -n --arg min_usdc_out "$MIN_USDC_OUT" '{ "operations": [ { "SwapSimple": { "dex_id": "slimedragon.near/xyk", "message": "AQAAAEBCDwABAAAA3QAAAAA=", "asset_in": "nep141:usdt.tether-token.near", "asset_out": "near", "amount": {"Amount": {"ExactIn": "1000000"}}, "constraint": null } }, { "SwapSimple": { "dex_id": "slimedragon.near/xyk", "message": "AQAAAEBCDwABAAAAVQAAAAA=", "asset_in": "near", "asset_out": "nep141:17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1", "amount": "OutputOfLastIn", "constraint": $min_usdc_out } } ] }')" \ prepaid-gas '200.0 Tgas' attached-deposit '1 yoctoNEAR' \ sign-as alice.near network-config mainnet sign-with-keychain sendPut the constraint on the last swap: it limits the result of the whole chain. The intermediate assets must be registered for you, because each output is credited to your inner balance before the next swap takes it.
Plach can also route through several of its pools in one swap, with a longer route in message. Several SwapSimple operations are for routes that go through different DEXs, or when you build the route yourself.
To swap on whichever of several DEXs or routes gives the most, or to fall back to another when one fails, use a SwapAdvanced operation.
The whole script
Section titled “The whole script”#!/usr/bin/env bash# Swaps USDt from the inner balance: for an exact amount of NEAR, then to USDC# through NEAR in one call. alice.near holds USDt in the wallet and has never# used Intear DEX.set -euo pipefail
near contract call-function as-transaction dex.intear.near storage_deposit \ json-args '{}' \ prepaid-gas '30.0 Tgas' attached-deposit '0.01 NEAR' \ sign-as alice.near network-config mainnet sign-with-keychain send
near contract call-function as-transaction dex.intear.near register_assets \ json-args '{ "asset_ids": [ "near", "nep141:usdt.tether-token.near", "nep141:17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1" ] }' \ prepaid-gas '30.0 Tgas' attached-deposit '1 yoctoNEAR' \ sign-as alice.near network-config mainnet sign-with-keychain send
near contract call-function as-transaction usdt.tether-token.near ft_transfer_call \ json-args '{"receiver_id": "dex.intear.near", "amount": "10000000", "msg": ""}' \ prepaid-gas '50.0 Tgas' attached-deposit '1 yoctoNEAR' \ sign-as alice.near network-config mainnet sign-with-keychain send
AMOUNT_IN=$(near contract call-function as-read-only dex.intear.near simulate_swap_simple \ json-args '{ "dex_id": "slimedragon.near/xyk", "message": "AQAAAEBCDwABAAAA3QAAAAA=", "trader": "alice.near", "asset_in": "nep141:usdt.tether-token.near", "asset_out": "near", "amount": {"ExactOut": "100000000000000000000000"} }' \ network-config mainnet now | jq -r '.[0]')# Pay up to 1% more than the simulationMAX_AMOUNT_IN=$((AMOUNT_IN * 101 / 100))
near contract call-function as-transaction dex.intear.near swap_simple \ json-args "$(jq -n --arg max_amount_in "$MAX_AMOUNT_IN" '{ "dex_id": "slimedragon.near/xyk", "message": "AQAAAEBCDwABAAAA3QAAAAA=", "asset_in": "nep141:usdt.tether-token.near", "asset_out": "near", "amount": {"ExactOut": "100000000000000000000000"}, "constraint": $max_amount_in }')" \ prepaid-gas '100.0 Tgas' attached-deposit '1 yoctoNEAR' \ sign-as alice.near network-config mainnet sign-with-keychain send
NEAR_OUT=$(near contract call-function as-read-only dex.intear.near simulate_swap_simple \ json-args '{ "dex_id": "slimedragon.near/xyk", "message": "AQAAAEBCDwABAAAA3QAAAAA=", "trader": "alice.near", "asset_in": "nep141:usdt.tether-token.near", "asset_out": "near", "amount": {"ExactIn": "1000000"} }' \ network-config mainnet now | jq -r '.[1]')USDC_OUT=$(near contract call-function as-read-only dex.intear.near simulate_swap_simple \ json-args "$(jq -n --arg near_out "$NEAR_OUT" '{ "dex_id": "slimedragon.near/xyk", "message": "AQAAAEBCDwABAAAAVQAAAAA=", "trader": "alice.near", "asset_in": "near", "asset_out": "nep141:17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1", "amount": {"ExactIn": $near_out} }')" \ network-config mainnet now | jq -r '.[1]')MIN_USDC_OUT=$((USDC_OUT * 99 / 100))
near contract call-function as-transaction dex.intear.near execute_operations \ json-args "$(jq -n --arg min_usdc_out "$MIN_USDC_OUT" '{ "operations": [ { "SwapSimple": { "dex_id": "slimedragon.near/xyk", "message": "AQAAAEBCDwABAAAA3QAAAAA=", "asset_in": "nep141:usdt.tether-token.near", "asset_out": "near", "amount": {"Amount": {"ExactIn": "1000000"}}, "constraint": null } }, { "SwapSimple": { "dex_id": "slimedragon.near/xyk", "message": "AQAAAEBCDwABAAAAVQAAAAA=", "asset_in": "near", "asset_out": "nep141:17208628f84f5d6ad33f0da3bbbeb27ffcb398eac501a31bd6ad2011e36133a1", "amount": "OutputOfLastIn", "constraint": $min_usdc_out } } ] }')" \ prepaid-gas '200.0 Tgas' attached-deposit '1 yoctoNEAR' \ sign-as alice.near network-config mainnet sign-with-keychain send