Regarding Transaction History
The working group is currently assessing metadata to be associated with transaction history. Here I advocate we should strive for feature parity with CAP, as the incumbent with overwhelming capture.
That Psychedelic steps back at the same time this group attempts to standardize transaction history presents an opportunity to ship an implementation with very broad near-term impact. As a caveat, of course CAP isn’t perfect, and we should be comfortable when differing from it.
General Lessons From CAP
- Motoko and Rust libraries make it trivial to add tx history to your canister.
- Hugely flexible data model is future-proof and extensible, but means unreliable data.
Transaction History Events
CAP employs an incredibly flexible data model, allowing developers to store basically anything they want:
public type Event = {
time : Nat64;
operation : Text;
details : [(Text, DetailValue)];
caller : Principal;
};
public type DetailValue = {
#I64 : Int64;
#U64 : Nat64;
#Vec : [DetailValue];
#Slice : [Nat8];
#Text : Text;
#True;
#False;
#Float : Float;
#Principal : Principal;
};
Developers made typos and forgot to add certain values, so the data was very inconsistent as a result.
The flexible model also provides extensibility, which may be a critical property. Consider the exercise of trying to determine a finite set of operations: ICRC has mint, transfer, and burn, but what about sale and list? Can we reliably predict future use cases, such as rent, delist, fractionalize, and so on? Should the standard leave room to support innovative tx history use cases?
Some Real CAP Event Types
I would recommend adding the “sale” event type to ICRC, considering the importance of marketplaces to the NFT ecosystem (sorry if this is already included, couldn’t find the reference.) Here’s an example CAP event:
// Sale (BTC Flower)
{
"time": 1670588669701,
"operation": "sale",
"details": [
[
"to",
{"Text": "58a0fcbd3ae8d5589f9b7e3208b979867b44d04b8d4d1bfe2ede9f641973243f"}
],
[
"from",
{"Principal": "jqazm-bdzbj-hnq3o-yexug-vqu3v-jonju-7ngcp-4yzbw-jyux4-lqejy-mae"}
],
[
"price_decimals",
{"U64": 8}
],
[
"price_currency",
{"Text": "ICP"}
],
[
"price",
{"U64": 18000000000}
],
[
"tokend_id",
{"Text": "jz2z7-3akor-uwiaa-aaaaa-beaag-maqca-aaaq7-a"}
]
],
"caller": "s4d6r-c23m5-5gapy-myo3t-7pgtm-pdf6g-3nepw-hfcnc-2ohyg-p6qqq-rae"
}
A “mint” event can also have a purchase price associated with it, as we see with this example:
// Sale (BTC Flower)
{
"time": 1670588669701,
"operation": "sale",
"details": [
[
"to",
{"Text": "58a0fcbd3ae8d5589f9b7e3208b979867b44d04b8d4d1bfe2ede9f641973243f"}
],
[
"from",
{"Principal": "jqazm-bdzbj-hnq3o-yexug-vqu3v-jonju-7ngcp-4yzbw-jyux4-lqejy-mae"}
],
[
"price_decimals",
{"U64": 8}
],
[
"price_currency",
{"Text": "ICP"}
],
[
"price",
{"U64": 18000000000}
],
[
"tokend_id",
{"Text": "jz2z7-3akor-uwiaa-aaaaa-beaag-maqca-aaaq7-a"}
]
],
"caller": "s4d6r-c23m5-5gapy-myo3t-7pgtm-pdf6g-3nepw-hfcnc-2ohyg-p6qqq-rae"
}
Some projects opted to add the “memo” field:
// Transfer (Cronics)
{
"time": 1670345256752,
"operation": "transfer",
"details": [
[
"token",
{ "Text": "oz5mx-cykor-uwiaa-aaaaa-b4aaq-maqca-aacq3-a" }
],
[
"to",
{ "Principal": "icdsn-5xpay-zrct4-of2q2-hyhrs-ftoyx-se5w7-xhzri-psrh4-ksiyr-bqe" }
],
[
"from",
{ "Principal": "tetgr-gbsy6-6hauq-s64fd-4qbcs-tkzqq-gmn26-3u5am-6bmn5-g2wi4-xqe" }
],
[
"memo",
{ "Slice": { "0": 0, "1": 0, "2": 0, "3": 0, "4": 0, "5": 0, "6": 0, "7": 0, "8": 0, "9": 0,"10": 0,"11": 0,"12": 0,"13": 0,"14": 0,"15": 0,"16": 0,"17": 0,"18": 0,"19": 0,"20": 0,"21": 0,"22": 0,"23": 0,"24": 0,"25": 0,"26": 0,"27": 0,"28": 0,"29": 0,"30": 0,"31": 0 } }
],
[
"balance",
{ "U64": 1 }
]
],
"caller": "tetgr-gbsy6-6hauq-s64fd-4qbcs-tkzqq-gmn26-3u5am-6bmn5-g2wi4-xqe"
}
Looking forward to the next discussion! I hope this provides some useful reference.