Hi there! First of all, thank you all for your effort! I’d like to know if there will be a reference implementation for Motoko as well? Or will I have to port the finished assignment by myself if I’d like to use the standard in Motoko?
hello @benji
any update regarding the code review?
is there any further changes to be made?
Hi, would like to join this bounty.
Experience:
- Currently utilizing IC DID for live NFT gated metaverse platform
- Successfully completed Dev Grant milestones with frontend and backend app fully deployed to the IC
Timeline:
- Updating base canister with read methods outlined in spec - 2-3d
- Updating base canister with write methods outlined in spec - 2-3d
- Connecting calls to frontend interface - 2d
- Making sure implementation is conformant to spec and testing implementation 2-3d
Hi @Agent2222,
thanks a lot for your interest. However, the bounty is already assigned.
Have a look at Internet Computer Loading and Bounties - Internet Computer Developer Forum for more opportunities.
Ah, thanks. Still getting the hang of navigating the forums.
Hi @pramitgaha, I submitted my review to your github. Another colleague is currently on vacation but will review once he’s back.
hello @benji , can you upgrade the candid
version in ic-ledger-types
package to 0.9.3
?
ic_ledger_types - Rust is using candid = ^0.9
so it should already be possible to use it in a project using candid 0.9.3
. What error do you get? @pramitgaha
ohh, I was importing the library by specifying the git path
icrc-ledger-types = { git ="https://github.com/dfinity/ic" }
In that git repo, candid
’s version was ‘0.8.4’
I didn’t knew library was published!
hello @benji I can’t see structs like Account
in the library!
I’m not sure what your question is, but Account
is here Account in icrc_ledger_types::icrc1::account - Rust
Hey all! It’s so incredible
By the way, what is the future fate of these standards? Will their quality be separately tested?
Besides, is it possible to create a separate library, for example, on Motoko, which will contain all the developed standards with the ability to import them and customize your canisters?
@benji , rewrote the work: icrc7
regarding clear of expired approvals: I didn’t do that. I saw in the revoke_approval
method’s error there is one variant ApprovalExpired
. To keep a track for that: I didn’t cleared the expired approvals.
Also regarding revoke_approval
I’ve messaged you!
can you have a look?
thank you!
We intend to remove the ApprovalExpired
error exactly for this reason.
The docs listed here have some updates.
We are a group building code for the IC and supporting the integration of existing IC tech into enterprise workflows.
We have a base ICRC7 Motoko Class/Base Implementation that we’d like to submit for this bounty. We have a test suite, and it can be implemented by the following actor:
import Array "mo:base/Array";
import Vec "mo:vector";
import Principal "mo:base/Principal";
import Time "mo:base/Time";
import Nat "mo:base/Nat";
import D "mo:base/Debug";
import ICRC7 "../src";
import SB "mo:stablebuffer_1_2_0/StableBuffer";
shared(_init_msg) actor class Example(_args : {
icrc7_args: ICRC7.InitArgs;
}) = this {
type LogEntry = ICRC7.LogEntry;
type Account = ICRC7.Account;
type Environment = ICRC7.Environment;
type Value = ICRC7.Value;
type NFT = ICRC7.NFT;
type NFTShared = ICRC7.NFTShared;
type NFTMap = ICRC7.NFTMap;
type OwnerOfResponse = ICRC7.OwnerOfResponse;
type OwnerOfResponses = ICRC7.OwnerOfResponses;
type ApprovalInfo = ICRC7.ApprovalInfo;
type ApprovalResponse = ICRC7.ApprovalResponse;
type ApprovalResponses = ICRC7.ApprovalResponses;
type ApprovalCollectionResponse = ICRC7.ApprovalCollectionResponse;
type TransferArgs = ICRC7.TransferArgs;
type TransferResponse = ICRC7.TransferResponse;
type TransferError = ICRC7.TransferArgs;
type RevokeTokensArgs = ICRC7.RevokeTokensArgs;
type RevokeTokensResponseItem = ICRC7.RevokeTokensResponseItem;
type RevokeCollectionArgs = ICRC7.RevokeCollectionArgs;
type RevokeCollectionResponseItem = ICRC7.RevokeCollectionResponseItem;
type TokenApproval = ICRC7.TokenApproval;
type CollectionApproval = ICRC7.CollectionApproval;
stable var init_msg = _init_msg; //preserves original initialization;
stable var icrc7_migration_state = ICRC7.init(ICRC7.initialState() , #v0_1_0(#id), switch(_args.icrc7_args){
case(null){
?{
symbol = ?"TST";
name = ?"Test NFT";
description = ?"A Test Collection";
logo = ?"https://www.icpscan.co/img/motoko.jpeg";
supply_cap = null;
total_supply = 0;
max_approvals_per_token_or_collection = ?10;
max_query_batch_size = ?100;
max_update_batch_size = ?100;
default_take_value = ?1000;
max_take_value = ?10000;
max_revoke_approvals = ?100;
max_memo_size = ?512;
deployer = init_msg.caller;
} : ICRC7.InitArgs;
};
case(?val) ?val;
}, init_msg.caller);
let #v0_1_0(#data(icrc7_state_current)) = icrc7_migration_state;
private var _icrc7 : ?ICRC7.ICRC7 = null;
private func get_icrc7_state() : ICRC7.CurrentState {
return icrc7_state_current;
};
private func get_icrc7_environment() : ICRC7.Environment{
{
canister = get_canister;
get_time = get_time;
refresh_state = get_icrc7_state;
log = ?addLog;
ledger = ?{
add_ledger_transaction = add_trx;
};
};
};
func icrc7() : ICRC7.ICRC7 {
switch(_icrc7){
case(null){
let initclass : ICRC7.ICRC7 = ICRC7.ICRC7(?icrc7_migration_state, Principal.fromActor(this), get_icrc7_environment());
_icrc7 := ?initclass;
initclass;
};
case(?val) val;
};
};
stable var log = SB.init<LogEntry>();
private func addLog(entry : LogEntry){
//note: Implement your own logging solution like canister geek. This will not scale without an implemented logging strategy
SB.add(log, entry);
};
//we will use a stable log for this example, but encourage the use of ICRC3 in a full implementation. see https://github.com/panindustrial/FullNFT.mo
stable var trx_log = Vec.new<ICRC7.Value>();
func add_trx(entry : Value) : Nat {
Vec.add(trx_log, entry);
return (Vec.size(trx_log) - 1);
};
private var canister_principal : ?Principal = null;
private func get_canister() : Principal {
switch (canister_principal) {
case (null) {
canister_principal := ?Principal.fromActor(this);
Principal.fromActor(this);
};
case (?val) {
val;
};
};
};
private func get_time() : Int{
//note: you may want to implement a testing framework where you can set this time manually
/* switch(state_current.testing.time_mode){
case(#test){
state_current.testing.test_time;
};
case(#standard){
Time.now();
};
}; */
Time.now();
};
public query func icrc_symbol() : async Text {
return switch(icrc7().get_ledger_info().symbol){
case(?val) val;
case(null) "";
};
};
public query func icrc_name() : async Text {
return switch(icrc7().get_ledger_info().name){
case(?val) val;
case(null) "";
};
};
public query func icrc7_description() : async ?Text {
return icrc7().get_ledger_info().description;
};
public query func icrc7_logo() : async ?Text {
return icrc7().get_ledger_info().logo;
};
public query func icrc7_max_memo_size() : async ?Nat {
return icrc7().get_ledger_info().max_memo_size;
};
public query func icrc7_total_supply() : async Nat {
return icrc7().get_ledger_info().total_supply;
};
public query func icrc7_supply_cap() : async ?Nat {
return icrc7().get_ledger_info().supply_cap;
};
public query func icrc7_max_approvals_per_token_or_collection() : async ?Nat {
return icrc7().get_ledger_info().max_approvals_per_token_or_collection;
};
public query func icrc7_max_query_batch_size() : async ?Nat {
return icrc7().get_ledger_info().max_query_batch_size;
};
public query func icrc7_max_update_batch_size() : async ?Nat {
return icrc7().get_ledger_info().max_update_batch_size;
};
public query func icrc7_default_take_value() : async ?Nat {
return icrc7().get_ledger_info().default_take_value;
};
public query func icrc7_max_take_value() : async ?Nat {
return icrc7().get_ledger_info().max_take_value;
};
public query func icrc7_max_revoke_approvals() : async ?Nat {
return icrc7().get_ledger_info().max_revoke_approvals;
};
public query func icrc7_collection_metadata() : async {metadata: [(Text, Value)]} {
let ledger_info = icrc7().get_ledger_info();
let results = Vec.new<(Text, Value)>();
switch(ledger_info.symbol){
case(?val) Vec.add(results, ("icrc7:symbol", #Text(val)));
case(null) {};
};
switch(ledger_info.name){
case(?val) Vec.add(results, ("icrc7:name", #Text(val)));
case(null) {};
};
switch(ledger_info.description){
case(?val) Vec.add(results, ("icrc7:description", #Text(val)));
case(null) {};
};
switch(ledger_info.logo){
case(?val) Vec.add(results, ("icrc7:logo", #Text(val)));
case(null) {};
};
Vec.add(results, ("icrc7:total_supply", #Nat(ledger_info.total_supply)));
switch(ledger_info.supply_cap){
case(?val) Vec.add(results, ("icrc7:supply_cap", #Nat(val)));
case(null) {};
};
switch(ledger_info.max_approvals_per_token_or_collection){
case(?val) Vec.add(results,("icrc7:max_approvals_per_token_or_collection", #Nat(val)));
case(null) {};
};
switch(ledger_info.max_query_batch_size){
case(?val) Vec.add(results,("icrc7:max_query_batch_size", #Nat(val)));
case(null) {};
};
switch(ledger_info.max_update_batch_size){
case(?val) Vec.add(results, ("icrc7:max_update_batch_size", #Nat(val)));
case(null) {};
};
switch(ledger_info.default_take_value){
case(?val) Vec.add(results,("icrc7:default_take_value", #Nat(val)));
case(null) {};
};
switch(ledger_info.max_take_value){
case(?val) Vec.add(results,("icrc7:max_take_value", #Nat(val)));
case(null) {};
};
switch(ledger_info.max_revoke_approvals){
case(?val) Vec.add(results, ("icrc7:max_revoke_approvals", #Nat(val)));
case(null) {};
};
return {
metadata = Vec.toArray(results);
};
};
//todo: confirm the nullability of the NFT
public query func icrc7_token_metadata(token_ids: [Nat]) : async [(Nat, ?NFTMap)]{
switch(icrc7().get_token_infos_shared(token_ids)){
case(#ok(val)) val;
case(#err(err)) D.trap(err);
};
};
public query func icrc7_owner_of(token_ids: [Nat]) : async OwnerOfResponses {
switch( icrc7().get_token_owners(token_ids)){
case(#ok(val)) val;
case(#err(err)) D.trap(err);
};
};
public query func icrc7_balance_of(account: Account) : async Nat {
return icrc7().get_token_owners_tokens_count(account);
};
public query func icrc7_tokens(prev: ?Nat, take: ?Nat) : async [Nat] {
return icrc7().get_tokens_paginated(prev, take);
};
public query func icrc7_tokens_of(account: Account, prev: ?Nat, take: ?Nat) : async [Nat] {
return icrc7().get_tokens_of_paginated(account, prev, take);
};
public query func icrc7_is_approved(spender: Account, from_subaccount: ?Blob, token_id: Nat) : async Bool {
return icrc7().is_approved(spender, from_subaccount, token_id);
};
public query func icrc7_get_approvals(token_ids: [Nat], prev: ?TokenApproval, take: ?Nat32) : async [TokenApproval] {
switch(icrc7().get_token_approvals(token_ids, prev, take)){
case(#ok(val)) val;
case(#err(err)) D.trap(err);
};
};
public query func icrc7_get_collection_approvals(owner : Account, prev: ?CollectionApproval, take: ?Nat32) : async [CollectionApproval] {
switch(icrc7().get_collection_approvals(owner, prev, take)){
case(#ok(val)) val;
case(#err(err)) D.trap(err);
};
};
public query func icrc7_supported_standards() : async [{ name : Text; url : Text }] {
//todo: figure this out
return [{name = "ICRC-7"; url = "https://github.com/dfinity/ICRC/ICRCs/ICRC-7"}];
};
//Update calls
public shared(msg) func icrc7_approve(token_ids: [Nat], approval: ApprovalInfo) : async ApprovalResponses {
switch(icrc7().approve_transfers(get_icrc7_environment(), msg.caller, token_ids, approval)){
case(#ok(val)) val;
case(#err(err)) D.trap(err);
};
};
public shared(msg) func icrc7_approve_collection(approval: ApprovalInfo) : async ApprovalCollectionResponse {
let result : ApprovalResponse = switch(icrc7().approve_collection(get_icrc7_environment(), msg.caller, approval)){
case(#ok(val)) val;
case(#err(err)) D.trap(err);
};
switch(result){
case(#Err(val)){
return (#Err(icrc7().TokenErrorToCollectionError(val)));
};
case(#Ok(val)){
return #Ok(val);
};
};
};
public shared(msg) func icrc7_transfer(args: TransferArgs) : async [(Nat, TransferResponse)] {
switch(icrc7().transfer(get_icrc7_environment(), msg.caller, args)){
case(#ok(val)) val;
case(#err(err)) D.trap(err);
};
};
public shared(msg) func icrc7_revoke_token_approvals(args: RevokeTokensArgs) : async [RevokeTokensResponseItem] {
switch(icrc7().revoke_token_approvals(get_icrc7_environment(), msg.caller, args)){
case(#ok(val)) val;
case(#err(err)) D.trap(err);
};
};
public shared(msg) func icrc7_revoke_collection_approvals(args: RevokeCollectionArgs) : async [RevokeCollectionResponseItem] {
switch(icrc7().revoke_collection_approvals(get_icrc7_environment(), msg.caller, args)){
case(#ok(val)) val;
case(#err(err)) D.trap(err);
};
};
};
Hello,
we would like to participate in this Bounty.
In Noku/Original we developed in June a Motoko version of the ICRC-7 standard.
You can see the code at our github page: noku-team/icrc7_motoko
We already opened a pull request to the awesome-motoko repository ( motoko-unofficial/awesome-motoko/pull/31 )
There are already a few collections that use this code, but the first one is Casino Lugano’s NFT Collection
Hi,
@ pramitgaha is your current implementation still WIP or it is production ready ? ( GitHub - rustacean1/icrc7: Icrc7 implementation in Rust )
If not finished, do you need help on it?
Gautier
Same question, does someone have an update on the state of this implementation?