From 50f6266cc2c19edb6a4d3b21eb5a130b466684fd Mon Sep 17 00:00:00 2001 From: bogwar <51327868+bogwar@users.noreply.github.com> Date: Tue, 3 Sep 2024 12:49:33 +0200 Subject: [PATCH 01/16] list approval ICRC, initial commit --- ICRCs/ICRC-xx | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 ICRCs/ICRC-xx diff --git a/ICRCs/ICRC-xx b/ICRCs/ICRC-xx new file mode 100644 index 0000000..e69de29 From 8c85abad0d7ce90bfdb5ee23238695fc0ea0d223 Mon Sep 17 00:00:00 2001 From: bogwar <51327868+bogwar@users.noreply.github.com> Date: Tue, 3 Sep 2024 12:51:34 +0200 Subject: [PATCH 02/16] new icrc number --- ICRCs/ICRC-103 | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 ICRCs/ICRC-103 diff --git a/ICRCs/ICRC-103 b/ICRCs/ICRC-103 new file mode 100644 index 0000000..e69de29 From b2776d1f146ced68e5993dd434f0016800df3be2 Mon Sep 17 00:00:00 2001 From: bogwar <51327868+bogwar@users.noreply.github.com> Date: Wed, 11 Sep 2024 11:01:18 +0200 Subject: [PATCH 03/16] new semantics --- ICRCs/ICRC-103 | 0 ICRCs/ICRC-103/ICRC-103.md | 90 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) delete mode 100644 ICRCs/ICRC-103 create mode 100644 ICRCs/ICRC-103/ICRC-103.md diff --git a/ICRCs/ICRC-103 b/ICRCs/ICRC-103 deleted file mode 100644 index e69de29..0000000 diff --git a/ICRCs/ICRC-103/ICRC-103.md b/ICRCs/ICRC-103/ICRC-103.md new file mode 100644 index 0000000..9f944aa --- /dev/null +++ b/ICRCs/ICRC-103/ICRC-103.md @@ -0,0 +1,90 @@ +| Status | +|:------:| +|Draft| + +# ICRC-191: Enhanced Allowance Query Mechanism with Pagination + +## 1. Introduction + +Although calls to the `icrc2_approve` and `icrc2_transfer_from` methods are recorded in the ledger, it is not possible to determine the allowances that are in effect at some point in time, except by traversing the entire ledger. This standard introduced an endpoint which will return this information thus making the management of allowances feasible. + +ICRC-191 is an extension of the ICRC-2 standard. +ICRC-191 specifies a way to list outstanding allowances. + + +## 2. Metadata + +A ledger that implements ICRC-191 MUST must include `record {name = "ICRC-191"; url = "https://github.com/dfinity/ICRC-1/standards/ICRC-191"}` as part of the output of `icrc1_supported_standards`. + +The endpoint introduced in this standard operates in two ways. In the public version any principal can obtain the outstanding allowances of any other principal. In the private version, the allowances returned by the endpoint must have been issued by the caller (i.e. the caller is the principal controlling the source account of an allowance.) +Which version of the standard is implemented by a ledger is specified through metadata which can be retrieved using `icrc1_metadata`. + +A ledger that implements ICRC-191 MUST return metadata `icrc191:public_allowances` of type Text (optional). The possible values are "true" if the allowance data is public and "false" otherwise. + + +## 3. Methods + +Some of the types used are shared with standards ICRC-1 and ICRC-2; we restate their definition for completeness. + +```candid +icrc191_list_allowances : (ListAllowancesArgs) -> (ListAllowancesResult) quey + +type ListAllowancesArgs = record { + from_account : opt Account; + prev_spender : opt Account; + take : opt nat; +} + +ListAllowanceResult = vec record { + from_account : Account; + to_spender : Account; + allowance : Allowance; +} + +type Account = record { + owner : principal; + subaccount : opt blob; +}; + +type Allowance = record { + allowance : nat; + expires_at : opt nat64; +} +``` + +The endpoint returns up to `take` allowances of the from_account.owner, starting with the allowance between `from_account` and `to_account`. + + +## 4. Semantics + +Outstanding allowances, as specified in the ICRC-2 standard, are represented as a map from pairs of accounts to allowances. To specify the behavior of `icrc191_list_allowances`, the set of pairs `(Account, Account)` is ordered lexicographically. Let `first_principal` be the lexicographically first principal, and `first_subaccount` be the lexicographically first subaccount (the default subaccount, i.e., the all-0 32-byte string). Let `caller_principal` be the principal of the caller. + +The `icrc191_list_allowances` method behaves as follows: + +* If `from_account` is not provided, it is instantiated as `Account{caller_principal, first_subaccount}`. +* If `from_account.subaccount` is not provided, it is instantiated with `first_subaccount`. +* If `prev_spender` is not provided, it is instantiated with `Account{first_principal, first_subaccount}`. + +If the ledger implements the private version of the standard, then the endpoint returns the empty list if `from_account.owner ≠ caller_principal`. + +Otherwise, the endpoint returns a list of records of the form `(account_1, account_2, allowance)` in lexicographic order, starting with the allowance of `(from_account, prev_spender)` (if present), and where `account_1.owner = from_account.owner`. The list is limited to at most `take` entries, or some maximum number of entries (that is an internal constant of the ledger). + + + +## 5. Example Using Symbolic Values + +Assume that allowances stored at some point by the ledger are, in lexicographic order: + +- A1 = ((p0,s0), (p1,s1), a1) +- A2 = ((p0,s0), (p2,s2), a2) +- A3 = ((p0,s1), (p3,s3), a3) +- A4 = ((p1,s1), (p4,s4), a4) +- A5 = ((p1,s2), (p5,s5), a5) + +Then: + +- If `p0` calls the list allowances endpoint, with `from_account = (p0, s0)`, `prev_spender = None` and `take=4` the endpoint returns ``(A1, A2, A3)``, i.e. the endpoint only returns allowances of accounts belonging to `p0`. It is limited to allowances of `p0`, but not only to those having `(p0,s0)` as source of the allowance. + +- If `p0` calls the list allowances endpoint with `from_account = (p1,s0)`, `p0 ≠ p1`, and the ledger implements the private version of the endpoint, then the endpoint returns the empty array. + +- If `p0` calls the list allowances endpoint with `from_account = (p0,s0)`, `prev_spender = (p2,s)` for some `s1 < s < s2`, and `take = 2` the endpoint returns `(A2, A3)`. Since `(p2,s)` is not in the list, the allowances returned start with the first existing allowance between a pair of accounts greater than `(from_account, prev_spender)`. From 2e5b23d6a0a25d9877f904987b37ccd147212a52 Mon Sep 17 00:00:00 2001 From: bogwar <51327868+bogwar@users.noreply.github.com> Date: Mon, 16 Sep 2024 16:44:19 +0200 Subject: [PATCH 04/16] new semantics --- ICRCs/ICRC-103/ICRC-103.md | 45 ++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/ICRCs/ICRC-103/ICRC-103.md b/ICRCs/ICRC-103/ICRC-103.md index 9f944aa..d81de81 100644 --- a/ICRCs/ICRC-103/ICRC-103.md +++ b/ICRCs/ICRC-103/ICRC-103.md @@ -6,7 +6,7 @@ ## 1. Introduction -Although calls to the `icrc2_approve` and `icrc2_transfer_from` methods are recorded in the ledger, it is not possible to determine the allowances that are in effect at some point in time, except by traversing the entire ledger. This standard introduced an endpoint which will return this information thus making the management of allowances feasible. +Although calls to the `icrc2_approve` and `icrc2_transfer_from` methods are recorded in the ledger, it is not possible to determine the allowances that are in effect at some point in time, except by traversing the entire ledger. This standard introduces an endpoint which will return this information thus making the management of allowances feasible. ICRC-191 is an extension of the ICRC-2 standard. ICRC-191 specifies a way to list outstanding allowances. @@ -14,7 +14,7 @@ ICRC-191 specifies a way to list outstanding allowances. ## 2. Metadata -A ledger that implements ICRC-191 MUST must include `record {name = "ICRC-191"; url = "https://github.com/dfinity/ICRC-1/standards/ICRC-191"}` as part of the output of `icrc1_supported_standards`. +A ledger that implements ICRC-191 MUST include `record {name = "ICRC-191"; url = "https://github.com/dfinity/ICRC-1/standards/ICRC-191"}` as part of the output of `icrc1_supported_standards`. The endpoint introduced in this standard operates in two ways. In the public version any principal can obtain the outstanding allowances of any other principal. In the private version, the allowances returned by the endpoint must have been issued by the caller (i.e. the caller is the principal controlling the source account of an allowance.) Which version of the standard is implemented by a ledger is specified through metadata which can be retrieved using `icrc1_metadata`. @@ -27,7 +27,7 @@ A ledger that implements ICRC-191 MUST return metadata `icrc191:public_allowance Some of the types used are shared with standards ICRC-1 and ICRC-2; we restate their definition for completeness. ```candid -icrc191_list_allowances : (ListAllowancesArgs) -> (ListAllowancesResult) quey +icrc191_list_allowances : (ListAllowancesArgs) -> (ListAllowancesResult) query type ListAllowancesArgs = record { from_account : opt Account; @@ -57,34 +57,47 @@ The endpoint returns up to `take` allowances of the from_account.owner, starting ## 4. Semantics -Outstanding allowances, as specified in the ICRC-2 standard, are represented as a map from pairs of accounts to allowances. To specify the behavior of `icrc191_list_allowances`, the set of pairs `(Account, Account)` is ordered lexicographically. Let `first_principal` be the lexicographically first principal, and `first_subaccount` be the lexicographically first subaccount (the default subaccount, i.e., the all-0 32-byte string). Let `caller_principal` be the principal of the caller. +Outstanding allowances, as specified in the ICRC-2 standard, are represented as a map from pairs of accounts to allowances. To specify the behavior of `icrc191_list_allowances`, the set of pairs `(Account, Account)` is ordered lexicographically. Let `first_subaccount` be the lexicographically first subaccount (the default subaccount, i.e., the all-0 32-byte string). Let `caller_principal` be the principal of the caller. The `icrc191_list_allowances` method behaves as follows: * If `from_account` is not provided, it is instantiated as `Account{caller_principal, first_subaccount}`. * If `from_account.subaccount` is not provided, it is instantiated with `first_subaccount`. -* If `prev_spender` is not provided, it is instantiated with `Account{first_principal, first_subaccount}`. If the ledger implements the private version of the standard, then the endpoint returns the empty list if `from_account.owner ≠ caller_principal`. -Otherwise, the endpoint returns a list of records of the form `(account_1, account_2, allowance)` in lexicographic order, starting with the allowance of `(from_account, prev_spender)` (if present), and where `account_1.owner = from_account.owner`. The list is limited to at most `take` entries, or some maximum number of entries (that is an internal constant of the ledger). - +Otherwise, the endpoint returns a list of records of the form `(account_1, account_2, allowance)` in lexicographic order, with `account_1.owner = from_account.owner`. + * If `prev_spender` is provided the list starts with the allowance immediately succeeding `(from_account, prev_spender)`. +* If `prev_spender` is not provided the list starts with the first allowance from `from_subaccount`. +The list is limited to at most `take` entries or a maximum number of entries (which is an internal constant of the ledger). ## 5. Example Using Symbolic Values -Assume that allowances stored at some point by the ledger are, in lexicographic order: +Assume that the ledger stores the following allowances, listed in lexicographic order: -- A1 = ((p0,s0), (p1,s1), a1) -- A2 = ((p0,s0), (p2,s2), a2) -- A3 = ((p0,s1), (p3,s3), a3) -- A4 = ((p1,s1), (p4,s4), a4) -- A5 = ((p1,s2), (p5,s5), a5) +- **A1** = `((p0, s0), (p1, s1), a1)` +- **A2** = `((p0, s0), (p2, s2), a2)` +- **A3** = `((p0, s1), (p3, s3), a3)` +- **A4** = `((p1, s1), (p4, s4), a4)` +- **A5** = `((p1, s2), (p5, s5), a5)` Then: -- If `p0` calls the list allowances endpoint, with `from_account = (p0, s0)`, `prev_spender = None` and `take=4` the endpoint returns ``(A1, A2, A3)``, i.e. the endpoint only returns allowances of accounts belonging to `p0`. It is limited to allowances of `p0`, but not only to those having `(p0,s0)` as source of the allowance. +1. **Case 1: `prev_spender` is not provided** + - If `p0` calls the list allowances endpoint with `from_account = (p0, s0)`, `prev_spender = None`, and `take = 4`, the endpoint returns `(A1, A2, A3)`. + - Since `prev_spender` is not provided, the list starts with the first allowance from `from_account = (p0, s0)`. + - The endpoint only returns allowances for `p0`, but it is not restricted to just those originating from `(p0, s0)`. + +2. **Case 2: `prev_spender` is provided** + - If `p0` calls the list allowances endpoint with `from_account = (p0, s0)`, `prev_spender = (p1, s1)`, and `take = 3`, the endpoint returns `(A2, A3)`. + - Since `prev_spender = (p1, s1)` is provided, the list starts with the first allowance immediately succeeding `(p0, s0), (p1, s1)` in lexicographic order, which is `(p0, s0), (p2, s2)` (A2). + - The returned list contains only allowances where the `owner` of `account_1` is `p0`, which matches the `from_account.owner`. -- If `p0` calls the list allowances endpoint with `from_account = (p1,s0)`, `p0 ≠ p1`, and the ledger implements the private version of the endpoint, then the endpoint returns the empty array. +3. **Case 3: Private version of the standard** + - If `p0` calls the list allowances endpoint with `from_account = (p1, s0)` (`p0 ≠ p1`), and the ledger implements the private version of the standard, the endpoint returns an empty list. + - Since `from_account.owner ≠ caller_principal` and the ledger implements the private version, no allowances are returned. -- If `p0` calls the list allowances endpoint with `from_account = (p0,s0)`, `prev_spender = (p2,s)` for some `s1 < s < s2`, and `take = 2` the endpoint returns `(A2, A3)`. Since `(p2,s)` is not in the list, the allowances returned start with the first existing allowance between a pair of accounts greater than `(from_account, prev_spender)`. +4. **Case 4: `prev_spender` is not in the list** + - If `p0` calls the list allowances endpoint with `from_account = (p0, s0)`, `prev_spender = (p2, s)` for some `s1 < s < s2`, and `take = 2`, the endpoint returns `(A2, A3)`. + - Since `(p0, s0), (p2, s)` is not in the list, the allowances start with the first available pair greater than `(p0, s0), (p2, s)`—in this case, `(p0, s0), (p2, s2)` (A2). From 710da86386d5916e5c1cbd1cb095232b6bdef50a Mon Sep 17 00:00:00 2001 From: bogwar <51327868+bogwar@users.noreply.github.com> Date: Mon, 16 Sep 2024 16:49:08 +0200 Subject: [PATCH 05/16] fix --- ICRCs/ICRC-103/ICRC-103.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ICRCs/ICRC-103/ICRC-103.md b/ICRCs/ICRC-103/ICRC-103.md index d81de81..4ef2a90 100644 --- a/ICRCs/ICRC-103/ICRC-103.md +++ b/ICRCs/ICRC-103/ICRC-103.md @@ -68,7 +68,7 @@ If the ledger implements the private version of the standard, then the endpoint Otherwise, the endpoint returns a list of records of the form `(account_1, account_2, allowance)` in lexicographic order, with `account_1.owner = from_account.owner`. * If `prev_spender` is provided the list starts with the allowance immediately succeeding `(from_account, prev_spender)`. -* If `prev_spender` is not provided the list starts with the first allowance from `from_subaccount`. + * If `prev_spender` is not provided the list starts with the first allowance from `from_account`. The list is limited to at most `take` entries or a maximum number of entries (which is an internal constant of the ledger). From d3c5c8b5343a165f709cd78d995e607e2f366c23 Mon Sep 17 00:00:00 2001 From: bogwar <51327868+bogwar@users.noreply.github.com> Date: Mon, 23 Sep 2024 16:00:00 +0200 Subject: [PATCH 06/16] implemented Thomas' suggestions --- ICRCs/ICRC-103/ICRC-103.md | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/ICRCs/ICRC-103/ICRC-103.md b/ICRCs/ICRC-103/ICRC-103.md index 4ef2a90..a042500 100644 --- a/ICRCs/ICRC-103/ICRC-103.md +++ b/ICRCs/ICRC-103/ICRC-103.md @@ -2,32 +2,35 @@ |:------:| |Draft| -# ICRC-191: Enhanced Allowance Query Mechanism with Pagination +# ICRC-103: Enhanced Allowance Query Mechanism with Pagination ## 1. Introduction Although calls to the `icrc2_approve` and `icrc2_transfer_from` methods are recorded in the ledger, it is not possible to determine the allowances that are in effect at some point in time, except by traversing the entire ledger. This standard introduces an endpoint which will return this information thus making the management of allowances feasible. -ICRC-191 is an extension of the ICRC-2 standard. -ICRC-191 specifies a way to list outstanding allowances. +ICRC-103 is an extension of the ICRC-2 standard. +ICRC-103 specifies a way to list outstanding allowances. ## 2. Metadata -A ledger that implements ICRC-191 MUST include `record {name = "ICRC-191"; url = "https://github.com/dfinity/ICRC-1/standards/ICRC-191"}` as part of the output of `icrc1_supported_standards`. +A ledger that implements ICRC-103 MUST include `record {name = "ICRC-103"; url = "https://github.com/dfinity/ICRC-1/standards/ICRC-103"}` as part of the output of `icrc1_supported_standards`. The endpoint introduced in this standard operates in two ways. In the public version any principal can obtain the outstanding allowances of any other principal. In the private version, the allowances returned by the endpoint must have been issued by the caller (i.e. the caller is the principal controlling the source account of an allowance.) Which version of the standard is implemented by a ledger is specified through metadata which can be retrieved using `icrc1_metadata`. -A ledger that implements ICRC-191 MUST return metadata `icrc191:public_allowances` of type Text (optional). The possible values are "true" if the allowance data is public and "false" otherwise. +A ledger that implements ICRC-103 MUST return metadata `icrc103:public_allowances` of type `text`. The possible values are "true" if the allowance data is public and "false" otherwise. +The number of allowances returned by the ledger is limited by an implementation-specific maximum, which is specified through ledger metadata. + +A ledger that implements ICRC-103 MUST return metadata `icrc103:max_returned_allowances` of type `nat`, indicating the precise maximum number of allowances the ledger will return in response to a query. ## 3. Methods Some of the types used are shared with standards ICRC-1 and ICRC-2; we restate their definition for completeness. ```candid -icrc191_list_allowances : (ListAllowancesArgs) -> (ListAllowancesResult) query +icrc103_list_allowances : (ListAllowancesArgs) -> (ListAllowancesResult) query type ListAllowancesArgs = record { from_account : opt Account; @@ -52,14 +55,14 @@ type Allowance = record { } ``` -The endpoint returns up to `take` allowances of the from_account.owner, starting with the allowance between `from_account` and `to_account`. +The endpoint returns up to allowances of the from_account.owner, starting with the allowance between `from_account` and `to_account`. ## 4. Semantics -Outstanding allowances, as specified in the ICRC-2 standard, are represented as a map from pairs of accounts to allowances. To specify the behavior of `icrc191_list_allowances`, the set of pairs `(Account, Account)` is ordered lexicographically. Let `first_subaccount` be the lexicographically first subaccount (the default subaccount, i.e., the all-0 32-byte string). Let `caller_principal` be the principal of the caller. +Outstanding allowances, as specified in the ICRC-2 standard, are represented as a map from pairs of accounts to allowances. To specify the behavior of `icrc103_list_allowances`, the set of pairs `(Account, Account)` is ordered lexicographically. Let `first_subaccount` be the lexicographically first subaccount (the default subaccount, i.e., the all-0 32-byte string). Let `caller_principal` be the principal of the caller. -The `icrc191_list_allowances` method behaves as follows: +The `icrc103_list_allowances` method behaves as follows: * If `from_account` is not provided, it is instantiated as `Account{caller_principal, first_subaccount}`. * If `from_account.subaccount` is not provided, it is instantiated with `first_subaccount`. @@ -70,7 +73,7 @@ Otherwise, the endpoint returns a list of records of the form `(account_1, accou * If `prev_spender` is provided the list starts with the allowance immediately succeeding `(from_account, prev_spender)`. * If `prev_spender` is not provided the list starts with the first allowance from `from_account`. -The list is limited to at most `take` entries or a maximum number of entries (which is an internal constant of the ledger). +The list is limited to at most `take` entries but not more than the maximum number of entries specified in `icrc103:max_returned_allowances`. ## 5. Example Using Symbolic Values @@ -82,6 +85,8 @@ Assume that the ledger stores the following allowances, listed in lexicographic - **A4** = `((p1, s1), (p4, s4), a4)` - **A5** = `((p1, s2), (p5, s5), a5)` +Each entry in the list is of the type `from_account: (,), spender: (), )` + Then: 1. **Case 1: `prev_spender` is not provided** From 008be7641961289589536100b010e8e0bcbc6ecb Mon Sep 17 00:00:00 2001 From: bogwar <51327868+bogwar@users.noreply.github.com> Date: Mon, 23 Sep 2024 17:40:02 +0200 Subject: [PATCH 07/16] icrc103_collection_metadata and small improvements --- ICRCs/ICRC-103/ICRC-103.md | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/ICRCs/ICRC-103/ICRC-103.md b/ICRCs/ICRC-103/ICRC-103.md index a042500..70e91c2 100644 --- a/ICRCs/ICRC-103/ICRC-103.md +++ b/ICRCs/ICRC-103/ICRC-103.md @@ -21,9 +21,11 @@ Which version of the standard is implemented by a ledger is specified through me A ledger that implements ICRC-103 MUST return metadata `icrc103:public_allowances` of type `text`. The possible values are "true" if the allowance data is public and "false" otherwise. -The number of allowances returned by the ledger is limited by an implementation-specific maximum, which is specified through ledger metadata. +The number of allowances that the ledger can return in response to a query is limited by an implementation-specific maximum, specified through the `icrc103_max_take_value` metadata. + +A ledger that implements ICRC-103 MUST return metadata `icrc103:max_take_value` of type `nat`, indicating the precise maximum number of allowances the ledger will return in response to a query. + -A ledger that implements ICRC-103 MUST return metadata `icrc103:max_returned_allowances` of type `nat`, indicating the precise maximum number of allowances the ledger will return in response to a query. ## 3. Methods @@ -38,7 +40,7 @@ type ListAllowancesArgs = record { take : opt nat; } -ListAllowanceResult = vec record { +type ListAllowancesResult = vec record { from_account : Account; to_spender : Account; allowance : Allowance; @@ -55,8 +57,23 @@ type Allowance = record { } ``` -The endpoint returns up to allowances of the from_account.owner, starting with the allowance between `from_account` and `to_account`. +The endpoint returns up to `take` allowances belonging to from_account.owner, starting with the allowance between `from_account` and `prev_account`. + +The `icrc103_collection_metadata` endpoint allows fetching all metadata entries related to this standard. + +```candid +icrc103_collection_metadata : () -> (vec record {text; Value}) query; + +type Value = variant { + Blob : blob; + Text : text; + Nat : nat; + Int : int; + Array ; int; + Map : vec record { text; Value}; +} +``` ## 4. Semantics @@ -67,13 +84,13 @@ The `icrc103_list_allowances` method behaves as follows: * If `from_account` is not provided, it is instantiated as `Account{caller_principal, first_subaccount}`. * If `from_account.subaccount` is not provided, it is instantiated with `first_subaccount`. -If the ledger implements the private version of the standard, then the endpoint returns the empty list if `from_account.owner ≠ caller_principal`. +If the ledger implements the private version of the standard, the endpoint returns an empty list when `from_account.owner ≠ caller_principal`. Otherwise, the endpoint returns a list of records of the form `(account_1, account_2, allowance)` in lexicographic order, with `account_1.owner = from_account.owner`. * If `prev_spender` is provided the list starts with the allowance immediately succeeding `(from_account, prev_spender)`. * If `prev_spender` is not provided the list starts with the first allowance from `from_account`. -The list is limited to at most `take` entries but not more than the maximum number of entries specified in `icrc103:max_returned_allowances`. +The list is limited to at most `take` entries but not more than the maximum number of entries specified in `icrc103:max_take_value`. ## 5. Example Using Symbolic Values From e15376a6ed6189544d05b0e99bea35036e170b47 Mon Sep 17 00:00:00 2001 From: bogwar <51327868+bogwar@users.noreply.github.com> Date: Mon, 23 Sep 2024 17:45:34 +0200 Subject: [PATCH 08/16] typo --- ICRCs/ICRC-103/ICRC-103.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ICRCs/ICRC-103/ICRC-103.md b/ICRCs/ICRC-103/ICRC-103.md index 70e91c2..c3f5a92 100644 --- a/ICRCs/ICRC-103/ICRC-103.md +++ b/ICRCs/ICRC-103/ICRC-103.md @@ -102,7 +102,7 @@ Assume that the ledger stores the following allowances, listed in lexicographic - **A4** = `((p1, s1), (p4, s4), a4)` - **A5** = `((p1, s2), (p5, s5), a5)` -Each entry in the list is of the type `from_account: (,), spender: (), )` +Each entry in the list is of the type `(from_account: (,), spender: (), )` Then: From 6c20b71835f201d81af13e98be4c90841793bab1 Mon Sep 17 00:00:00 2001 From: bogwar <51327868+bogwar@users.noreply.github.com> Date: Tue, 24 Sep 2024 10:09:58 +0200 Subject: [PATCH 09/16] latest Thomas' suggestion + clarifications --- ICRCs/ICRC-103/ICRC-103.md | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/ICRCs/ICRC-103/ICRC-103.md b/ICRCs/ICRC-103/ICRC-103.md index c3f5a92..ab5d3e1 100644 --- a/ICRCs/ICRC-103/ICRC-103.md +++ b/ICRCs/ICRC-103/ICRC-103.md @@ -17,15 +17,15 @@ ICRC-103 specifies a way to list outstanding allowances. A ledger that implements ICRC-103 MUST include `record {name = "ICRC-103"; url = "https://github.com/dfinity/ICRC-1/standards/ICRC-103"}` as part of the output of `icrc1_supported_standards`. The endpoint introduced in this standard operates in two ways. In the public version any principal can obtain the outstanding allowances of any other principal. In the private version, the allowances returned by the endpoint must have been issued by the caller (i.e. the caller is the principal controlling the source account of an allowance.) -Which version of the standard is implemented by a ledger is specified through metadata which can be retrieved using `icrc1_metadata`. +Which version of the standard is implemented by a ledger is specified through the `icrc103:public_allowances` metadata. -A ledger that implements ICRC-103 MUST return metadata `icrc103:public_allowances` of type `text`. The possible values are "true" if the allowance data is public and "false" otherwise. +A ledger that implements ICRC-103 MUST return the metadata entry `icrc103:public_allowances` of type `text`. The possible values are "true" if the allowance data is public and "false" otherwise. -The number of allowances that the ledger can return in response to a query is limited by an implementation-specific maximum, specified through the `icrc103_max_take_value` metadata. - -A ledger that implements ICRC-103 MUST return metadata `icrc103:max_take_value` of type `nat`, indicating the precise maximum number of allowances the ledger will return in response to a query. +The number of allowances that the ledger can return in response to a query is limited by an implementation-specific maximum, specified through the `icrc103:max_take_value` metadata. +A ledger that implements ICRC-103 MUST return the metadata entry `icrc103:max_take_value` of type `nat`, indicating the precise maximum number of allowances the ledger will return in response to a query. +Metadata entries can be retrieved using method `icrc1_metadata` defined in the ICRC-1 standard as well as `icrc103_collection_metadata` defined below. ## 3. Methods @@ -43,7 +43,8 @@ type ListAllowancesArgs = record { type ListAllowancesResult = vec record { from_account : Account; to_spender : Account; - allowance : Allowance; + allowance : nat; + expires_at : opt nat64; } type Account = record { @@ -51,13 +52,9 @@ type Account = record { subaccount : opt blob; }; -type Allowance = record { - allowance : nat; - expires_at : opt nat64; -} ``` -The endpoint returns up to `take` allowances belonging to from_account.owner, starting with the allowance between `from_account` and `prev_account`. +The endpoint returns up to `take` allowances belonging to from_account.owner, starting with the allowance between `from_account` and `prev_spender`. The `icrc103_collection_metadata` endpoint allows fetching all metadata entries related to this standard. @@ -70,7 +67,7 @@ type Value = variant { Text : text; Nat : nat; Int : int; - Array ; int; + Array : int; Map : vec record { text; Value}; } ``` @@ -94,7 +91,7 @@ The list is limited to at most `take` entries but not more than the maximum numb ## 5. Example Using Symbolic Values -Assume that the ledger stores the following allowances, listed in lexicographic order: +Assume that the ledger stores the following allowances, listed in lexicographic order. Below, `p0,p1,...,p5` are some arbitrary principals, `s0` is the default subaccount, `s1,s2,..,s5` are subacounts, and `a1,a2,...,a5` are allowances (the associated expiration is omitted). - **A1** = `((p0, s0), (p1, s1), a1)` - **A2** = `((p0, s0), (p2, s2), a2)` @@ -102,7 +99,7 @@ Assume that the ledger stores the following allowances, listed in lexicographic - **A4** = `((p1, s1), (p4, s4), a4)` - **A5** = `((p1, s2), (p5, s5), a5)` -Each entry in the list is of the type `(from_account: (,), spender: (), )` +Each entry in the list is of the type `(from_account: (,), to_spender: (), )` Then: From f4607842362cdbb152cf483aa58f8e9fe8bac056 Mon Sep 17 00:00:00 2001 From: bogwar <51327868+bogwar@users.noreply.github.com> Date: Tue, 24 Sep 2024 16:21:26 +0200 Subject: [PATCH 10/16] removed icrc103_collection_metadata --- ICRCs/ICRC-103/ICRC-103.md | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/ICRCs/ICRC-103/ICRC-103.md b/ICRCs/ICRC-103/ICRC-103.md index ab5d3e1..e9e1a65 100644 --- a/ICRCs/ICRC-103/ICRC-103.md +++ b/ICRCs/ICRC-103/ICRC-103.md @@ -25,7 +25,7 @@ The number of allowances that the ledger can return in response to a query is li A ledger that implements ICRC-103 MUST return the metadata entry `icrc103:max_take_value` of type `nat`, indicating the precise maximum number of allowances the ledger will return in response to a query. -Metadata entries can be retrieved using method `icrc1_metadata` defined in the ICRC-1 standard as well as `icrc103_collection_metadata` defined below. +Metadata entries can be retrieved using method `icrc1_metadata` defined by the ICRC-1 standard. ## 3. Methods @@ -56,21 +56,6 @@ type Account = record { The endpoint returns up to `take` allowances belonging to from_account.owner, starting with the allowance between `from_account` and `prev_spender`. -The `icrc103_collection_metadata` endpoint allows fetching all metadata entries related to this standard. - - -```candid -icrc103_collection_metadata : () -> (vec record {text; Value}) query; - -type Value = variant { - Blob : blob; - Text : text; - Nat : nat; - Int : int; - Array : int; - Map : vec record { text; Value}; -} -``` ## 4. Semantics From a352e8d6a4bbac0f806b75c9181bfdc07dd3d319 Mon Sep 17 00:00:00 2001 From: bogwar <51327868+bogwar@users.noreply.github.com> Date: Wed, 25 Sep 2024 17:14:09 +0200 Subject: [PATCH 11/16] new endpoint name & minor rewriting --- ICRCs/ICRC-103/ICRC-103.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/ICRCs/ICRC-103/ICRC-103.md b/ICRCs/ICRC-103/ICRC-103.md index e9e1a65..df62975 100644 --- a/ICRCs/ICRC-103/ICRC-103.md +++ b/ICRCs/ICRC-103/ICRC-103.md @@ -32,7 +32,7 @@ Metadata entries can be retrieved using method `icrc1_metadata` defined by the I Some of the types used are shared with standards ICRC-1 and ICRC-2; we restate their definition for completeness. ```candid -icrc103_list_allowances : (ListAllowancesArgs) -> (ListAllowancesResult) query +icrc103_get_allowances : (ListAllowancesArgs) -> (ListAllowancesResult) query type ListAllowancesArgs = record { from_account : opt Account; @@ -59,9 +59,9 @@ The endpoint returns up to `take` allowances belonging to from_account.owner, st ## 4. Semantics -Outstanding allowances, as specified in the ICRC-2 standard, are represented as a map from pairs of accounts to allowances. To specify the behavior of `icrc103_list_allowances`, the set of pairs `(Account, Account)` is ordered lexicographically. Let `first_subaccount` be the lexicographically first subaccount (the default subaccount, i.e., the all-0 32-byte string). Let `caller_principal` be the principal of the caller. +Outstanding allowances, as specified in the ICRC-2 standard, are represented as a map from pairs of accounts to allowances. To specify the behavior of `icrc103_get_allowances`, the set of pairs `(Account, Account)` is ordered lexicographically. Let `first_subaccount` be the lexicographically first subaccount (the default subaccount, i.e., the all-0 32-byte string). Let `caller_principal` be the principal of the caller. -The `icrc103_list_allowances` method behaves as follows: +The `icrc103_get_allowances` method behaves as follows: * If `from_account` is not provided, it is instantiated as `Account{caller_principal, first_subaccount}`. * If `from_account.subaccount` is not provided, it is instantiated with `first_subaccount`. @@ -88,10 +88,11 @@ Each entry in the list is of the type `(from_account: (,) Then: + 1. **Case 1: `prev_spender` is not provided** - If `p0` calls the list allowances endpoint with `from_account = (p0, s0)`, `prev_spender = None`, and `take = 4`, the endpoint returns `(A1, A2, A3)`. - Since `prev_spender` is not provided, the list starts with the first allowance from `from_account = (p0, s0)`. - - The endpoint only returns allowances for `p0`, but it is not restricted to just those originating from `(p0, s0)`. + - The endpoint returns allowances for `p0`, including those that do not necessarily originate from `(p0, s0)`. 2. **Case 2: `prev_spender` is provided** - If `p0` calls the list allowances endpoint with `from_account = (p0, s0)`, `prev_spender = (p1, s1)`, and `take = 3`, the endpoint returns `(A2, A3)`. From d8f73b9b8cf3a8efd746f07c726d09cdd74a44ea Mon Sep 17 00:00:00 2001 From: bogwar <51327868+bogwar@users.noreply.github.com> Date: Thu, 10 Oct 2024 10:51:49 +0200 Subject: [PATCH 12/16] clarification of the size of the response & criteria for listing termination --- ICRCs/ICRC-103/ICRC-103.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ICRCs/ICRC-103/ICRC-103.md b/ICRCs/ICRC-103/ICRC-103.md index df62975..47ebeb8 100644 --- a/ICRCs/ICRC-103/ICRC-103.md +++ b/ICRCs/ICRC-103/ICRC-103.md @@ -72,7 +72,9 @@ Otherwise, the endpoint returns a list of records of the form `(account_1, accou * If `prev_spender` is provided the list starts with the allowance immediately succeeding `(from_account, prev_spender)`. * If `prev_spender` is not provided the list starts with the first allowance from `from_account`. -The list is limited to at most `take` entries but not more than the maximum number of entries specified in `icrc103:max_take_value`. +The list includes up to `take` entries if `take` is provided, but it cannot exceed the maximum number specified by the `icrc103:max_take_value` metadata. If take is not provided, the ledger will return as many entries as possible, up to the `icrc103:max_take_value` limit. + +If the response contains fewer entries than the smaller of `take` and `icrc103:max_take_value`, it indicates that there are no more allowances that meet the criteria for listing. ## 5. Example Using Symbolic Values From 1e6a0725e627e7456e5ccc7681c1c5ea3d079c81 Mon Sep 17 00:00:00 2001 From: bogwar <51327868+bogwar@users.noreply.github.com> Date: Tue, 15 Oct 2024 11:44:09 +0200 Subject: [PATCH 13/16] listallowances -> getallowances --- ICRCs/ICRC-103/ICRC-103.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/ICRCs/ICRC-103/ICRC-103.md b/ICRCs/ICRC-103/ICRC-103.md index 47ebeb8..e576fec 100644 --- a/ICRCs/ICRC-103/ICRC-103.md +++ b/ICRCs/ICRC-103/ICRC-103.md @@ -32,15 +32,15 @@ Metadata entries can be retrieved using method `icrc1_metadata` defined by the I Some of the types used are shared with standards ICRC-1 and ICRC-2; we restate their definition for completeness. ```candid -icrc103_get_allowances : (ListAllowancesArgs) -> (ListAllowancesResult) query +icrc103_get_allowances : (GetAllowancesArgs) -> (GetAllowancesResult) query -type ListAllowancesArgs = record { +type GetAllowancesArgs = record { from_account : opt Account; prev_spender : opt Account; take : opt nat; } -type ListAllowancesResult = vec record { +type GetAllowancesResult = vec record { from_account : Account; to_spender : Account; allowance : nat; @@ -72,13 +72,13 @@ Otherwise, the endpoint returns a list of records of the form `(account_1, accou * If `prev_spender` is provided the list starts with the allowance immediately succeeding `(from_account, prev_spender)`. * If `prev_spender` is not provided the list starts with the first allowance from `from_account`. -The list includes up to `take` entries if `take` is provided, but it cannot exceed the maximum number specified by the `icrc103:max_take_value` metadata. If take is not provided, the ledger will return as many entries as possible, up to the `icrc103:max_take_value` limit. +The list includes up to `take` entries if `take` is provided, but it cannot exceed the maximum number specified by the `icrc103:max_take_value` metadata. If `take` is not provided, the ledger will return as many entries as possible, up to the limit specified by `icrc103:max_take_value`. -If the response contains fewer entries than the smaller of `take` and `icrc103:max_take_value`, it indicates that there are no more allowances that meet the criteria for listing. +If the response contains fewer entries than the smaller of `take` and `icrc103:max_take_value`, it indicates that there are no more allowances that meet the criteria for listing. ## 5. Example Using Symbolic Values -Assume that the ledger stores the following allowances, listed in lexicographic order. Below, `p0,p1,...,p5` are some arbitrary principals, `s0` is the default subaccount, `s1,s2,..,s5` are subacounts, and `a1,a2,...,a5` are allowances (the associated expiration is omitted). +Assume that the ledger stores the following allowances, listed in lexicographic order. Below, `p0,p1,...,p5` are some arbitrary principals, `s0` is the default subaccount, `s1,s2,..,s5` are subaccounts, and `a1,a2,...,a5` are allowances (the associated expiration is omitted). - **A1** = `((p0, s0), (p1, s1), a1)` - **A2** = `((p0, s0), (p2, s2), a2)` @@ -92,19 +92,19 @@ Then: 1. **Case 1: `prev_spender` is not provided** - - If `p0` calls the list allowances endpoint with `from_account = (p0, s0)`, `prev_spender = None`, and `take = 4`, the endpoint returns `(A1, A2, A3)`. + - If `p0` calls the get allowances endpoint with `from_account = (p0, s0)`, `prev_spender = None`, and `take = 4`, the endpoint returns `(A1, A2, A3)`. - Since `prev_spender` is not provided, the list starts with the first allowance from `from_account = (p0, s0)`. - - The endpoint returns allowances for `p0`, including those that do not necessarily originate from `(p0, s0)`. + - The endpoint returns allowances for `p0`, including those that may not originate from `(p0, s0)`. 2. **Case 2: `prev_spender` is provided** - - If `p0` calls the list allowances endpoint with `from_account = (p0, s0)`, `prev_spender = (p1, s1)`, and `take = 3`, the endpoint returns `(A2, A3)`. + - If `p0` calls the get allowances endpoint with `from_account = (p0, s0)`, `prev_spender = (p1, s1)`, and `take = 3`, the endpoint returns `(A2, A3)`. - Since `prev_spender = (p1, s1)` is provided, the list starts with the first allowance immediately succeeding `(p0, s0), (p1, s1)` in lexicographic order, which is `(p0, s0), (p2, s2)` (A2). - The returned list contains only allowances where the `owner` of `account_1` is `p0`, which matches the `from_account.owner`. 3. **Case 3: Private version of the standard** - - If `p0` calls the list allowances endpoint with `from_account = (p1, s0)` (`p0 ≠ p1`), and the ledger implements the private version of the standard, the endpoint returns an empty list. + - If `p0` calls the get allowances endpoint with `from_account = (p1, s0)` (`p0 ≠ p1`), and the ledger implements the private version of the standard, the endpoint returns an empty list. - Since `from_account.owner ≠ caller_principal` and the ledger implements the private version, no allowances are returned. 4. **Case 4: `prev_spender` is not in the list** - - If `p0` calls the list allowances endpoint with `from_account = (p0, s0)`, `prev_spender = (p2, s)` for some `s1 < s < s2`, and `take = 2`, the endpoint returns `(A2, A3)`. + - If `p0` calls the get allowances endpoint with `from_account = (p0, s0)`, `prev_spender = (p2, s)` for some `s1 < s < s2`, and `take = 2`, the endpoint returns `(A2, A3)`. - Since `(p0, s0), (p2, s)` is not in the list, the allowances start with the first available pair greater than `(p0, s0), (p2, s)`—in this case, `(p0, s0), (p2, s2)` (A2). From 6e434c91f8ad14cf948b56419169af17036662cd Mon Sep 17 00:00:00 2001 From: bogwar <51327868+bogwar@users.noreply.github.com> Date: Mon, 28 Oct 2024 17:46:53 +0100 Subject: [PATCH 14/16] accessing allowances of a different principal returns error on private ledgers --- ICRCs/ICRC-103/ICRC-103.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/ICRCs/ICRC-103/ICRC-103.md b/ICRCs/ICRC-103/ICRC-103.md index e576fec..3935490 100644 --- a/ICRCs/ICRC-103/ICRC-103.md +++ b/ICRCs/ICRC-103/ICRC-103.md @@ -32,7 +32,7 @@ Metadata entries can be retrieved using method `icrc1_metadata` defined by the I Some of the types used are shared with standards ICRC-1 and ICRC-2; we restate their definition for completeness. ```candid -icrc103_get_allowances : (GetAllowancesArgs) -> (GetAllowancesResult) query +icrc103_get_allowances : (GetAllowancesArgs) -> (variant{Ok: Allowances, Err: GetAllowancesError}) query type GetAllowancesArgs = record { from_account : opt Account; @@ -40,7 +40,13 @@ type GetAllowancesArgs = record { take : opt nat; } -type GetAllowancesResult = vec record { +type GetAllowancesError = variant{ + AccessDenied : text; + GenericError : record { error_code : nat; message : text }; +} + + +type Allowances = vec record { from_account : Account; to_spender : Account; allowance : nat; @@ -66,7 +72,7 @@ The `icrc103_get_allowances` method behaves as follows: * If `from_account` is not provided, it is instantiated as `Account{caller_principal, first_subaccount}`. * If `from_account.subaccount` is not provided, it is instantiated with `first_subaccount`. -If the ledger implements the private version of the standard, the endpoint returns an empty list when `from_account.owner ≠ caller_principal`. +If the ledger implements the private version of the standard, the endpoint returns an `AccessDenied` if `from_account.owner ≠ caller_principal`. Otherwise, the endpoint returns a list of records of the form `(account_1, account_2, allowance)` in lexicographic order, with `account_1.owner = from_account.owner`. * If `prev_spender` is provided the list starts with the allowance immediately succeeding `(from_account, prev_spender)`. From 90197074df4db14f4b52b203d5e07a83f25b4d2a Mon Sep 17 00:00:00 2001 From: bogwar <51327868+bogwar@users.noreply.github.com> Date: Mon, 4 Nov 2024 12:42:45 +0100 Subject: [PATCH 15/16] improved intro following prodsec suggestions --- ICRCs/ICRC-103/ICRC-103.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ICRCs/ICRC-103/ICRC-103.md b/ICRCs/ICRC-103/ICRC-103.md index 3935490..6b11b5a 100644 --- a/ICRCs/ICRC-103/ICRC-103.md +++ b/ICRCs/ICRC-103/ICRC-103.md @@ -6,7 +6,10 @@ ## 1. Introduction -Although calls to the `icrc2_approve` and `icrc2_transfer_from` methods are recorded in the ledger, it is not possible to determine the allowances that are in effect at some point in time, except by traversing the entire ledger. This standard introduces an endpoint which will return this information thus making the management of allowances feasible. +The `icrc2_allowance` method can be used to get the allowance between specific pairs of accounts on the ledger. However, retrieving all allowances associated with a principal is challenging because it requires knowledge of the various subaccounts and spender information linked to that principal. Additionally, while calls to the `icrc2_approve` and `icrc2_transfer_from` methods are recorded in the ledger, determining which allowances are currently in effect would require traversing the entire ledger. This standard addresses these challenges by introducing an endpoint that allows querying all outstanding allowances related to a specific account, thus facilitating comprehensive and efficient allowance management. + + + ICRC-103 is an extension of the ICRC-2 standard. ICRC-103 specifies a way to list outstanding allowances. From f323e3bbd4065885d5a374f8c5b27781ec905752 Mon Sep 17 00:00:00 2001 From: bogwar <51327868+bogwar@users.noreply.github.com> Date: Mon, 18 Nov 2024 16:17:49 +0100 Subject: [PATCH 16/16] updated the url to the standard --- ICRCs/ICRC-103/ICRC-103.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ICRCs/ICRC-103/ICRC-103.md b/ICRCs/ICRC-103/ICRC-103.md index 6b11b5a..ffcc279 100644 --- a/ICRCs/ICRC-103/ICRC-103.md +++ b/ICRCs/ICRC-103/ICRC-103.md @@ -17,7 +17,7 @@ ICRC-103 specifies a way to list outstanding allowances. ## 2. Metadata -A ledger that implements ICRC-103 MUST include `record {name = "ICRC-103"; url = "https://github.com/dfinity/ICRC-1/standards/ICRC-103"}` as part of the output of `icrc1_supported_standards`. +A ledger that implements ICRC-103 MUST include `record {name = "ICRC-103"; url = ""https://github.com/dfinity/ICRC/blob/main/ICRCs/ICRC-106""}` as part of the output of `icrc1_supported_standards`. The endpoint introduced in this standard operates in two ways. In the public version any principal can obtain the outstanding allowances of any other principal. In the private version, the allowances returned by the endpoint must have been issued by the caller (i.e. the caller is the principal controlling the source account of an allowance.) Which version of the standard is implemented by a ledger is specified through the `icrc103:public_allowances` metadata.