ICRC-55 DeFi Vectors

A DeFi Vector has a source address and a destination address.
The source address is controlled by the vector agent (canister).
The destination address can be anywhere and doesn’t have to be controlled by the agent.
Vectors are first set up inside the agent and then used simply by sending tokens to their source address. No other communication is required for them to move tokens to the destination.
They are automatic agents using heartbeats or timers.

The client can send multiple transactions to the source address over a long period of time.
This makes them perfect for usage by developers and DAOs for dApp tokenization. Integrating them takes sending one icrc1_transfer and since there are no additional interfaces for their primary operation, nothing can break.
These could be a fundamental building block when creating dApps that speeds up development and results in bullet proof tokenization.

A simple visualization of DeFi Vectors and the reason they were named vectors.

Vector within one ledger

Such vectors can send tokens from A to B on a schedule - scheduler agent. Or be a splitter agent - sending tokens to different addresses. It’s possible to also have neurons as sources and targets.

The destination of agent A can be the source of agent B

Vector between two ledgers on the IC

These are exchange vectors and any DEX can provide services with its own vector agent.

Vector crossing different networks

Vectors within one agent can share sources

Vector agents on the IC can work with sources and destinations in other chains thanks to t-ecdsa.
Example - serve as tokenization engine for Bitcoin inscriptions.

When it comes to IC tokens, vectors communicate between each other and clients through the ledger. Using ICRC-1, ICRC-4 to send transactions and ICRC-3 to follow the transaction log. They don’t have to wait for a callback when sending transactions (oneway calls).

This requires the client to setup their vectors with the agent. Ideally vector agents will be permanent, audited and black-holed or DAO controlled.

There is one exception - withdrawing from the source in cases when the agent fails to move tokens to the destination (Ex: an exchange vector agent couldn’t satisfy a target rate for a long time). This one takes a call to the agent. It’s possible to not have it - for example the agent sends automatically tokens back to an address if it fails.

Vectors work very well with the new messaging model.

Interfaces for different vector agents can be standardized with icrc extensions.

DeFi WG GitHub - Neutrinomic/wg_defi
Next meeting: 6th Feb. 4pm CET


Interesting stuff. I read it a couple of times - hopefully I’m on the same page in thinking.

The first thing that pops into my head with this kind of thing is a tax efficient way of taking payments. A business could have a payment vector which takes payments in any token, converts this to a USD stable and records the value of the sale for easy reporting. The vector could then on a timer shift X% into a tax-saving account while a 2nd payment is made to the ‘main’ account (changing chains/tokens if needed).

Am I correct in thinking a vector canister wishing to swap/ change tokens needs to hold a balance of both? Sort of alike a private liquidity pool but the price comes from a 3rd party rather than the balance in the private pool?

In regards the ICRC-3 reading of the ledger - I wonder if there is a more efficient way of doing this - at the slight expense of setup complexity and maybe latency.

The idea here is that a standard is created for ‘notify’ events and then any canister developer can subscribe to a black-holed notification canister (providing the address to scan for, a canister to notify, and maybe even a OpenChat principal for alerts). The notification canister then reads single/multiple ledgers scanning against the subscribed accounts.

Once notified of a transaction, the agent can then do whatever logic they like - eg making an ICRC-1 transfer.

The benefit of this is that the agents can all be passive - reducing cycles burn and reducing the number of people reading the same data from ledger canisters.

Just a couple of ideas.


Sounds like an interesting use case! Thanks for sharing.
Defi Vectors only specify some transport & communication aspects.

Rule 1: Vector agents aren’t required to be called/notified with messages when receiving tokens for their casual operation, transfering to the source address is sufficient and they automatically handle deposits. If someone breaks this rule, then we can’t chain these easily.

Ofc you can make a notifying canister that follows the log and notifies the vector agent. There are a few issues with that

  • ICP ledger has hashed addresses in its log
  • The messaging model doesn’t guarantee message delivery
  • Also it will be a bit slower

It’s possible, just not sure it’s worth it yet.

An exchange vector can work in many ways. It could have a local pool or it could just get the tokens from somewhere else, or it could mint them - BTC → ckBTC


There is a slight problem.
ICRC ledgers accept tx with {account;subaccount} and log tx with {account;subaccount}
The ICP ledger accepts tx with {account;subaccount} or (legacy account) and log tx with (legacy account)
legacy account - hash({account;subaccount})

With the ICP ledger when following the log we don’t know if a transaction is sent to us unless we know the exact subaccount.

