Skip to content

Inner balances

The engine holds assets for two kinds of owners: accounts (users) and DEXs. Each owner has an inner balance per asset. Swaps, transfers and DEX calls only move amounts between inner balances. Tokens leave the engine only when they’re withdrawn.

An owner is written as { "Account": "alice.near" } or { "Dex": "slimedragon.near/xyk" } in method arguments.

The near CLI examples on this page run in order, as alice.near after a storage deposit. Together they’re one script.

An owner can only receive an asset that is registered for it. Anything that would credit an unregistered asset fails with Asset <asset> is not registered for Account(<account>). This includes deposits, the output of swaps, and transfers.

Terminal window
near contract call-function as-transaction dex.intear.near register_assets \
json-args '{"asset_ids": ["near", "nep141:usdt.tether-token.near"]}' \
prepaid-gas '30.0 Tgas' attached-deposit '1 yoctoNEAR' \
sign-as alice.near network-config mainnet sign-with-keychain send

And for another account:

Terminal window
near contract call-function as-transaction dex.intear.near register_assets \
json-args '{
"asset_ids": ["nep141:usdt.tether-token.near"],
"for": {"Account": "bob.near"}
}' \
prepaid-gas '30.0 Tgas' attached-deposit '1 yoctoNEAR' \
sign-as alice.near network-config mainnet sign-with-keychain send
  • for is optional and defaults to you. You can register assets for another account or for a DEX.
  • The storage is always paid from your storage balance, even when registering for someone else.
  • Assets that are already registered are skipped. Registration can’t be undone.

Use are_assets_registered to check, for example before building a transaction:

Terminal window
near contract call-function as-read-only dex.intear.near are_assets_registered \
json-args '{
"asset_ids": ["near", "nep141:usdt.tether-token.near"],
"for": {"Account": "alice.near"}
}' \
network-config mainnet now

Deposits credit your inner balance. Each kind of asset arrives in its own way:

Asset How to deposit Credited to
near deposit_near on the engine, with the NEAR attached The caller
nep141:<contract> ft_transfer_call on the token, to dex.intear.near sender_id
nep171:<contract>:<token id> nft_transfer_call on the NFT contract, to dex.intear.near previous_owner_id
nep245:<contract>:<token id> mt_transfer_call or mt_batch_transfer_call on the contract, to dex.intear.near Each previous_owner_id

Leave msg empty ("") for a plain deposit, and don’t pass operations to deposit_near. Each plain deposit logs a user_deposit event.

Terminal window
near contract call-function as-transaction dex.intear.near deposit_near \
json-args '{}' \
prepaid-gas '30.0 Tgas' attached-deposit '1 NEAR' \
sign-as alice.near network-config mainnet sign-with-keychain send
Terminal window
near contract call-function as-transaction usdt.tether-token.near ft_transfer_call \
json-args '{"receiver_id": "dex.intear.near", "amount": "5000000", "msg": ""}' \
prepaid-gas '50.0 Tgas' attached-deposit '1 yoctoNEAR' \
sign-as alice.near network-config mainnet sign-with-keychain send

With a non-empty msg, the deposit doesn’t go to your inner balance: the tokens are used by the operations in msg.

If the deposit fails, for example because the asset isn’t registered for you, the token contract gets the tokens back to you, as NEP-141, NEP-171 and NEP-245 transfers do when the receiver fails.

You can also deposit NEAR with execute_operations: if you attach more than 1 yoctoNEAR, the whole deposit is added to your inner balance before the operations run.

Terminal window
near contract call-function as-read-only dex.intear.near asset_balance_of \
json-args '{"of": {"Account": "alice.near"}, "asset_id": "nep141:usdt.tether-token.near"}' \
network-config mainnet now
near contract call-function as-read-only dex.intear.near registered_assets_of \
json-args '{"account_id": "alice.near", "from_index": 0, "limit": 100}' \
network-config mainnet now

asset_balance_of returns the balance, or null if the asset isn’t registered for the owner.

registered_assets_of returns [[asset_id, balance], ...] for every registered asset, in the order they were registered. Pass dex_id instead of account_id for a DEX. Exactly one of them is required.

transfer_asset moves an amount from your inner balance to another account or DEX inside the engine. The receiver must have the asset registered.

Terminal window
near contract call-function as-transaction dex.intear.near transfer_asset \
json-args '{
"to": {"Account": "bob.near"},
"asset_id": "nep141:usdt.tether-token.near",
"amount": "1000000"
}' \
prepaid-gas '30.0 Tgas' attached-deposit '1 yoctoNEAR' \
sign-as alice.near network-config mainnet sign-with-keychain send

withdraw sends assets from your inner balance out of the engine: NEAR with a transfer, tokens with ft_transfer, nft_transfer or mt_transfer.

A NEP-141 token can only be sent to a wallet that is registered on the token contract. Register bob.near there first, unless they already hold the token:

Terminal window
near contract call-function as-transaction usdt.tether-token.near storage_deposit \
json-args '{"account_id": "bob.near", "registration_only": true}' \
prepaid-gas '30.0 Tgas' attached-deposit '0.00125 NEAR' \
sign-as alice.near network-config mainnet sign-with-keychain send

Then withdraw to them:

Terminal window
near contract call-function as-transaction dex.intear.near withdraw \
json-args '{
"asset_id": "nep141:usdt.tether-token.near",
"amount": {"Exact": "2000000"},
"withdraw_to": "bob.near"
}' \
prepaid-gas '50.0 Tgas' attached-deposit '1 yoctoNEAR' \
sign-as alice.near network-config mainnet sign-with-keychain send
Argument Description
asset_id The asset to withdraw
amount { "Exact": "<amount>" }, or { "Full": { "at_least": "<amount>" } } for the whole balance. Full fails if the balance is lower than at_least. at_least can be null
withdraw_to The wallet to send to. Optional, defaults to you

The amount leaves your inner balance right away, and the transfer happens in the next receipt. The method returns true if the transfer succeeded, and logs a withdraw event.

If the transfer fails, it returns false and the assets are refunded to an inner balance:

  1. to the receiver (withdraw_to), if the asset is registered for them in the engine,
  2. otherwise back to you.

Withdrawing an amount of 0 does nothing and returns true.