Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add return value to sbt_revoke_by_owner #88

Merged
merged 7 commits into from
Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions contracts/community-sbt/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ Change log entries are to be added to the Unreleased section. Example entry:

### Breaking Changes

- The registry method `sbt_revoke_by_owner` now returns `boolean` indicating if all the tokens were revoked. `true` if all the tokens were revoked succesfully or `false` if not and the method needs to be called agian.

### Bug Fixes

## v4.3.0 (2023-09-07)
Expand Down
52 changes: 48 additions & 4 deletions contracts/registry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2266,8 +2266,8 @@ mod tests {

ctr.sbt_mint(vec![(alice(), vec![m1_1.clone(), m1_2.clone()])]);

// revoke (burn) tokens minted for alice from issuer2
ctr.sbt_revoke_by_owner(alice(), true);
let res = ctr.sbt_revoke_by_owner(alice(), true);
assert!(res);

let log_burn = mk_log_str(
"burn",
Expand Down Expand Up @@ -2302,7 +2302,8 @@ mod tests {
ctx.predecessor_account_id = issuer1();
testing_env!(ctx.clone());
assert_eq!(test_utils::get_logs().len(), 0);
ctr.sbt_revoke_by_owner(alice(), false);
let res = ctr.sbt_revoke_by_owner(alice(), false);
assert!(res);

let log_revoke = mk_log_str(
"revoke",
Expand All @@ -2320,7 +2321,7 @@ mod tests {
assert!(res_with_expired.is_empty());
let res_without_expired = ctr.sbt_tokens_by_owner(alice(), None, None, None, Some(true));
assert!(res_without_expired.len() == 1);
assert_eq!(res[0].1.len(), 2);
assert_eq!(res_without_expired[0].1.len(), 2);
assert_eq!(ctr.sbt_supply(issuer1()), 2);
assert_eq!(ctr.sbt_supply(issuer2()), 0);
assert_eq!(ctr.sbt_supply_by_class(issuer1(), 1), 1);
Expand Down Expand Up @@ -2381,6 +2382,49 @@ mod tests {
assert_eq!(ctr.sbt_supply(issuer2()), 9);
}

#[test]
fn sbt_revoke_by_owner_limit() {
let (mut ctx, mut ctr) = setup(&issuer1(), 200 * MINT_DEPOSIT);

// mint tokens to alice from issuer1
let batch_metadata = mk_batch_metadata(100);
ctr.sbt_mint(vec![(alice(), batch_metadata[..50].to_vec())]);

// mint tokens to alice from issuer2
ctx.predecessor_account_id = issuer2();
ctx.prepaid_gas = max_gas();
testing_env!(ctx.clone());
ctr.sbt_mint(vec![(alice(), batch_metadata[..50].to_vec())]);

ctx.prepaid_gas = max_gas();
testing_env!(ctx.clone());
let res = ctr.sbt_tokens_by_owner(alice(), None, None, None, None);
assert_eq!(res[0].1.len(), 50);
assert_eq!(res[1].1.len(), 50);

assert_eq!(ctr.sbt_supply(issuer1()), 50);
assert_eq!(ctr.sbt_supply(issuer2()), 50);

ctx.prepaid_gas = max_gas();
testing_env!(ctx.clone());
// revoke (burn) tokens minted for alice from issuer2
let res = ctr.sbt_revoke_by_owner(alice(), true);
amityadav0 marked this conversation as resolved.
Show resolved Hide resolved
assert!(!res);

ctx.prepaid_gas = max_gas();
testing_env!(ctx);
// revoke (burn) tokens minted for alice from issuer2
let res = ctr.sbt_revoke_by_owner(alice(), true);
assert!(res);

// make sure the balances are updated correctly
let res = ctr.sbt_tokens_by_owner(alice(), None, None, None, None);
assert_eq!(res[0].1.len(), 50);

assert_eq!(ctr.sbt_supply(issuer1()), 50);
assert_eq!(ctr.sbt_supply(issuer2()), 0);
}

#[test]
fn is_human() {
let (mut ctx, mut ctr) = setup(&fractal_mainnet(), 150 * MINT_DEPOSIT);
Expand Down
24 changes: 17 additions & 7 deletions contracts/registry/src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use near_sdk::{json_types::Base64VecU8, near_bindgen, AccountId};
use crate::*;

const MAX_LIMIT: u32 = 1000;
const MAX_REVOKE_PER_CALL: u32 = 25;

#[near_bindgen]
impl SBTRegistry for Contract {
Expand Down Expand Up @@ -350,20 +351,28 @@ impl SBTRegistry for Contract {
}

/// Revokes owners SBTs issued by the caller either by burning or updating their expire
/// time. The function will try to revoke at most `MAX_LIMIT` tokens (to fit into the tx
/// time. The function will try to revoke at most `MAX_REVOKE_PER_CALL` tokens (to fit into the tx
/// gas limit), so when an owner has many tokens from the issuer, the issuer may need to
/// call this function multiple times, until all tokens are revoked. Issuer should query
/// `sbt_supply_by_owner` to check if the function should be called again.
/// call this function multiple times, until all tokens are revoked.
/// Retuns true if all the tokens were revoked, false otherwise.
/// If false is returned issuer must call the method until true is returned
/// Must be called by an SBT contract.
/// Must emit `Revoke` event.
/// Must also emit `Burn` event if the SBT tokens are burned (removed).
fn sbt_revoke_by_owner(&mut self, owner: AccountId, burn: bool) {
fn sbt_revoke_by_owner(&mut self, owner: AccountId, burn: bool) -> bool {
sczembor marked this conversation as resolved.
Show resolved Hide resolved
let issuer = env::predecessor_account_id();
let issuer_id = self.assert_issuer(&issuer);
let mut tokens_by_owner =
self.sbt_tokens_by_owner(owner.clone(), Some(issuer.clone()), None, None, Some(true));
let mut tokens_by_owner = self.sbt_tokens_by_owner(
owner.clone(),
Some(issuer.clone()),
None,
Some(MAX_REVOKE_PER_CALL),
Some(true),
);
let remaining_supply = self.sbt_supply_by_owner(owner.clone(), issuer.clone(), None);
let tokens_len = tokens_by_owner[0].1.len();
if tokens_by_owner.is_empty() {
return;
return true;
};
let (_, tokens) = tokens_by_owner.pop().unwrap();

Expand Down Expand Up @@ -441,6 +450,7 @@ impl SBTRegistry for Contract {
tokens: token_ids,
}
.emit_revoke();
tokens_len >= remaining_supply as usize
}

/// Allows issuer to update token metadata reference and reference_hash.
Expand Down
2 changes: 1 addition & 1 deletion contracts/sbt/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ pub trait SBTRegistry {
/// Must be called by an SBT contract.
/// Must emit `Revoke` event.
/// Must also emit `Burn` event if the SBT tokens are burned (removed).
fn sbt_revoke_by_owner(&mut self, owner: AccountId, burn: bool);
fn sbt_revoke_by_owner(&mut self, owner: AccountId, burn: bool) -> bool;

/// Allows issuer to update token metadata reference and reference_hash.
/// * `updates` is a list of triples: (token ID, reference, reference hash).
Expand Down
Loading