If the ICP ledger adds both the {account;subaccount} and (legacy account) inside log tx when icrc transfers are made, this will solve our problems @mariop . When non-icrc transfers are made, only the (legacy account) gets logged. (Solves them if all wallets use icrc1_transfer when given ICRC1 text address and don’t covert it to legacy account and send to that using legacy transfer. If they don’t understand icrc1 text addresses, then tokens won’t get set at all, which is good) Edit: actually the ICP ledger knows the principal,subaccount of the (from) icrc account even in the old function, so that can be added without prob, It’s just doesn’t know the icrc account of the (to) address.

With permanent vectors that’s not a problem at all, but they have to be created manually before they get used (they store the subaccount in memory and wait for it hashed or not)

With ICRC ledgers, we can make on-demand vectors where users send tokens (ckBTC) and get tokens back (ckETH) - their sender address. We can’t do it with the ICP ledger, because when we receive (ICP) we need to send (ckBTC) to an account and not the hashed legacy address.
ICP is the most important token around, so it’s not like - only 1 ledger out of 40 has this problem, but more like 90% of the value around DeFi carries the problem.

In @NS01 idea to make a notifier, the notifier following ICP ledger will require subscribers to send every single subaccount to the notifier for it to be able to function. This is not the case with ICRC ledgers. A notifier there can just send all notifications based on the account.owner = canister principal and this will cover all subaccounts.

1 Like

DeFi Vector throughput

Please let me know if there is a flaw in the following calculations:

Given there is a backpressure limit - up to 500 in-flight calls between a pair of canisters. If a single icrc1_transfer takes 5 seconds, that will mean a canister can make up to 100 calls/sec = 100 tx/s with icrc1. With ICRC-4 [ICRC-4: Batch Transfers · Issue #4 · dfinity/ICRC · GitHub], it can do 100 calls/sec where let’s say each call can contain a batch with 100 transactions (conservative) = 10,000 tx/sec.

On the other side (reading), we need to follow the transaction log. Currently, a call to fetch tx using ICRC-3 returns 1,000 transactions and takes ~4 sec. If we are just making one call after another, we are going to be able to follow the ledger with a speed of 250 tx/s. But since blocks have sequential numbers, we can run many calls in parallel if we are too far behind. So our speed can go up to let’s say 20 parallel calls * 250 tx/s = 5,000 tx/s.

So in theory, a DeFi vector has a limit of sending 10,000 tx/s with ICRC-4 , reading 5,000 tx/s with ICRC-3 and a limit of sending 100 tx/s with ICRC-1.

@skilesare @mariop @free

1 Like

We have a PoC permanent exchange vector working https://github.com/Neutrinomic/defivectors Not audited yet, it’s under development.
Going through the whole code to see how they work isn’t recommended.
Also we want to make more vectors and do the airdrop with one and a lot of the code can be reused, so we deconstructed it and pulled out two libraries:

(A lot of room for improvement in terms of speed, performance and handling edge cases under load)

Once we put them back in, the whole thing will get audited, so anyone making vectors will enjoy the better security of these libraries.

Finally, there is this repo https://github.com/Neutrinomic/devefi_backpass
an example simple vector using the libraries. It classifies as on-demand vector, since there is no need to set it up before making a transaction.

It just sends tokens back to the sender as soon as it receives them.
If you want to test it out, send ckBTC (don’t send a lot) to “7i4bb-xaaaa-aaaal-qdfla-cai” (any subaccount will work) and the vector agent will send your tokens back minus the ledger fee.


Where does the WG meet?

1 Like

ICP Developer Community Discord. ICP Developer Community

The test confirmed it DeVeFi Ledger - ICRC ledger client library - #11 by infu

Some more advanced things you can do with ICP DeVeFi using our MIT-licensed library. All kinds of DeFi contracts—you just program the flow and nothing else. Contract size reduced from ~5000 lines to 50. Lending, AMMs, arbitrage bots, trading bots, algorithmic coins, etc. You send one token, you get another. No public actor methods needed.

Of course Dfinity built 99.99% of the infrastructure. We just made the library. They deserve most of the credit.


Big Brain thinking here, seriously

So to implement some of this code, it seems you need to use a get_transactions () function which is currently missing from the icrc1 standard implementation but exists in some active icrc1 contract.
The draft icrc3 will include get_blocks but idk if this will work for a get_transactions or an even further get_batch transactions.

1 Like

Yes, if a canister method doesn’t have “icrc” prefix then it is not part of any icrc. Ledgers will have icrc1,2,3,4 and so on methods. Our middleware is currently made to only work with the SNSW icrc ledger by Dfinity, but we will make it work with icrc3 when it gets implemented.

1 Like