diff --git a/contracts/assemblyscript/nep4/__tests__/main.unit.spec.ts b/contracts/assemblyscript/nep4/__tests__/main.unit.spec.ts index 0d4e767..c6a9caa 100644 --- a/contracts/assemblyscript/nep4/__tests__/main.unit.spec.ts +++ b/contracts/assemblyscript/nep4/__tests__/main.unit.spec.ts @@ -17,42 +17,30 @@ const carol = 'carol' describe('grant_access', () => { it('grants access to the given account_id for all the tokens that account has', () => { const aliceToken = nonSpec.mint_to(alice) - Context.setPredecessor_account_id(alice) + Context.setPredecessor_account_id(alice) grant_access(bob) - expect(check_access(bob)).toBe(true) - }) - - it('requires the caller of the function to have access to the token.', () => { - expect(() => { - const aliceToken = nonSpec.mint_to(alice) - Context.setPredecessor_account_id(bob) - - grant_access(bob); - }).toThrow(nonSpec.ERROR_NO_TOKENS_CONTROLLED) + Context.setPredecessor_account_id(bob) + expect(check_access(alice)).toBe(true) }) }); describe('revoke_access', () => { it('revokes access to the given `accountId` for the given `tokenId`', () => { const aliceToken = nonSpec.mint_to(alice) - Context.setPredecessor_account_id(alice) + Context.setPredecessor_account_id(alice) grant_access(bob); - expect(check_access(bob)).toBe(true) - revoke_access(bob); - expect(check_access(bob)).toBe(false) - }) + Context.setPredecessor_account_id(bob) + expect(check_access(alice)).toBe(true) - it('requires caller of the function to have access to the token.', () => { - expect(() => { - const aliceToken = nonSpec.mint_to(alice) - Context.setPredecessor_account_id(bob) + Context.setPredecessor_account_id(alice) + revoke_access(bob); - revoke_access(bob); - }).toThrow(nonSpec.ERROR_NO_TOKENS_CONTROLLED) + Context.setPredecessor_account_id(bob) + expect(check_access(alice)).toBe(false) }) }) @@ -118,11 +106,12 @@ describe('transfer', () => { describe('check_access', () => { it('returns true if caller of the function has access to the token', () => { const aliceToken = nonSpec.mint_to(alice) - Context.setPredecessor_account_id(alice) + Context.setPredecessor_account_id(alice) grant_access(bob) - expect(check_access(bob)).toBe(true) + Context.setPredecessor_account_id(bob) + expect(check_access(alice)).toBe(true) }) it('returns false if caller of function does not have access', () => { diff --git a/contracts/assemblyscript/nep4/main.ts b/contracts/assemblyscript/nep4/main.ts index 24ebb5c..ea676e2 100644 --- a/contracts/assemblyscript/nep4/main.ts +++ b/contracts/assemblyscript/nep4/main.ts @@ -10,14 +10,14 @@ type TokenId = u64 export const MAX_SUPPLY = u64(1_000) const tokenToOwner = new PersistentMap('a') -const escrowAccess = new PersistentMap('b') +const escrowAccess = new PersistentMap('b') const TOTAL_SUPPLY = 'c' /******************/ /* ERROR MESSAGES */ /******************/ -export const ERROR_NO_TOKENS_CONTROLLED = "Caller does not control any tokens." +export const ERROR_NO_ESCROW_REGISTERED = "Caller has no escrow registered." export const ERROR_CALLER_ID_DOES_NOT_MATCH_EXPECTATION = "Caller ID does not match expectation." export const ERROR_CLAIMED_OWNER_DOES_NOT_OWN_TOKEN = "Claimed owner does not own token" export const ERROR_MAXIMUM_TOKEN_LIMIT_REACHED = "Maximum token limit reached." @@ -27,47 +27,13 @@ export const ERROR_MAXIMUM_TOKEN_LIMIT_REACHED = "Maximum token limit reached." /******************/ // Grant the access to the given `accountId` for all tokens that account has. -// Requirements: -// * The caller of the function (`predecessor`) should have access to the tokens. export function grant_access(escrow_account_id: string): void { - const predecessor = context.predecessor - - // fetch all accounts with escrow access to predecessor tokens - assert(escrowAccess.contains(predecessor), ERROR_NO_TOKENS_CONTROLLED) - const escrowAccounts = escrowAccess.getSome(predecessor) - - // add escrow_account_id to list of escrow accounts - escrowAccounts.push(escrow_account_id) - - // grant escrow account access to all predecessor tokens - escrowAccess.set(predecessor, escrowAccounts) + escrowAccess.set(context.predecessor, escrow_account_id) } -// Revoke the access to the given `accountId` for the given `tokenId`. -// Requirements: -// * The caller of the function (`predecessor`) should have access to the token. +// Revoke the access to the given `accountId` for all tokens that account has. export function revoke_access(escrow_account_id: string): void { - const predecessor = context.predecessor - - // fetch escrow_account_id from list of escrow accounts - assert(escrowAccess.contains(predecessor), ERROR_NO_TOKENS_CONTROLLED) - const escrowAccounts = escrowAccess.getSome(predecessor) - - // remove the escrow account from list of accounts with access to owner's tokens - // note we can't use Array.filter() since it's not implemented in AssemblyScript - // and only number types seem to work with Array.filter() - // also there are no clojures in AssemblyScript yet so passing in the value to filter on - // seems like a non-starter. for loops FTW! - let filteredAccounts: AccountId[] = [] - for (let index = 0; index < escrowAccounts.length; index++) { - const account = escrowAccounts[index] - if(account != escrow_account_id) { - filteredAccounts.push(account) - } - } - - // commit the removal to the escrow registry - escrowAccess.set(predecessor, filteredAccounts) + escrowAccess.delete(context.predecessor) } // Transfer the given `token_id` from the given `owner_id`. Account `new_owner_id` becomes the new owner. @@ -77,8 +43,8 @@ export function transfer_from(owner_id: string, new_owner_id: string, token_id: const predecessor = context.predecessor // fetch token escrow & verify access - const escrowAccounts = escrowAccess.getSome(owner_id) - assert(escrowAccounts.includes(predecessor), ERROR_CALLER_ID_DOES_NOT_MATCH_EXPECTATION) + const escrow = escrowAccess.getSome(owner_id) + assert(escrow == predecessor, ERROR_CALLER_ID_DOES_NOT_MATCH_EXPECTATION) // assign new owner to token tokenToOwner.set(token_id, new_owner_id) @@ -102,20 +68,18 @@ export function transfer(new_owner_id: string, token_id: TokenId): void { /* VIEW METHODS */ /****************/ -// Returns `true` or `false` based on caller of the function (`predecessor`) having access to a user's tokens -export function check_access(account_id: string): bool { - const owner = context.predecessor +// Returns `true` or `false` based on caller of the function (`predecessor`) having access to account_id's tokens +export function check_access(account_id: string): boolean { + const caller = context.predecessor + + assert(caller != account_id, ERROR_CALLER_ID_DOES_NOT_MATCH_EXPECTATION) - // confirm the caller has been minted at least one token - if(!escrowAccess.contains(owner)) { - // caller has never been minted a token and does not appear in the registry + if (!escrowAccess.contains(account_id)) { return false - } else { - // fetch list of escrow accounts with access to owner's tokens - const escrowAccounts = escrowAccess.getSome(owner) - // return result of check - return escrowAccounts.includes(account_id) } + + const escrow = escrowAccess.getSome(account_id) + return escrow == caller } // Get an individual owner by given `tokenId`. @@ -136,7 +100,6 @@ export function mint_to(owner_id: AccountId): u64 { // assign ownership tokenToOwner.set(tokenId, owner_id) - escrowAccess.set(owner_id, []) // increment and store the next tokenId storage.set(TOTAL_SUPPLY, tokenId + 1)