Hello Internet Computer Community!
We’re excited to share bity_ic_icrc3, our open-source implementation of the ICRC3 transaction standard for the Internet Computer. We’re developing this library with the goal of enhancing the developer experience and improving standardization across the IC ecosystem.
What is ICRC3 and why it matters
ICRC3 is the transaction standard that complements other ICRC standards by providing a unified way to record, store, and query transaction history on the Internet Computer. While standards like ICRC1 (fungible tokens) and ICRC7 (NFTs) define the token operations, ICRC3 standardizes how these operations are logged and made available to users and applications.
The standard addresses several critical needs:
- Standardized history access: Consistent API for querying transaction history across different tokens
- Efficient storage: Automatic archiving to manage ledger size as transaction history grows
- Certification: Support for certified queries of transaction history
- Interoperability: Universal transaction format that works across different applications
Why we built bity_ic_icrc3
As part of our collaboration with Origyn to create a robust implementation of ICRC7/ICRC-37 in Rust on Dfinity, our team found ourselves needing to reimplement ICRC3 - a standard that should be easily reusable by any project. We noticed that many developers were reimplementing the same transaction logging logic over and over, leading to inconsistencies and duplicated effort.
We’ve invested significant time creating a robust, flexible implementation that:
- Is fully compliant with the ICRC3 standard
- Works seamlessly with ICRC1, ICRC2, ICRC7, and ICRC37 (or any others standard that need blocks transactions)
- Can be used with any project requiring a blockchain-style action logging system, not just token standards
- Handles archiving and storage management automatically
- Is easy to integrate into any canister
- Includes essential optimizations for performance and cycles efficiency
While ICRC3 was designed primarily for token standards, its architecture makes it perfect for any application that needs to maintain an auditable history of actions in a blockchain-like structure. Whether you’re building a governance system, a supply chain tracker, or any application requiring transparent action logging, bity_ic_icrc3 provides the infrastructure you need.
How to integrate bity_ic_icrc3 into your project
Integration is straightforward. Add it to your Cargo.toml
:
[dependencies]
bity_ic_icrc3 = "0.1.0"
bity_ic_icrc3_macros = "0.1.0"
Then in your canister code:
// 1. Define your transaction type
#[derive(CandidType, Serialize, Deserialize, Clone, Debug)]
pub struct MyTransaction {
pub btype: String,
pub timestamp: u64,
pub tx: TransactionData,
}
// 2. Add ICRC3 state to your canister
use bity_ic_icrc3_macros::icrc3_state;
icrc3_state!();
// 3. Initialize ICRC3 in your init function
fn init() {
// Configure ICRC3
let icrc3_config = ICRC3Config {
supported_blocks: vec![
SupportedBlockType {
block_type: "transfer".to_string(),
url: "https://github.com/dfinity/ICRC/...",
},
// Add other transaction types
],
constants: ICRC3Properties::new(/* ... */),
};
// Initialize
init_icrc3(icrc3_config);
}
// 4. Create ICRC3 API endpoints
#[query]
async fn icrc3_get_blocks(args: GetBlocksArg) -> GetBlocksResult {
icrc3_get_blocks_impl::<MyTransaction>(args).await
}
// Add other endpoints (icrc3_get_archives, etc.)
// 5. Add transactions in your update methods
#[update]
async fn transfer(/* ... */) {
// Business logic...
// Log the transaction
let transaction = MyTransaction {
btype: "transfer".to_string(),
timestamp: ic_cdk::api::time(),
tx: TransactionData {
// Transaction details
},
};
match icrc3_add_transaction(transaction).await {
Ok(_) => { /* Success */ },
Err(e) => { /* Handle error */ }
}
}
Real-world example: ICRC7 NFT integration
We’ve already implemented this in the ICRC7 NFT solution we’re working on. Here’s a simplified example of how we use ICRC3 to record a token transfer:
#[update]
pub async fn icrc7_transfer(args: icrc7::icrc7_transfer::Args) -> Response {
// Validate the transfer...
// When valid, record the transaction
let transaction = Icrc3Transaction {
btype: "7xfer".to_string(),
timestamp: ic_cdk::api::time(),
tx: TransactionData {
tid: token_id.clone(),
from: Some(token_owner),
to: Some(new_owner),
meta: None,
memo: args.memo.clone(),
created_at_time: Some(Nat::from(time)),
},
};
icrc3_add_transaction(transaction).await?;
// Update token ownership state
// ...
}
For metadata updates, we store additional information in the transaction:
// When updating NFT metadata
let mut metadata_map = BTreeMap::new();
metadata_map.insert(
"icrc7:token_name".to_string(),
Icrc3Value::Text(new_name.clone()),
);
let transaction = Icrc3Transaction {
btype: "7update_token".to_string(),
timestamp: ic_cdk::api::time(),
tx: TransactionData {
tid: token_id.clone(),
from: Some(Account { owner: caller, subaccount: None }),
to: None,
meta: Some(Icrc3Value::Map(metadata_map)),
memo: None,
created_at_time: Some(Nat::from(ic_cdk::api::time())),
},
};
icrc3_add_transaction(transaction).await?;
Benefits for the Internet Computer ecosystem
By adopting this library, we can achieve:
- Consistent user experience: Wallets and block explorers can display transaction history in a standardized way
- Developer efficiency: Focus on your business logic instead of implementing transaction logging
- Interoperability: Applications can easily read transaction history from any token that implements ICRC3
- Future-proof: As the standard evolves, you’ll get updates through the library
- Reduced cycles consumption: Our implementation includes optimizations for storage and archiving
Developer Grant Proposal
We’ve applied for a developer grant to support ongoing development and maintenance of this library. The grant would help us:
- Expand test coverage and improve documentation
- Add features like configurable transaction compression
- Create adapters for more token standards beyond ICRC1 and ICRC7
- Build example applications and integration guides
- Perform security audits and optimizations
Get involved
We’d love your feedback and contributions! You can:
- Try the library and share your experience
- Review or try to contribute to the codebase on GitHub (links above)
- Suggest features or report issues
Next steps
For now, icrc3 is available on our github :
- dfinity-rust-libraries/src/icrc3 at master · BitySA/dfinity-rust-libraries · GitHub
- dfinity-rust-libraries/src/icrc3_canisters at master · BitySA/dfinity-rust-libraries · GitHub
- dfinity-rust-libraries/src/icrc3_macros at master · BitySA/dfinity-rust-libraries · GitHub
With integrations tests and a example canisters presents :
- dfinity-rust-libraries/src/icrc3_canisters/canisters/icrc3_example at master · BitySA/dfinity-rust-libraries · GitHub
- dfinity-rust-libraries/src/icrc3_canisters/integration_testing at master · BitySA/dfinity-rust-libraries · GitHub
We’re planning to release v1.0.0 in the coming weeks.
We’ll also soon be releasing the icrc7 nft version we’re working on, which would also be a good use case.
In addition to the core library, we’re developing a transaction indexer that will provide a simple way to browse and search through transactions. This indexer will:
- Allow efficient querying of transaction history across multiple canisters
- Support filtering by transaction types, accounts, and time ranges
- Provide aggregated statistics and insights
- Offer a simple API for integration with frontends and analytics tools
- Scale automatically with your application’s growth
This will give developers who use our library a complete solution for transaction management without having to build their own indexing infrastructure.
Questions?
Please share your thoughts and questions in the comments below. We’re here to help the community adopt this standard and make the Internet Computer ecosystem more user-friendly and interoperable!