Completed: - Bounty #26 - ICRC-1 Motoko - up to $10k

Arweave costs about the same, but you’ll get storage for “minimum 200 years”.

Who knows if it would survive 200 years, but if your 1 GB is stored 2 years for $5, that’s cheaper than spending $10 for 2 years


1 Like

The ability to look up and verify an old transaction is likely necessary for most tokens. There are a number of payment flows that work by verifying that info. The ICP canister only holds the 2000 latest transactions, so if you have any kind of async workflow you need access to retrieve the transaction. Even if you had a dependable HTTP gateway to arweave that you could use HTTP outcalls to you’d be looking at cycle costs on the order(total estimate here) of at least 100,000x the cycle cost of a cross canister call and likely a number of rounds of consensus.

There are likely scenarios where storing data off chain on arweave or ipfs might be ok, but in most cases, you are severely limiting composability. It should be an anti-pattern for the IC. If you can store the data on the IC, and the unit economics come anywhere close to working in the medium term, you should store it on the IC. You leave yourself open to serendipity and use cases that you can’t imagine now. Moving it off the IC severely limits that capability.

I hope this is only relevant specifically for token transaction history, otherwise the high cost sounds like a major issue. It would force IC to be a closed system, pretty much making it pointless to have outbound HTTP calls if they’re so expensive

(I just looked it up and it’s 2.275 USD to store 1 GB on Arweave. Def a good deal for some use cases)

I’m confused dude — I thought the IC supports HTTP calls, but based on what you’ve said here, it sounds extremely inefficient and costly =\


Probably important to remember that this is base cost to store on Arweave. After that you have to figure out what you’re going to do with it. Does Arweave offer any sort of computation capability? If not, what chain do you go to for that and how much cost to make it work.

1 Like

I imagine it will be very expensive relative to a cross-canister call. Instead of just routing a message across a subnet you will have 13 computers make an outgoing HTTP call and then process whatever result is returned, then run a program to sync the responses and ensure a cohesive answer.

According to Computation and Storage Costs | Internet Computer Home a cross net call’s flat fee is 260,000. So an HTTP out call is 1,538x for just the flat fee. The per byte for HTTP out calls is 100M per byte, but the xcanister is 1,000 per byte. So your bytes are 100,000x more expensive. Perhaps @dieter.sommer can give us an update on what the final costs ended up being as this was rolled to production…these were numbers from a beta discussion.


Yea good point — I think it’s primarily for storage but it can do some cool things too haha


1 Like

Ahh I see, that is interesting. Yea I understand that numbers extremely massive. Now thats in rust with very little canister instruction limit right? On a motoko canister, if one were to do some operations on every single balance atomically the actual limit of balances would be limited, no?

It’s interesting that the ledger accounts delete balances that are not zero. Does it only choose the account balances below a certain number of decimals?

@Icypee I think the balances are in the main canister because an account balance requires less bytes than a transaction. And transactions tend to grow more than the number of new accounts that buy a token.

The max size of a transaction is about 196 bytes, and an account balance is about 76 bytes.
Assuming the max size of a canister is 4 GB, it’s possible to store 56M account balances in a single canister and only about 21M transactions.

The screenshot above is of the USDT token, one of the top tokens on the ethereum network with about 4M holders and 160M transactions .

Using this example, we can see that the main canister can store 14x the number of account balances but will need to upgrade to multiple archive canisters to store all the transactions.


Nope…it just orders them and deletes the smallest balances until it gets to the desired number.

1 Like

Ahh I see, thats a good point. Yea in reality and esp. with I think canister now moving to 32 gb storage its almost unlikely that another canister is needed. However, my question was more of a thought excercise to see if there was a way to have multi canister balances for one token and keep evertyhing consistent. I come from a education background where we always test with extremas for both 0 and as the limit goes to infinity so having storage limits like this where I can see a potential to scale to infinity keeps me up at night to solve it even if its almost never needed :sweat_smile:

1 Like

Timo has talked about multi-canister ledgers before, but that is really the only discussion I’ve seen about it. As far as motoko ICRC-1 goes…I think we just need to pressure-test it and see how much the performance differs from rust. I’m not expecting that much of a difference given the recent streaming upgrade upgrade.

1 Like

Is this bounty finished or has ICDev or Dfinity reviewed this implementation of the ICRC1 standard?

Also am I right to think that a canister that uses this library (e.g. icrc1/ at main · NatLabs/icrc1 · GitHub) can be used as the ledger canister for a SNS ? In order to be able to kick off a project creating the token first, and maybe later give the control to a SNS governance.

@tomijaga , @Iceypee any status updates? I think the last things we were waiting for were the Rosetta integrations.

1 Like

Oh @skilesare I wasnt assigned this bounty. Was just asking questions and learning.


Hey, @sardariuss I haven’t been keeping up with the developments of SNS but if it supports the icrc1 standard then you should be able to use this library. Maybe @skilesare can tell you for sure if it does. I’ve implemented all the functions for the icrc1 token standard but I would suggest waiting till the library has been reviewed by the IcDev org before using it in production.

Rosetta Integration

This is the function for the Rosetta API integration.

The GetTransactionsResponse type for this function has a field, archived_transactions that has a callback fn embedded in it. The problem with this is fns are considered shared types in motoko and shared functions are only allowed as public fields in actor classes for now so I keep getting errors when I implement a solution for this type.

I wrote this piece of code for the get_transactions fn but it returns an error:

/Users/dire.sol/Documents/dev/icp/icrc1/src/ICRC1/Canisters/ type error [M0077], a shared function is only allowed as a public field of an actor
  (This is a limitation of the current version.)

Is there any way to return a shared function from an actor without getting this error?

1 Like

Cc @claudio can you take a look?

1 Like

On mobile, but try to define function ‘callback’ as a public shared function at the same level as, and similarly to, for example, ‘get_transactions’ instead of locally within ‘get_transactions’.

You may want to protect this public function being called by any old caller by checking the caller id appropriately, if that makes sense here.

In Motoko programs targeting the IC, shared functions can only refer to public methods of actors, not locally declared or anonymous functions.


Thanks for your help @claudio!
I understand how to use shared functions better now.
I was able to assign the archive canister’s public get_transactions function to the callback field and return the response without any errors.

@skilesare The rosetta implementation is done and ready for a full review. Let me know if there is anything else that needs to be done.


Thanks to all involved in creating this. I’ll be using it soon and as a critical piece.

I have a basic question regarding ICRC and their interaction with canisters here, in case any of you know: How to get a canister's address to send ICRC tokens to, and generate further subaccounts(?) to do the same?

I’ll paste it here for ease:

I have a canister I need to send an ICRC token to. (The aim is for the canister to receive and hold an ICRC token balance).

How do I, as owner of the canister,

(a) get the canister’s default address to send ICRC tokens to, and

(b) generate additional addresses (not sure if they’re called subaccounts, whatever they are) controlled by the same canister to send ICRC tokens to?

Actually, does the ICRC-1 standard distinguish between such subaccounts (I don’t know if that’s the term), or does it only recognise one account per canister?