diff --git a/.github/ISSUE_TEMPLATE/01_bug_report.yml b/.github/ISSUE_TEMPLATE/01_bug_report.yml index 5e38c0e1..bd2712c2 100644 --- a/.github/ISSUE_TEMPLATE/01_bug_report.yml +++ b/.github/ISSUE_TEMPLATE/01_bug_report.yml @@ -93,8 +93,7 @@ body: label: Version description: What version of Compact are you running? options: - - 0.26.0 (Default) + - 0.29.0 (Default) default: 0 validations: required: true - diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index e7d22291..705e0694 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -41,6 +41,6 @@ runs: - name: Setup Compact Compiler if: ${{ inputs.skip-compact != 'true' }} - uses: midnightntwrk/setup-compact-action@4130145456ad3f45934788dd4a65647eb283e658 # loose commit/not released + uses: midnightntwrk/setup-compact-action@836895c8fffbbea6bd986af2b17e8941ff29d1f8 # v1 with: - compact-version: "0.26.0" + compact-version: "0.29.0" diff --git a/contracts/package.json b/contracts/package.json index 02e88b25..d05b662f 100644 --- a/contracts/package.json +++ b/contracts/package.json @@ -20,6 +20,9 @@ }, "homepage": "https://docs.openzeppelin.com/contracts-compact/", "type": "module", + "imports": { + "#test-utils/address.js": "./test-utils/address.js" + }, "scripts": { "compact": "compact-compiler", "compact:access": "compact-compiler --dir access", diff --git a/contracts/src/access/AccessControl.compact b/contracts/src/access/AccessControl.compact index d6c57734..021d2e43 100644 --- a/contracts/src/access/AccessControl.compact +++ b/contracts/src/access/AccessControl.compact @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Compact Contracts v0.0.1-alpha.1 (access/AccessControl.compact) -pragma language_version >= 0.18.0; +pragma language_version >= 0.21.0; /** * @module AccessControl @@ -81,7 +81,8 @@ module AccessControl { * @type {Map} * @type {Map, Map, Boolean>} _operatorRoles  */ - export ledger _operatorRoles: Map, Map, Boolean>>; + export ledger _operatorRoles: Map, + Map, Boolean>>; /** * @description Mapping from a role identifier to an admin role identifier. @@ -94,25 +95,21 @@ module AccessControl { export ledger DEFAULT_ADMIN_ROLE: Bytes<32>; - /** - * @description Returns `true` if `account` has been granted `roleId`. - * - * @circuitInfo k=10, rows=487 - * - * @param {Bytes<32>} roleId - The role identifier. - * @param {Either} account - The account to query. - * @return {Boolean} - Whether the account has the specified role. + /** + * @description Returns `true` if `account` has been granted `roleId`. + * + * @circuitInfo k=10, rows=487 + * + * @param {Bytes<32>} roleId - The role identifier. + * @param {Either} account - The account to query. + * @return {Boolean} - Whether the account has the specified role.   */ - export circuit hasRole(roleId: Bytes<32>, account: Either): Boolean { - if ( - _operatorRoles.member(disclose(roleId)) && - _operatorRoles - .lookup(roleId) - .member(disclose(account)) - ) { - return _operatorRoles - .lookup(roleId) - .lookup(disclose(account)); + export circuit hasRole(roleId: Bytes<32>, + account: Either + ): Boolean { + if (_operatorRoles.member(disclose(roleId)) && + _operatorRoles.lookup(roleId).member(disclose(account))) { + return _operatorRoles.lookup(roleId).lookup(disclose(account)); } else { return false; } @@ -132,7 +129,7 @@ module AccessControl { * @return {[]} - Empty tuple. */ export circuit assertOnlyRole(roleId: Bytes<32>): [] { - _checkRole(roleId, left(ownPublicKey())); + _checkRole(roleId, left(ownPublicKey())); } /** @@ -148,7 +145,10 @@ module AccessControl { * @param {Either} account - The account to query. * @return {[]} - Empty tuple. */ - export circuit _checkRole(roleId: Bytes<32>, account: Either): [] { + export circuit _checkRole( + roleId: Bytes<32>, + account: Either + ): [] { assert(hasRole(roleId, account), "AccessControl: unauthorized account"); } @@ -184,7 +184,10 @@ module AccessControl { * @param {Either} account - A ZswapCoinPublicKey or ContractAddress. * @return {[]} - Empty tuple. */ - export circuit grantRole(roleId: Bytes<32>, account: Either): [] { + export circuit grantRole( + roleId: Bytes<32>, + account: Either + ): [] { assertOnlyRole(getRoleAdmin(roleId)); _grantRole(roleId, account); } @@ -202,31 +205,39 @@ module AccessControl { * @param {Either} account - A ZswapCoinPublicKey or ContractAddress. * @return {[]} - Empty tuple. */ - export circuit revokeRole(roleId: Bytes<32>, account: Either): [] { + export circuit revokeRole( + roleId: Bytes<32>, + account: Either + ): [] { assertOnlyRole(getRoleAdmin(roleId)); _revokeRole(roleId, account); } - /** - * @description Revokes `roleId` from the calling account. - * - * @notice Roles are often managed via {grantRole} and {revokeRole}: this circuit's - * purpose is to provide a mechanism for accounts to lose their privileges - * if they are compromised (such as when a trusted device is misplaced). - * - * @circuitInfo k=10, rows=640 - * - * Requirements: - * - * - The caller must be `callerConfirmation`. - * - The caller must not be a `ContractAddress`. - * - * @param {Bytes<32>} roleId - The role identifier. - * @param {Either} callerConfirmation - A ZswapCoinPublicKey or ContractAddress. - * @return {[]} - Empty tuple. - */ - export circuit renounceRole(roleId: Bytes<32>, callerConfirmation: Either): [] { - assert(callerConfirmation == left(ownPublicKey()), "AccessControl: bad confirmation"); + /** + * @description Revokes `roleId` from the calling account. + * + * @notice Roles are often managed via {grantRole} and {revokeRole}: this circuit's + * purpose is to provide a mechanism for accounts to lose their privileges + * if they are compromised (such as when a trusted device is misplaced). + * + * @circuitInfo k=10, rows=640 + * + * Requirements: + * + * - The caller must be `callerConfirmation`. + * - The caller must not be a `ContractAddress`. + * + * @param {Bytes<32>} roleId - The role identifier. + * @param {Either} callerConfirmation - A ZswapCoinPublicKey or ContractAddress. + * @return {[]} - Empty tuple. + */ + export circuit renounceRole( + roleId: Bytes<32>, + callerConfirmation: Either + ): [] { + assert(callerConfirmation == left(ownPublicKey()), + "AccessControl: bad confirmation" + ); _revokeRole(roleId, callerConfirmation); } @@ -258,7 +269,10 @@ module AccessControl { * @param {Either} account - A ZswapCoinPublicKey or ContractAddress. * @return {Boolean} roleGranted - A boolean indicating if `roleId` was granted. */ - export circuit _grantRole(roleId: Bytes<32>, account: Either): Boolean { + export circuit _grantRole( + roleId: Bytes<32>, + account: Either + ): Boolean { assert(!Utils_isContractAddress(account), "AccessControl: unsafe role approval"); return _unsafeGrantRole(roleId, account); } @@ -276,7 +290,10 @@ module AccessControl { * @param {Either} account - A ZswapCoinPublicKey or ContractAddress. * @return {Boolean} roleGranted - A boolean indicating if `role` was granted. */ - export circuit _unsafeGrantRole(roleId: Bytes<32>, account: Either): Boolean { + export circuit _unsafeGrantRole( + roleId: Bytes<32>, + account: Either + ): Boolean { if (hasRole(roleId, account)) { return false; } @@ -284,14 +301,9 @@ module AccessControl { if (!_operatorRoles.member(disclose(roleId))) { _operatorRoles.insert( disclose(roleId), - default, - Boolean - >> - ); - _operatorRoles - .lookup(roleId) - .insert(disclose(account), true); + default, Boolean>> + ); + _operatorRoles.lookup(roleId).insert(disclose(account), true); return true; } @@ -309,14 +321,15 @@ module AccessControl { * @param {Bytes<32>} adminRole - The admin role identifier. * @return {Boolean} roleRevoked - A boolean indicating if `roleId` was revoked. */ - export circuit _revokeRole(roleId: Bytes<32>, account: Either): Boolean { + export circuit _revokeRole( + roleId: Bytes<32>, + account: Either + ): Boolean { if (!hasRole(roleId, account)) { return false; } - _operatorRoles - .lookup(roleId) - .insert(disclose(account), false); + _operatorRoles.lookup(roleId).insert(disclose(account), false); return true; } } diff --git a/contracts/src/access/Ownable.compact b/contracts/src/access/Ownable.compact index a5bb44b6..5c15f5a5 100644 --- a/contracts/src/access/Ownable.compact +++ b/contracts/src/access/Ownable.compact @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Compact Contracts v0.0.1-alpha.1 (access/Ownable.compact) -pragma language_version >= 0.18.0; +pragma language_version >= 0.21.0; /** * @module Ownable @@ -143,7 +143,7 @@ module Ownable { export circuit renounceOwnership(): [] { Initializable_assertInitialized(); assertOnlyOwner(); - _transferOwnership(burnAddress()); + _transferOwnership(shieldedBurnAddress()); } /** @@ -206,7 +206,9 @@ module Ownable { * @param {Either} newOwner - The new owner. * @returns {[]} Empty tuple. */ - export circuit _unsafeUncheckedTransferOwnership(newOwner: Either): [] { + export circuit _unsafeUncheckedTransferOwnership( + newOwner: Either + ): [] { Initializable_assertInitialized(); _owner = disclose(newOwner); } diff --git a/contracts/src/access/ZOwnablePK.compact b/contracts/src/access/ZOwnablePK.compact index 588d7001..a8c0199d 100644 --- a/contracts/src/access/ZOwnablePK.compact +++ b/contracts/src/access/ZOwnablePK.compact @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Compact Contracts v0.0.1-alpha.1 (access/ZOwnablePK.compact) -pragma language_version >= 0.18.0; +pragma language_version >= 0.21.0; /** * @module ZOwnablePK @@ -191,13 +191,14 @@ module ZOwnablePK { Initializable_assertInitialized(); const nonce = wit_secretNonce(); - const callerAsEither = Either { - is_left: true, - left: ownPublicKey(), - right: ContractAddress { bytes: pad(32, "") } - }; + const callerAsEither = + Either { is_left: true, + left: ownPublicKey(), + right: ContractAddress { bytes: pad(32, "") } }; const id = _computeOwnerId(callerAsEither, nonce); - assert(_ownerCommitment == _computeOwnerCommitment(id, _counter), "ZOwnablePK: caller is not the owner"); + assert(_ownerCommitment == _computeOwnerCommitment(id, _counter), + "ZOwnablePK: caller is not the owner" + ); } /** @@ -232,19 +233,11 @@ module ZOwnablePK { * after every transfer to prevent duplicate commitments given the same `id`. * @returns {Bytes<32>} The commitment derived from `id` and `counter`. */ - export circuit _computeOwnerCommitment( - id: Bytes<32>, - counter: Uint<64>, - ): Bytes<32> { + export circuit _computeOwnerCommitment(id: Bytes<32>, counter: Uint<64>,): Bytes<32> { Initializable_assertInitialized(); return persistentHash>>( - [ - id, - _instanceSalt, - counter as Field as Bytes<32>, - pad(32, "ZOwnablePK:shield:") - ] - ); + [id, _instanceSalt, counter as Field as Bytes<32>, pad(32, "ZOwnablePK:shield:")] + ); } /** @@ -280,9 +273,9 @@ module ZOwnablePK { * @returns {Bytes<32>} The computed owner ID. */ export pure circuit _computeOwnerId( - pk: Either, - nonce: Bytes<32> - ): Bytes<32> { + pk: Either, + nonce: Bytes<32> + ): Bytes<32> { assert(pk.is_left, "ZOwnablePK: contract address owners are not yet supported"); return persistentHash>>([pk.left.bytes, nonce]); diff --git a/contracts/src/access/test/AccessControl.test.ts b/contracts/src/access/test/AccessControl.test.ts index 33459c79..d31040a0 100644 --- a/contracts/src/access/test/AccessControl.test.ts +++ b/contracts/src/access/test/AccessControl.test.ts @@ -1,24 +1,19 @@ -import { - type CoinPublicKey, - convertFieldToBytes, -} from '@midnight-ntwrk/compact-runtime'; +import { convertFieldToBytes } from '@midnight-ntwrk/compact-runtime'; import { beforeEach, describe, expect, it } from 'vitest'; +import * as utils from '#test-utils/address.js'; import { AccessControlSimulator } from './simulators/AccessControlSimulator.js'; -import * as utils from './utils/address.js'; -// Callers -const OPERATOR_1 = utils.toHexPadded('OPERATOR_1'); -const ADMIN = utils.toHexPadded('ADMIN'); -const CUSTOM_ADMIN = utils.toHexPadded('CUSTOM_ADMIN'); -const UNAUTHORIZED = utils.toHexPadded('UNAUTHORIZED'); -const OPERATOR_CONTRACT = utils.toHexPadded('OPERATOR_CONTRACT'); +// PKs +const [OPERATOR_1, Z_OPERATOR_1] = utils.generateEitherPubKeyPair('OPERATOR_1'); +const [_, Z_OPERATOR_2] = utils.generateEitherPubKeyPair('OPERATOR_2'); +const [ADMIN, Z_ADMIN] = utils.generateEitherPubKeyPair('ADMIN'); +const [CUSTOM_ADMIN, Z_CUSTOM_ADMIN] = + utils.generateEitherPubKeyPair('CUSTOM_ADMIN'); +const [UNAUTHORIZED, Z_UNAUTHORIZED] = + utils.generateEitherPubKeyPair('UNAUTHORIZED'); -// Encoded PK/Addresses -const Z_OPERATOR_1 = utils.createEitherTestUser('OPERATOR_1'); -const Z_OPERATOR_2 = utils.createEitherTestUser('OPERATOR_2'); -const Z_ADMIN = utils.createEitherTestUser('ADMIN'); -const Z_CUSTOM_ADMIN = utils.createEitherTestUser('CUSTOM_ADMIN'); -const Z_UNAUTHORIZED = utils.createEitherTestUser('UNAUTHORIZED'); +// Encoded contract addresses +const OPERATOR_CONTRACT = utils.toHexPadded('OPERATOR_CONTRACT'); const Z_OPERATOR_CONTRACT = utils.createEitherTestContractAddress('OPERATOR_CONTRACT'); @@ -31,7 +26,6 @@ const CUSTOM_ADMIN_ROLE = convertFieldToBytes(32, 4n, ''); const UNINITIALIZED_ROLE = convertFieldToBytes(32, 5n, ''); let accessControl: AccessControlSimulator; -let caller: CoinPublicKey; const callerTypes = { contract: OPERATOR_CONTRACT, @@ -79,25 +73,22 @@ describe('AccessControl', () => { }); it('should allow operator with role to call', () => { - caller = OPERATOR_1; expect(() => - accessControl.assertOnlyRole(OPERATOR_ROLE_1, caller), + accessControl.as(OPERATOR_1).assertOnlyRole(OPERATOR_ROLE_1), ).not.toThrow(); }); it('should throw if caller is unauthorized', () => { - caller = UNAUTHORIZED; expect(() => - accessControl.assertOnlyRole(OPERATOR_ROLE_1, caller), + accessControl.as(UNAUTHORIZED).assertOnlyRole(OPERATOR_ROLE_1), ).toThrow('AccessControl: unauthorized account'); }); it('should throw if ContractAddress with role is caller', () => { - caller = OPERATOR_CONTRACT; accessControl._unsafeGrantRole(OPERATOR_ROLE_1, Z_OPERATOR_CONTRACT); expect(() => - accessControl.assertOnlyRole(OPERATOR_ROLE_1, caller), + accessControl.as(OPERATOR_CONTRACT).assertOnlyRole(OPERATOR_ROLE_1), ).toThrow('AccessControl: unauthorized account'); }); }); @@ -143,11 +134,10 @@ describe('AccessControl', () => { describe('grantRole', () => { beforeEach(() => { accessControl._grantRole(DEFAULT_ADMIN_ROLE, Z_ADMIN); - caller = ADMIN; }); it('admin should grant role', () => { - accessControl.grantRole(OPERATOR_ROLE_1, Z_OPERATOR_1, caller); + accessControl.as(ADMIN).grantRole(OPERATOR_ROLE_1, Z_OPERATOR_1); expect(accessControl.hasRole(OPERATOR_ROLE_1, Z_OPERATOR_1)).toBe(true); }); @@ -155,7 +145,7 @@ describe('AccessControl', () => { for (let i = 0; i < operatorRoles.length; i++) { // length - 1 because we test ContractAddress separately for (let j = 0; j < operatorPKs.length - 1; j++) { - accessControl.grantRole(operatorRoles[i], operatorPKs[j], caller); + accessControl.as(ADMIN).grantRole(operatorRoles[i], operatorPKs[j]); expect(accessControl.hasRole(operatorRoles[i], operatorPKs[j])).toBe( true, ); @@ -164,17 +154,16 @@ describe('AccessControl', () => { }); it('should throw if operator grants role', () => { - accessControl.grantRole(OPERATOR_ROLE_1, Z_OPERATOR_1, caller); + accessControl.as(ADMIN).grantRole(OPERATOR_ROLE_1, Z_OPERATOR_1); - caller = OPERATOR_1; expect(() => { - accessControl.grantRole(OPERATOR_ROLE_1, Z_UNAUTHORIZED, caller); + accessControl.as(OPERATOR_1).grantRole(OPERATOR_ROLE_1, Z_UNAUTHORIZED); }).toThrow('AccessControl: unauthorized account'); }); it('should throw if admin grants role to ContractAddress', () => { expect(() => { - accessControl.grantRole(OPERATOR_ROLE_1, Z_OPERATOR_CONTRACT, caller); + accessControl.as(ADMIN).grantRole(OPERATOR_ROLE_1, Z_OPERATOR_CONTRACT); }).toThrow('AccessControl: unsafe role approval'); }); }); @@ -190,28 +179,24 @@ describe('AccessControl', () => { operatorTypes, )('when the operator is a %s', (_operatorType, _operator) => { it('admin should revoke role', () => { - caller = ADMIN; - - accessControl.revokeRole(OPERATOR_ROLE_1, _operator, caller); + accessControl.as(ADMIN).revokeRole(OPERATOR_ROLE_1, _operator); expect(accessControl.hasRole(OPERATOR_ROLE_1, _operator)).toBe(false); }); it('should throw if operator revokes role', () => { - caller = callerTypes[_operatorType]; + const caller = callerTypes[_operatorType]; expect(() => { - accessControl.revokeRole(OPERATOR_ROLE_1, Z_UNAUTHORIZED, caller); + accessControl.as(caller).revokeRole(OPERATOR_ROLE_1, Z_UNAUTHORIZED); }).toThrow('AccessControl: unauthorized account'); }); }); it('admin should revoke multiple roles', () => { - caller = ADMIN; - for (let i = 0; i < operatorRoles.length; i++) { for (let j = 0; j < operatorPKs.length; j++) { accessControl._unsafeGrantRole(operatorRoles[i], operatorPKs[j]); - accessControl.revokeRole(operatorRoles[i], operatorPKs[j], caller); + accessControl.as(ADMIN).revokeRole(operatorRoles[i], operatorPKs[j]); expect(accessControl.hasRole(operatorRoles[i], operatorPKs[j])).toBe( false, ); @@ -223,31 +208,28 @@ describe('AccessControl', () => { describe('renounceRole', () => { beforeEach(() => { accessControl._grantRole(OPERATOR_ROLE_1, Z_OPERATOR_1); - caller = OPERATOR_1; }); it('should allow operator to renounce own role', () => { - accessControl.renounceRole(OPERATOR_ROLE_1, Z_OPERATOR_1, caller); + accessControl.as(OPERATOR_1).renounceRole(OPERATOR_ROLE_1, Z_OPERATOR_1); expect(accessControl.hasRole(OPERATOR_ROLE_1, Z_OPERATOR_1)).toBe(false); }); it('ContractAddress renounce should throw', () => { - caller = OPERATOR_CONTRACT; accessControl._unsafeGrantRole(OPERATOR_ROLE_1, Z_OPERATOR_CONTRACT); expect(() => { - accessControl.renounceRole( - OPERATOR_ROLE_1, - Z_OPERATOR_CONTRACT, - caller, - ); + accessControl + .as(OPERATOR_CONTRACT) + .renounceRole(OPERATOR_ROLE_1, Z_OPERATOR_CONTRACT); }).toThrow('AccessControl: bad confirmation'); }); it('unauthorized renounce should throw', () => { - caller = UNAUTHORIZED; expect(() => { - accessControl.renounceRole(OPERATOR_ROLE_1, Z_OPERATOR_1, caller); + accessControl + .as(UNAUTHORIZED) + .renounceRole(OPERATOR_ROLE_1, Z_OPERATOR_1); }).toThrow('AccessControl: bad confirmation'); }); }); @@ -279,31 +261,29 @@ describe('AccessControl', () => { }); it('should authorize new admin to grant / revoke roles', () => { - caller = CUSTOM_ADMIN; - accessControl._grantRole(CUSTOM_ADMIN_ROLE, Z_CUSTOM_ADMIN); accessControl._setRoleAdmin(OPERATOR_ROLE_1, CUSTOM_ADMIN_ROLE); expect(() => - accessControl.grantRole(OPERATOR_ROLE_1, Z_OPERATOR_1, caller), + accessControl.as(CUSTOM_ADMIN).grantRole(OPERATOR_ROLE_1, Z_OPERATOR_1), ).not.toThrow(); expect(() => - accessControl.revokeRole(OPERATOR_ROLE_1, Z_OPERATOR_1, caller), + accessControl + .as(CUSTOM_ADMIN) + .revokeRole(OPERATOR_ROLE_1, Z_OPERATOR_1), ).not.toThrow(); }); it('should disallow previous admin from granting / revoking roles', () => { - caller = ADMIN; - accessControl._grantRole(DEFAULT_ADMIN_ROLE, Z_ADMIN); accessControl._grantRole(CUSTOM_ADMIN_ROLE, Z_CUSTOM_ADMIN); accessControl._setRoleAdmin(OPERATOR_ROLE_1, CUSTOM_ADMIN_ROLE); expect(() => - accessControl.grantRole(OPERATOR_ROLE_1, Z_OPERATOR_1, caller), + accessControl.as(ADMIN).grantRole(OPERATOR_ROLE_1, Z_OPERATOR_1), ).toThrow('AccessControl: unauthorized account'); expect(() => - accessControl.revokeRole(OPERATOR_ROLE_1, Z_OPERATOR_1, caller), + accessControl.as(ADMIN).revokeRole(OPERATOR_ROLE_1, Z_OPERATOR_1), ).toThrow('AccessControl: unauthorized account'); }); }); diff --git a/contracts/src/access/test/Ownable.test.ts b/contracts/src/access/test/Ownable.test.ts index 8689f697..af2716a0 100644 --- a/contracts/src/access/test/Ownable.test.ts +++ b/contracts/src/access/test/Ownable.test.ts @@ -1,7 +1,6 @@ -import type { CoinPublicKey } from '@midnight-ntwrk/compact-runtime'; import { beforeEach, describe, expect, it } from 'vitest'; +import * as utils from '#test-utils/address.js'; import { OwnableSimulator } from './simulators/OwnableSimulator.js'; -import * as utils from './utils/address.js'; // PKs const [OWNER, Z_OWNER] = utils.generateEitherPubKeyPair('OWNER'); @@ -18,7 +17,6 @@ const isInit = true; const isBadInit = false; let ownable: OwnableSimulator; -let caller: CoinPublicKey; const newOwnerTypes = [ ['contract', Z_OWNER_CONTRACT], @@ -90,86 +88,67 @@ describe('Ownable', () => { describe('assertOnlyOwner', () => { it('should allow owner to call', () => { - caller = OWNER; - expect(() => { - ownable.assertOnlyOwner(caller); + ownable.as(OWNER).assertOnlyOwner(); }).not.toThrow(); }); it('should fail when called by unauthorized', () => { - caller = UNAUTHORIZED; - expect(() => { - ownable.assertOnlyOwner(caller); + ownable.as(UNAUTHORIZED).assertOnlyOwner(); }).toThrow('Ownable: caller is not the owner'); }); }); describe('transferOwnership', () => { it('should transfer ownership', () => { - caller = OWNER; - ownable.transferOwnership(Z_NEW_OWNER, caller); + ownable.as(OWNER).transferOwnership(Z_NEW_OWNER); expect(ownable.owner()).toEqual(Z_NEW_OWNER); - // Old owner - caller = OWNER; + // Original owner expect(() => { - ownable.assertOnlyOwner(caller); + ownable.as(OWNER).assertOnlyOwner(); }).toThrow('Ownable: caller is not the owner'); - // Unauthorized - caller = UNAUTHORIZED; expect(() => { - ownable.assertOnlyOwner(caller); + ownable.as(UNAUTHORIZED).assertOnlyOwner(); }).toThrow('Ownable: caller is not the owner'); - // New owner - caller = NEW_OWNER; expect(() => { - ownable.assertOnlyOwner(caller); + ownable.as(NEW_OWNER).assertOnlyOwner(); }).not.toThrow(); }); it('should fail when unauthorized transfers ownership', () => { expect(() => { - caller = UNAUTHORIZED; - ownable.transferOwnership(Z_NEW_OWNER, caller); + ownable.as(UNAUTHORIZED).transferOwnership(Z_NEW_OWNER); }).toThrow('Ownable: caller is not the owner'); }); it('should fail when transferring to a contract address', () => { expect(() => { - caller = OWNER; - ownable.transferOwnership(Z_RECIPIENT_CONTRACT, caller); + ownable.as(OWNER).transferOwnership(Z_RECIPIENT_CONTRACT); }).toThrow('Ownable: unsafe ownership transfer'); }); it('should fail when transferring to zero (pk)', () => { - caller = OWNER; - expect(() => { - ownable.transferOwnership(utils.ZERO_KEY, caller); + ownable.as(OWNER).transferOwnership(utils.ZERO_KEY); }).toThrow('Ownable: invalid new owner'); }); it('should fail when transferring to zero (contract)', () => { - caller = OWNER; - expect(() => { - ownable.transferOwnership(utils.ZERO_ADDRESS, caller); + ownable.as(OWNER).transferOwnership(utils.ZERO_ADDRESS); }).toThrow('Ownable: unsafe ownership transfer'); }); it('should transfer multiple times', () => { - caller = OWNER; - ownable.transferOwnership(Z_NEW_OWNER, caller); + ownable.as(OWNER).transferOwnership(Z_NEW_OWNER); - caller = NEW_OWNER; - ownable.transferOwnership(Z_OWNER, caller); + ownable.as(NEW_OWNER).transferOwnership(Z_OWNER); - caller = OWNER; - ownable.transferOwnership(Z_NEW_OWNER, caller); + ownable.as(OWNER).transferOwnership(Z_NEW_OWNER); expect(ownable.owner()).toEqual(Z_NEW_OWNER); }); @@ -179,61 +158,48 @@ describe('Ownable', () => { describe.each( newOwnerTypes, )('when the owner is a %s', (type, newOwner) => { - caller = OWNER; - it('should transfer ownership', () => { - ownable._unsafeTransferOwnership(newOwner, caller); + ownable.as(OWNER)._unsafeTransferOwnership(newOwner); expect(ownable.owner()).toEqual(newOwner); - // Old owner - caller = OWNER; + // Original owner expect(() => { - ownable.assertOnlyOwner(caller); + ownable.as(OWNER).assertOnlyOwner(); }).toThrow('Ownable: caller is not the owner'); if (type === 'pubkey') { // New owner - caller = NEW_OWNER; expect(() => { - ownable.assertOnlyOwner(caller); + ownable.as(NEW_OWNER).assertOnlyOwner(); }).not.toThrow(); } }); }); it('should fail when unauthorized transfers ownership', () => { - caller = UNAUTHORIZED; - expect(() => { - ownable._unsafeTransferOwnership(Z_NEW_OWNER, caller); + ownable.as(UNAUTHORIZED)._unsafeTransferOwnership(Z_NEW_OWNER); }).toThrow('Ownable: caller is not the owner'); }); it('should fail when transferring to zero (pk)', () => { - caller = OWNER; - expect(() => { - ownable._unsafeTransferOwnership(utils.ZERO_KEY, caller); + ownable.as(OWNER)._unsafeTransferOwnership(utils.ZERO_KEY); }).toThrow('Ownable: invalid new owner'); }); it('should fail when transferring to zero (contract)', () => { - caller = OWNER; - expect(() => { - ownable._unsafeTransferOwnership(utils.ZERO_ADDRESS, caller); + ownable.as(OWNER)._unsafeTransferOwnership(utils.ZERO_ADDRESS); }).toThrow('Ownable: invalid new owner'); }); it('should transfer multiple times', () => { - caller = OWNER; - ownable._unsafeTransferOwnership(Z_NEW_OWNER, caller); + ownable.as(OWNER)._unsafeTransferOwnership(Z_NEW_OWNER); - caller = NEW_OWNER; - ownable._unsafeTransferOwnership(Z_OWNER, caller); + ownable.as(NEW_OWNER)._unsafeTransferOwnership(Z_OWNER); - caller = OWNER; - ownable._unsafeTransferOwnership(Z_OWNER_CONTRACT, caller); + ownable.as(OWNER)._unsafeTransferOwnership(Z_OWNER_CONTRACT); expect(ownable.owner()).toEqual(Z_OWNER_CONTRACT); }); @@ -243,24 +209,20 @@ describe('Ownable', () => { it('should renounce ownership', () => { expect(ownable.owner()).toEqual(Z_OWNER); - caller = OWNER; - ownable.renounceOwnership(caller); + ownable.as(OWNER).renounceOwnership(); // Check owner expect(ownable.owner()).toEqual(utils.ZERO_KEY); // Confirm revoked permissions - caller = OWNER; expect(() => { - ownable.assertOnlyOwner(caller); + ownable.as(OWNER).assertOnlyOwner(); }).toThrow('Ownable: caller is not the owner'); }); it('should fail when renouncing from unauthorized', () => { - caller = UNAUTHORIZED; - expect(() => { - ownable.renounceOwnership(caller); + ownable.as(UNAUTHORIZED).renounceOwnership(); }).toThrow('Ownable: caller is not the owner'); }); }); @@ -270,22 +232,17 @@ describe('Ownable', () => { ownable._transferOwnership(Z_NEW_OWNER); expect(ownable.owner()).toEqual(Z_NEW_OWNER); - // Old owner - caller = OWNER; + // Original owner expect(() => { - ownable.assertOnlyOwner(caller); + ownable.as(OWNER).assertOnlyOwner(); }).toThrow('Ownable: caller is not the owner'); - // Unauthorized - caller = UNAUTHORIZED; expect(() => { - ownable.assertOnlyOwner(caller); + ownable.as(UNAUTHORIZED).assertOnlyOwner(); }).toThrow('Ownable: caller is not the owner'); - // New owner - caller = NEW_OWNER; expect(() => { - ownable.assertOnlyOwner(caller); + ownable.as(NEW_OWNER).assertOnlyOwner(); }).not.toThrow(); }); @@ -307,14 +264,11 @@ describe('Ownable', () => { }); it('should transfer multiple times', () => { - caller = OWNER; - ownable._transferOwnership(Z_NEW_OWNER, caller); + ownable.as(OWNER)._transferOwnership(Z_NEW_OWNER); - caller = NEW_OWNER; - ownable._transferOwnership(Z_OWNER, caller); + ownable.as(NEW_OWNER)._transferOwnership(Z_OWNER); - caller = OWNER; - ownable._transferOwnership(Z_NEW_OWNER, caller); + ownable.as(OWNER)._transferOwnership(Z_NEW_OWNER); expect(ownable.owner()).toEqual(Z_NEW_OWNER); }); @@ -331,34 +285,27 @@ describe('Ownable', () => { it('should enforce permissions after transfer (pk)', () => { ownable._unsafeUncheckedTransferOwnership(Z_NEW_OWNER); - // Old owner - caller = OWNER; + // Original owner expect(() => { - ownable.assertOnlyOwner(caller); + ownable.as(OWNER).assertOnlyOwner(); }).toThrow('Ownable: caller is not the owner'); - // Unauthorized - caller = UNAUTHORIZED; expect(() => { - ownable.assertOnlyOwner(caller); + ownable.as(UNAUTHORIZED).assertOnlyOwner(); }).toThrow('Ownable: caller is not the owner'); // New owner - caller = NEW_OWNER; expect(() => { - ownable.assertOnlyOwner(caller); + ownable.as(NEW_OWNER).assertOnlyOwner(); }).not.toThrow(); }); it('should transfer multiple times', () => { - caller = OWNER; - ownable._unsafeUncheckedTransferOwnership(Z_NEW_OWNER, caller); + ownable.as(OWNER)._unsafeUncheckedTransferOwnership(Z_NEW_OWNER); - caller = NEW_OWNER; - ownable._unsafeUncheckedTransferOwnership(Z_OWNER, caller); + ownable.as(NEW_OWNER)._unsafeUncheckedTransferOwnership(Z_OWNER); - caller = OWNER; - ownable._unsafeUncheckedTransferOwnership(Z_OWNER_CONTRACT, caller); + ownable.as(OWNER)._unsafeUncheckedTransferOwnership(Z_OWNER_CONTRACT); expect(ownable.owner()).toEqual(Z_OWNER_CONTRACT); }); diff --git a/contracts/src/access/test/ZOwnablePK.test.ts b/contracts/src/access/test/ZOwnablePK.test.ts index 2dcb5987..2dcb62cd 100644 --- a/contracts/src/access/test/ZOwnablePK.test.ts +++ b/contracts/src/access/test/ZOwnablePK.test.ts @@ -5,10 +5,10 @@ import { persistentHash, } from '@midnight-ntwrk/compact-runtime'; import { beforeEach, describe, expect, it } from 'vitest'; -import type { ZswapCoinPublicKey } from '../../../artifacts/MockOwnable/contract/index.cjs'; +import * as utils from '#test-utils/address.js'; +import type { ZswapCoinPublicKey } from '../../../artifacts/MockOwnable/contract/index.js'; import { ZOwnablePKPrivateState } from '../witnesses/ZOwnablePKWitnesses.js'; import { ZOwnablePKSimulator } from './simulators/ZOwnablePKSimulator.js'; -import * as utils from './utils/address.js'; // PKs const [OWNER, Z_OWNER] = utils.generatePubKeyPair('OWNER'); diff --git a/contracts/src/access/test/mocks/MockAccessControl.compact b/contracts/src/access/test/mocks/MockAccessControl.compact index 0d4f9224..273121cc 100644 --- a/contracts/src/access/test/mocks/MockAccessControl.compact +++ b/contracts/src/access/test/mocks/MockAccessControl.compact @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma language_version >= 0.18.0; +pragma language_version >= 0.21.0; import CompactStandardLibrary; diff --git a/contracts/src/access/test/mocks/MockOwnable.compact b/contracts/src/access/test/mocks/MockOwnable.compact index 3675e663..ebbc6110 100644 --- a/contracts/src/access/test/mocks/MockOwnable.compact +++ b/contracts/src/access/test/mocks/MockOwnable.compact @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma language_version >= 0.18.0; +pragma language_version >= 0.21.0; import CompactStandardLibrary; diff --git a/contracts/src/access/test/mocks/MockZOwnablePK.compact b/contracts/src/access/test/mocks/MockZOwnablePK.compact index f35d5b4c..e0e5e18a 100644 --- a/contracts/src/access/test/mocks/MockZOwnablePK.compact +++ b/contracts/src/access/test/mocks/MockZOwnablePK.compact @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma language_version >= 0.18.0; +pragma language_version >= 0.21.0; import CompactStandardLibrary; import "../../ZOwnablePK" prefix ZOwnablePK_; diff --git a/contracts/src/access/test/simulators/AccessControlSimulator.ts b/contracts/src/access/test/simulators/AccessControlSimulator.ts index b9d0701c..8d8f06e8 100644 --- a/contracts/src/access/test/simulators/AccessControlSimulator.ts +++ b/contracts/src/access/test/simulators/AccessControlSimulator.ts @@ -1,89 +1,50 @@ import { - type CircuitContext, - type CoinPublicKey, - type ContractState, - constructorContext, - emptyZswapLocalState, - QueryContext, -} from '@midnight-ntwrk/compact-runtime'; -import { sampleContractAddress } from '@midnight-ntwrk/zswap'; + type BaseSimulatorOptions, + createSimulator, +} from '@openzeppelin-compact/contracts-simulator'; import { type ContractAddress, type Either, - type Ledger, ledger, Contract as MockAccessControl, type ZswapCoinPublicKey, -} from '../../../../artifacts/MockAccessControl/contract/index.cjs'; // Combined imports +} from '../../../../artifacts/MockAccessControl/contract/index.js'; import { - type AccessControlPrivateState, + AccessControlPrivateState, AccessControlWitnesses, } from '../../witnesses/AccessControlWitnesses.js'; -import type { IContractSimulator } from '../types/test.js'; /** - * @description A simulator implementation of a AccessControl contract for testing purposes. - * @template P - The private state type, fixed to AccessControlPrivateState. - * @template L - The ledger type, fixed to Contract.Ledger. + * Type constructor args */ -export class AccessControlSimulator - implements IContractSimulator -{ - /** @description The underlying contract instance managing contract logic. */ - readonly contract: MockAccessControl; +type AccessControlArgs = readonly []; + +const AccessControlSimulatorBase = createSimulator< + AccessControlPrivateState, + ReturnType, + ReturnType, + MockAccessControl, + AccessControlArgs +>({ + contractFactory: (witnesses) => + new MockAccessControl(witnesses), + defaultPrivateState: () => AccessControlPrivateState, + contractArgs: () => [], + ledgerExtractor: (state) => ledger(state), + witnessesFactory: () => AccessControlWitnesses(), +}); - /** @description The deployed address of the contract. */ - readonly contractAddress: string; - - /** @description The current circuit context, updated by contract operations. */ - circuitContext: CircuitContext; - - /** - * @description Initializes the mock contract. - */ - constructor() { - this.contract = new MockAccessControl( - AccessControlWitnesses, - ); - const { - currentPrivateState, - currentContractState, - currentZswapLocalState, - } = this.contract.initialState(constructorContext({}, '0'.repeat(64))); - this.circuitContext = { - currentPrivateState, - currentZswapLocalState, - originalState: currentContractState, - transactionContext: new QueryContext( - currentContractState.data, - sampleContractAddress(), - ), - }; - this.contractAddress = this.circuitContext.transactionContext.address; - } - - /** - * @description Retrieves the current public ledger state of the contract. - * @returns The ledger state as defined by the contract. - */ - public getPublicState(): Ledger { - return ledger(this.circuitContext.transactionContext.state); - } - - /** - * @description Retrieves the current private state of the contract. - * @returns The private state of type AccessControlPrivateState. - */ - public getPrivateState(): AccessControlPrivateState { - return this.circuitContext.currentPrivateState; - } - - /** - * @description Retrieves the current contract state. - * @returns The contract state object. - */ - public getContractState(): ContractState { - return this.circuitContext.originalState; +/** + * AccessControl Simulator + */ +export class AccessControlSimulator extends AccessControlSimulatorBase { + constructor( + options: BaseSimulatorOptions< + AccessControlPrivateState, + ReturnType + > = {}, + ) { + super([], options); } /** @@ -96,30 +57,15 @@ export class AccessControlSimulator roleId: Uint8Array, account: Either, ): boolean { - return this.contract.impureCircuits.hasRole( - this.circuitContext, - roleId, - account, - ).result; + return this.circuits.impure.hasRole(roleId, account); } /** * @description Retrieves an account's permission for `roleId`. - * @param caller - Optional. Sets the caller context if provided. * @param roleId - The role identifier. */ - public assertOnlyRole(roleId: Uint8Array, caller?: CoinPublicKey) { - const res = this.contract.impureCircuits.assertOnlyRole( - { - ...this.circuitContext, - currentZswapLocalState: caller - ? emptyZswapLocalState(caller) - : this.circuitContext.currentZswapLocalState, - }, - roleId, - ); - - this.circuitContext = res.context; + public assertOnlyRole(roleId: Uint8Array) { + this.circuits.impure.assertOnlyRole(roleId); } /** @@ -131,11 +77,7 @@ export class AccessControlSimulator roleId: Uint8Array, account: Either, ) { - this.circuitContext = this.contract.impureCircuits._checkRole( - this.circuitContext, - roleId, - account, - ).context; + this.circuits.impure._checkRole(roleId, account); } /** @@ -144,85 +86,43 @@ export class AccessControlSimulator * @returns The admin identifier for `roleId`. */ public getRoleAdmin(roleId: Uint8Array): Uint8Array { - return this.contract.impureCircuits.getRoleAdmin( - this.circuitContext, - roleId, - ).result; + return this.circuits.impure.getRoleAdmin(roleId); } /** * @description Grants an account permissions to use `roleId`. - * @param caller - Optional. Sets the caller context if provided. * @param roleId - The role identifier. * @param account - A ZswapCoinPublicKey or a ContractAddress. */ public grantRole( roleId: Uint8Array, account: Either, - caller?: CoinPublicKey, ) { - const res = this.contract.impureCircuits.grantRole( - { - ...this.circuitContext, - currentZswapLocalState: caller - ? emptyZswapLocalState(caller) - : this.circuitContext.currentZswapLocalState, - }, - roleId, - account, - ); - - this.circuitContext = res.context; + this.circuits.impure.grantRole(roleId, account); } /** * @description Revokes an account's permission to use `roleId`. - * @param caller - Optional. Sets the caller context if provided. * @param roleId - The role identifier. * @param account - A ZswapCoinPublicKey or a ContractAddress. */ public revokeRole( roleId: Uint8Array, account: Either, - caller?: CoinPublicKey, ) { - const res = this.contract.impureCircuits.revokeRole( - { - ...this.circuitContext, - currentZswapLocalState: caller - ? emptyZswapLocalState(caller) - : this.circuitContext.currentZswapLocalState, - }, - roleId, - account, - ); - - this.circuitContext = res.context; + this.circuits.impure.revokeRole(roleId, account); } /** * @description Revokes `roleId` from the calling account. - * @param caller - Optional. Sets the caller context if provided. * @param roleId - The role identifier. * @param account - A ZswapCoinPublicKey or a ContractAddress. */ public renounceRole( roleId: Uint8Array, account: Either, - caller?: CoinPublicKey, ) { - const res = this.contract.impureCircuits.renounceRole( - { - ...this.circuitContext, - currentZswapLocalState: caller - ? emptyZswapLocalState(caller) - : this.circuitContext.currentZswapLocalState, - }, - roleId, - account, - ); - - this.circuitContext = res.context; + this.circuits.impure.renounceRole(roleId, account); } /** @@ -231,11 +131,7 @@ export class AccessControlSimulator * @param adminId - The admin role identifier. */ public _setRoleAdmin(roleId: Uint8Array, adminId: Uint8Array) { - this.circuitContext = this.contract.impureCircuits._setRoleAdmin( - this.circuitContext, - roleId, - adminId, - ).context; + this.circuits.impure._setRoleAdmin(roleId, adminId); } /** @@ -247,14 +143,7 @@ export class AccessControlSimulator roleId: Uint8Array, account: Either, ): boolean { - const res = this.contract.impureCircuits._grantRole( - this.circuitContext, - roleId, - account, - ); - - this.circuitContext = res.context; - return res.result; + return this.circuits.impure._grantRole(roleId, account); } /** @@ -267,14 +156,7 @@ export class AccessControlSimulator roleId: Uint8Array, account: Either, ): boolean { - const res = this.contract.impureCircuits._unsafeGrantRole( - this.circuitContext, - roleId, - account, - ); - - this.circuitContext = res.context; - return res.result; + return this.circuits.impure._unsafeGrantRole(roleId, account); } /** @@ -286,13 +168,6 @@ export class AccessControlSimulator roleId: Uint8Array, account: Either, ): boolean { - const res = this.contract.impureCircuits._revokeRole( - this.circuitContext, - roleId, - account, - ); - - this.circuitContext = res.context; - return res.result; + return this.circuits.impure._revokeRole(roleId, account); } } diff --git a/contracts/src/access/test/simulators/OwnableSimulator.ts b/contracts/src/access/test/simulators/OwnableSimulator.ts index f89c310a..a7bfb447 100644 --- a/contracts/src/access/test/simulators/OwnableSimulator.ts +++ b/contracts/src/access/test/simulators/OwnableSimulator.ts @@ -1,223 +1,119 @@ import { - type CircuitContext, - type CoinPublicKey, - type ContractState, - constructorContext, - emptyZswapLocalState, - QueryContext, -} from '@midnight-ntwrk/compact-runtime'; -import { sampleContractAddress } from '@midnight-ntwrk/zswap'; + type BaseSimulatorOptions, + createSimulator, +} from '@openzeppelin-compact/contracts-simulator'; import { type ContractAddress, type Either, - type Ledger, ledger, Contract as MockOwnable, type ZswapCoinPublicKey, -} from '../../../../artifacts/MockOwnable/contract/index.cjs'; // Combined imports +} from '../../../../artifacts/MockOwnable/contract/index.js'; import { - type OwnablePrivateState, + OwnablePrivateState, OwnableWitnesses, } from '../../witnesses/OwnableWitnesses.js'; -import type { IContractSimulator } from '../types/test.js'; /** - * @description A simulator implementation of a Ownable contract for testing purposes. - * @template P - The private state type, fixed to OwnablePrivateState. - * @template L - The ledger type, fixed to Contract.Ledger. + * Type constructor args */ -export class OwnableSimulator - implements IContractSimulator -{ - /** @description The underlying contract instance managing contract logic. */ - readonly contract: MockOwnable; +type OwnableArgs = readonly [ + initialOwner: Either, + isInit: boolean, +]; + +const OwnableSimulatorBase = createSimulator< + OwnablePrivateState, + ReturnType, + ReturnType, + MockOwnable, + OwnableArgs +>({ + contractFactory: (witnesses) => + new MockOwnable(witnesses), + defaultPrivateState: () => OwnablePrivateState, + contractArgs: (initialOwner, isInit) => [initialOwner, isInit], + ledgerExtractor: (state) => ledger(state), + witnessesFactory: () => OwnableWitnesses(), +}); - /** @description The deployed address of the contract. */ - readonly contractAddress: string; - - /** @description The current circuit context, updated by contract operations. */ - circuitContext: CircuitContext; - - /** - * @description Initializes the mock contract. - */ +/** + * Ownable Simulator + */ +export class OwnableSimulator extends OwnableSimulatorBase { constructor( initialOwner: Either, isInit: boolean, + options: BaseSimulatorOptions< + OwnablePrivateState, + ReturnType + > = {}, ) { - this.contract = new MockOwnable(OwnableWitnesses); - const { - currentPrivateState, - currentContractState, - currentZswapLocalState, - } = this.contract.initialState( - constructorContext({}, '0'.repeat(64)), - initialOwner, - isInit, - ); - this.circuitContext = { - currentPrivateState, - currentZswapLocalState, - originalState: currentContractState, - transactionContext: new QueryContext( - currentContractState.data, - sampleContractAddress(), - ), - }; - this.contractAddress = this.circuitContext.transactionContext.address; + super([initialOwner, isInit], options); } - - /** - * @description Retrieves the current public ledger state of the contract. - * @returns The ledger state as defined by the contract. - */ - public getPublicState(): Ledger { - return ledger(this.circuitContext.transactionContext.state); - } - - /** - * @description Retrieves the current private state of the contract. - * @returns The private state of type OwnablePrivateState. - */ - public getPrivateState(): OwnablePrivateState { - return this.circuitContext.currentPrivateState; - } - - /** - * @description Retrieves the current contract state. - * @returns The contract state object. - */ - public getContractState(): ContractState { - return this.circuitContext.originalState; - } - /** * @description Returns the current contract owner. * @returns The contract owner. */ public owner(): Either { - return this.contract.impureCircuits.owner(this.circuitContext).result; + return this.circuits.impure.owner(); } /** * @description Transfers ownership of the contract to `newOwner`. * @param newOwner - The new owner. - * @param sender - Optional. Sets the caller context if provided. */ public transferOwnership( newOwner: Either, - sender?: CoinPublicKey, ) { - const res = this.contract.impureCircuits.transferOwnership( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - newOwner, - ); - - this.circuitContext = res.context; + this.circuits.impure.transferOwnership(newOwner); } /** * @description Unsafe variant of `transferOwnership`. * @param newOwner - The new owner. - * @param sender - Optional. Sets the caller context if provided. */ public _unsafeTransferOwnership( newOwner: Either, - sender?: CoinPublicKey, ) { - const res = this.contract.impureCircuits._unsafeTransferOwnership( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - newOwner, - ); - - this.circuitContext = res.context; + this.circuits.impure._unsafeTransferOwnership(newOwner); } /** * @description Leaves the contract without an owner. * It will not be possible to call `assertOnlyOnwer` circuits anymore. * Can only be called by the current owner. - * @param sender - Optional. Sets the caller context if provided. */ - public renounceOwnership(sender?: CoinPublicKey) { - const res = this.contract.impureCircuits.renounceOwnership({ - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }); - - this.circuitContext = res.context; + public renounceOwnership() { + this.circuits.impure.renounceOwnership(); } /** * @description Throws if called by any account other than the owner. * Use this to restrict access of specific circuits to the owner. - * @param sender - Optional. Sets the caller context if provided. */ - public assertOnlyOwner(sender?: CoinPublicKey) { - const res = this.contract.impureCircuits.assertOnlyOwner({ - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }); - - this.circuitContext = res.context; + public assertOnlyOwner() { + this.circuits.impure.assertOnlyOwner(); } /** * @description Transfers ownership of the contract to `newOwner` without * enforcing permission checks on the caller. * @param newOwner - The new owner. - * @param sender - Optional. Sets the caller context if provided. */ public _transferOwnership( newOwner: Either, - sender?: CoinPublicKey, ) { - const res = this.contract.impureCircuits._transferOwnership( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - newOwner, - ); - - this.circuitContext = res.context; + this.circuits.impure._transferOwnership(newOwner); } /** * @description Unsafe variant of `_transferOwnership`. * @param newOwner - The new owner. - * @param sender - Optional. Sets the caller context if provided. */ public _unsafeUncheckedTransferOwnership( newOwner: Either, - sender?: CoinPublicKey, ) { - const res = this.contract.impureCircuits._unsafeUncheckedTransferOwnership( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - newOwner, - ); - - this.circuitContext = res.context; + this.circuits.impure._unsafeUncheckedTransferOwnership(newOwner); } } diff --git a/contracts/src/access/test/simulators/ZOwnablePKSimulator.ts b/contracts/src/access/test/simulators/ZOwnablePKSimulator.ts index 82fcc70e..5dd24cf9 100644 --- a/contracts/src/access/test/simulators/ZOwnablePKSimulator.ts +++ b/contracts/src/access/test/simulators/ZOwnablePKSimulator.ts @@ -6,9 +6,9 @@ import { type ContractAddress, type Either, ledger, - Contract as MockOwnable, + Contract as MockZOwnablePK, type ZswapCoinPublicKey, -} from '../../../../artifacts/MockZOwnablePK/contract/index.cjs'; +} from '../../../../artifacts/MockZOwnablePK/contract/index.js'; import { ZOwnablePKPrivateState, ZOwnablePKWitnesses, @@ -37,10 +37,11 @@ const ZOwnablePKSimulatorBase: any = createSimulator< ZOwnablePKPrivateState, ReturnType, ReturnType, + MockZOwnablePK, ZOwnablePKArgs >({ contractFactory: (witnesses) => - new MockOwnable(witnesses), + new MockZOwnablePK(witnesses), defaultPrivateState: () => ZOwnablePKPrivateState.generate(), contractArgs: (owner, instanceSalt, isInit) => { return [owner, instanceSalt, isInit]; diff --git a/contracts/src/access/test/types/test.ts b/contracts/src/access/test/types/test.ts deleted file mode 100644 index 643def10..00000000 --- a/contracts/src/access/test/types/test.ts +++ /dev/null @@ -1,102 +0,0 @@ -import type { - CircuitContext, - ContractState, -} from '@midnight-ntwrk/compact-runtime'; - -/** - * Interface defining a generic contract simulator. - * - * @template P - Type representing the private contract state. - * @template L - Type representing the public ledger state. - */ -export interface IContractSimulator { - /** - * The deployed contract's address. - */ - readonly contractAddress: string; - - /** - * The current circuit context holding the contract state. - */ - circuitContext: CircuitContext

; - - /** - * Returns the current public ledger state. - * - * @returns The current ledger state of type L. - */ - getPublicState(): L; - - /** - * Returns the current private contract state. - * - * @returns The current private state of type P. - */ - getPrivateState(): P; - - /** - * Returns the original contract state. - * - * @returns The current contract state. - */ - getContractState(): ContractState; -} - -/** - * Extracts pure circuits from a contract type. - * - * Pure circuits are those in `circuits` but not in `impureCircuits`. - * - * @template TContract - Contract type with `circuits` and `impureCircuits`. - */ -export type ExtractPureCircuits = TContract extends { - circuits: infer TCircuits extends Record; - impureCircuits: infer TImpureCircuits extends Record; -} - ? Omit - : never; - -/** - * Extracts impure circuits from a contract type. - * - * Impure circuits are those in `impureCircuits`. - * - * @template TContract - Contract type with `circuits` and `impureCircuits`. - */ -export type ExtractImpureCircuits = TContract extends { - impureCircuits: infer TImpureCircuits; -} - ? TImpureCircuits - : never; - -/** - * Transforms a collection of circuit functions by removing the explicit `CircuitContext` parameter, - * producing a version of each function that can be called without passing the context explicitly. - * - * Each original circuit function is expected to have the signature: - * `(ctx: CircuitContext, ...args) => { result: R; context: CircuitContext }` - * or a compatible shape. - * - * The transformed type maps each key `K` of the input `Circuits` type to a new function - * that takes the same parameters as the original, *except* the first `CircuitContext` argument, - * and returns the `result` part `R` directly. - * - * @template Circuits - An object type whose values are circuit functions accepting a `CircuitContext` - * and returning an object with `result` and optionally `context`. - * @template TState - The type representing the private or contract state passed inside `CircuitContext`. - */ -export type ContextlessCircuits = { - [K in keyof Circuits]: Circuits[K] extends ( - ctx: CircuitContext, - ...args: infer P - ) => { result: infer R; context: CircuitContext } - ? (...args: P) => R - : never; -}; - -export type SimulatorOptions any> = { - address?: string; - coinPK?: string; - privateState?: PS; - witnesses?: ReturnType; -}; diff --git a/contracts/src/access/test/utils/AbstractContractSimulator.ts b/contracts/src/access/test/utils/AbstractContractSimulator.ts deleted file mode 100644 index 36ac5d73..00000000 --- a/contracts/src/access/test/utils/AbstractContractSimulator.ts +++ /dev/null @@ -1,131 +0,0 @@ -import type { - CircuitContext, - ContractState, -} from '@midnight-ntwrk/compact-runtime'; -import type { ContextlessCircuits, IContractSimulator } from '../types/test.js'; - -/** - * Abstract base class for simulating contract behavior. - * Provides common functionality for managing circuit contexts and creating proxies - * for pure and impure circuit functions. - * - * @template P - The type representing the private state of the contract. - * @template L - The type representing the public ledger (contract) state. - */ -export abstract class AbstractContractSimulator - implements IContractSimulator -{ - /** - * The deployed contract's address. - * Must be implemented by concrete subclasses. - */ - abstract readonly contractAddress: string; - - /** - * The current circuit context containing private state, contract state, and transaction context. - * Must be implemented by concrete subclasses. - */ - abstract circuitContext: CircuitContext

; - - /** - * Retrieves the current public ledger state of the contract. - * Must be implemented by concrete subclasses. - * - * @returns The current public ledger state. - */ - abstract getPublicState(): L; - - /** - * Retrieves the current private state from the circuit context. - * - * @returns The current private state of the contract. - */ - public getPrivateState(): P { - return this.circuitContext.currentPrivateState; - } - - /** - * Retrieves the original contract state from the circuit context. - * - * @returns The original contract state. - */ - public getContractState(): ContractState { - return this.circuitContext.originalState; - } - - /** - * Creates a proxy wrapper around pure circuits. - * Pure circuits do not modify contract state, so only the result is returned. - * - * @template Circuits - The type of the circuits object to proxy. - * @param circuits - The original circuits object containing functions accepting a CircuitContext. - * @param context - A function returning the current CircuitContext to pass to circuit functions. - * @returns A proxy with contextless circuits that accept the original arguments and return only results. - */ - protected createPureCircuitProxy( - circuits: Circuits, - context: () => CircuitContext

, - ): ContextlessCircuits { - return new Proxy(circuits, { - get(target, prop, receiver) { - const original = Reflect.get(target, prop, receiver); - - if (typeof original !== 'function') return original; - - return (...args: any[]) => { - const ctx = context(); - - const fn = original as ( - ctx: CircuitContext

, - ...args: any[] - ) => { result: any }; - - return fn(ctx, ...args).result; - }; - }, - }) as ContextlessCircuits; - } - - /** - * Creates a proxy wrapper around impure circuits. - * Impure circuits can modify contract state, so the circuit context is updated accordingly. - * - * @template Circuits - The type of the circuits object to proxy. - * @param circuits - The original circuits object containing functions accepting a CircuitContext. - * @param context - A function returning the current CircuitContext to pass to circuit functions. - * @param updateContext - A callback to update the circuit context with the new context returned by the circuit. - * @returns A proxy with contextless circuits that accept the original arguments, update context, and return results. - */ - protected createImpureCircuitProxy( - circuits: Circuits, - context: () => CircuitContext

, - updateContext: (ctx: CircuitContext

) => void, - ): ContextlessCircuits { - return new Proxy(circuits, { - get(target, prop, receiver) { - const original = Reflect.get(target, prop, receiver); - - if (typeof original !== 'function') return original; - - return (...args: any[]) => { - const ctx = context(); - - const fn = original as ( - ctx: CircuitContext

, - ...args: any[] - ) => { result: any; context: CircuitContext

}; - - const { result, context: newCtx } = fn(ctx, ...args); - updateContext(newCtx); - return result; - }; - }, - }) as ContextlessCircuits; - } - - /** - * Optional method to reset any cached circuit proxies. - * Concrete subclasses can override this to clear proxies if needed. - */ - public resetCircuitProxies?(): void {} -} diff --git a/contracts/src/access/test/utils/SimualatorStateManager.ts b/contracts/src/access/test/utils/SimualatorStateManager.ts deleted file mode 100644 index ac06fdba..00000000 --- a/contracts/src/access/test/utils/SimualatorStateManager.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { - type CircuitContext, - type ConstructorContext, - type ContractState, - constructorContext, - QueryContext, - sampleContractAddress, -} from '@midnight-ntwrk/compact-runtime'; - -/** - * A composable utility class for managing Compact contract state in simulations. - * - * This class handles initialization and lifecycle management of the `CircuitContext`, - * which includes private state, public (ledger) state, zswap local state, and transaction context. - * - * It is designed to be embedded compositionally inside contract simulator classes - * (e.g., `FooSimulator`), enabling better separation of concerns and easier test setup. - * - * @template P - The type of the contract's private state. - * - * ### Responsibilities - * - Initializes the contract state using the compiled contract's `.initialState` method. - * - Stores and exposes the `CircuitContext` via getters/setters. - * - Supports injection of private state and contract constructor arguments. - * - Allows the owning simulator to update private state manually during testing. - * - * ### Example Usage: - * ```ts - * const contract = new MyContract(witnesses); - * const manager = new SimulatorStateManager( - * contract, - * { foo: 1n }, // initial private state - * '0'.repeat(64), // coin public key - * sampleContractAddress(), // optional contract address - * arg1, arg2 // additional constructor args - * ); - * - * const context = manager.getContext(); - * ``` - */ -export class SimulatorStateManager

{ - private context: CircuitContext

; - - /** - * Creates an instance of `SimulatorStateManager`. - * - * @param contract - A compiled Compact contract instance (from artifacts), exposing `initialState()`. - * @param privateState - The initial private state to inject into the contract. - * @param coinPK - The caller's coin public key (used to create the constructor context). - * @param contractAddress - Optional override for the contract's address. Defaults to `sampleContractAddress` if not provided. - * @param contractArgs - Additional arguments to pass to the contract constructor (e.g., circuit params). - */ - constructor( - contract: { - initialState: ( - ctx: ConstructorContext

, - ...args: any[] - ) => { - currentPrivateState: P; - currentContractState: ContractState; - currentZswapLocalState: any; - }; - }, - privateState: P, - coinPK: string, - contractAddress?: string, - ...contractArgs: any[] - ) { - const initCtx = constructorContext(privateState, coinPK); - - const { - currentPrivateState, - currentContractState, - currentZswapLocalState, - } = contract.initialState(initCtx, ...contractArgs); - - this.context = { - currentPrivateState, - currentZswapLocalState, - originalState: currentContractState, - transactionContext: new QueryContext( - currentContractState.data, - contractAddress ?? sampleContractAddress(), - ), - }; - } - - /** - * Retrieves the current `CircuitContext`, including private state, - * zswap state, contract state, and transaction context. - */ - getContext(): CircuitContext

{ - return this.context; - } - - /** - * Replaces the internal `CircuitContext` with a new one. - * - * Useful when circuits mutate state and return an updated context. - */ - setContext(newContext: CircuitContext

) { - this.context = newContext; - } - - /** - * Updates just the private state inside the existing context. - * - * This is a lightweight way to simulate local state changes without reconstructing the full context. - * - * @param newPrivateState - The new private state object to apply. - */ - updatePrivateState(newPrivateState: P) { - this.context.currentPrivateState = newPrivateState; - } -} diff --git a/contracts/src/access/test/utils/createCircuitProxies.ts b/contracts/src/access/test/utils/createCircuitProxies.ts deleted file mode 100644 index 8aa500da..00000000 --- a/contracts/src/access/test/utils/createCircuitProxies.ts +++ /dev/null @@ -1,64 +0,0 @@ -import type { CircuitContext } from '@midnight-ntwrk/compact-runtime'; -import type { - ContextlessCircuits, - ExtractImpureCircuits, - ExtractPureCircuits, -} from '../types/test.js'; - -/** - * Creates lazily-initialized circuit proxies for pure and impure contract functions. - */ -export function createCircuitProxies< - P, - ContractType extends { - circuits: Record; - impureCircuits: Record; - }, ->( - contract: ContractType, - getContext: () => CircuitContext

, - getCallerContext: () => CircuitContext

, - updateContext: (ctx: CircuitContext

) => void, - createPureProxy: >( - circuits: C, - context: () => CircuitContext

, - ) => ContextlessCircuits, - createImpureProxy: >( - circuits: C, - context: () => CircuitContext

, - updateContext: (ctx: CircuitContext

) => void, - ) => ContextlessCircuits, -) { - let pureProxy: - | ContextlessCircuits, P> - | undefined; - let impureProxy: - | ContextlessCircuits, P> - | undefined; - - return { - get circuits() { - if (!pureProxy) { - pureProxy = createPureProxy( - contract.circuits as ExtractPureCircuits, - getContext, - ); - } - if (!impureProxy) { - impureProxy = createImpureProxy( - contract.impureCircuits as ExtractImpureCircuits, - getCallerContext, - updateContext, - ); - } - return { - pure: pureProxy, - impure: impureProxy, - }; - }, - resetProxies() { - pureProxy = undefined; - impureProxy = undefined; - }, - }; -} diff --git a/contracts/src/access/test/utils/test.ts b/contracts/src/access/test/utils/test.ts deleted file mode 100644 index 52e92528..00000000 --- a/contracts/src/access/test/utils/test.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { - type CircuitContext, - type CoinPublicKey, - type ContractAddress, - type ContractState, - emptyZswapLocalState, - QueryContext, -} from '@midnight-ntwrk/compact-runtime'; -import type { IContractSimulator } from '../types/test.js'; - -/** - * Constructs a `CircuitContext` from the given state and sender information. - * - * This is typically used at runtime to provide the necessary context - * for executing circuits, including contract state, private state, - * sender identity, and transaction data. - * - * @template P - The type of the contract's private state. - * @param privateState - The current private state of the contract. - * @param contractState - The full contract state, including public and private data. - * @param sender - The public key of the sender (used in the circuit). - * @param contractAddress - The address of the deployed contract. - * @returns A fully populated `CircuitContext` for circuit execution. - * @todo TODO: Move this utility to a generic package for broader reuse across contracts. - */ -export function useCircuitContext

( - privateState: P, - contractState: ContractState, - sender: CoinPublicKey, - contractAddress: ContractAddress, -): CircuitContext

{ - return { - originalState: contractState, - currentPrivateState: privateState, - transactionContext: new QueryContext(contractState.data, contractAddress), - currentZswapLocalState: emptyZswapLocalState(sender), - }; -} - -/** - * Prepares a new `CircuitContext` using the given sender and contract. - * - * Useful for mocking or updating the circuit context with a custom sender. - * - * @template P - The type of the contract's private state. - * @template L - The type of the contract's ledger (public state). - * @template C - The specific type of the contract implementing `MockContract`. - * @param contract - The contract instance implementing `MockContract`. - * @param sender - The public key to set as the sender in the new circuit context. - * @returns A new `CircuitContext` with the sender and updated context values. - * @todo TODO: Move this utility to a generic package for broader reuse across contracts. - */ -export function useCircuitContextSender< - P, - L, - C extends IContractSimulator, ->(contract: C, sender: CoinPublicKey): CircuitContext

{ - const currentPrivateState = contract.getPrivateState(); - const originalState = contract.getContractState(); - const contractAddress = contract.contractAddress; - - return { - originalState, - currentPrivateState, - transactionContext: new QueryContext(originalState.data, contractAddress), - currentZswapLocalState: emptyZswapLocalState(sender), - }; -} diff --git a/contracts/src/access/witnesses/AccessControlWitnesses.ts b/contracts/src/access/witnesses/AccessControlWitnesses.ts index 454fb380..d73ecf81 100644 --- a/contracts/src/access/witnesses/AccessControlWitnesses.ts +++ b/contracts/src/access/witnesses/AccessControlWitnesses.ts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Compact Contracts v0.0.1-alpha.1 (access/witnesses/AccessControlWitnesses.ts) -// This is how we type an empty object. export type AccessControlPrivateState = Record; -export const AccessControlWitnesses = {}; +export const AccessControlPrivateState: AccessControlPrivateState = {}; +export const AccessControlWitnesses = () => ({}); diff --git a/contracts/src/access/witnesses/OwnableWitnesses.ts b/contracts/src/access/witnesses/OwnableWitnesses.ts index 561b62b5..a3d39a17 100644 --- a/contracts/src/access/witnesses/OwnableWitnesses.ts +++ b/contracts/src/access/witnesses/OwnableWitnesses.ts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Compact Contracts v0.0.1-alpha.1 (access/witnesses/OwnableWitnesses.ts) -// This is how we type an empty object. export type OwnablePrivateState = Record; -export const OwnableWitnesses = {}; +export const OwnablePrivateState: OwnablePrivateState = {}; +export const OwnableWitnesses = () => ({}); diff --git a/contracts/src/access/witnesses/ZOwnablePKWitnesses.ts b/contracts/src/access/witnesses/ZOwnablePKWitnesses.ts index 62cc3bba..6453011d 100644 --- a/contracts/src/access/witnesses/ZOwnablePKWitnesses.ts +++ b/contracts/src/access/witnesses/ZOwnablePKWitnesses.ts @@ -1,6 +1,6 @@ import { getRandomValues } from 'node:crypto'; import type { WitnessContext } from '@midnight-ntwrk/compact-runtime'; -import type { Ledger } from '../../../artifacts/MockZOwnablePK/contract/index.cjs'; +import type { Ledger } from '../../../artifacts/MockZOwnablePK/contract/index.js'; /** * @description Interface defining the witness methods for ZOwnablePK operations. diff --git a/contracts/src/archive/ShieldedToken.compact b/contracts/src/archive/ShieldedToken.compact index 16663c03..599b0a41 100644 --- a/contracts/src/archive/ShieldedToken.compact +++ b/contracts/src/archive/ShieldedToken.compact @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Compact Contracts v0.0.1-alpha.1 (archive/ShieldedToken.compact) -pragma language_version >= 0.18.0; +pragma language_version >= 0.21.0; /** * @module ShieldedToken (archived until further notice, DO NOT USE IN PRODUCTION) diff --git a/contracts/src/archive/test/ShieldedToken.test.ts b/contracts/src/archive/test/ShieldedToken.test.ts index bc7de82b..dac0b238 100644 --- a/contracts/src/archive/test/ShieldedToken.test.ts +++ b/contracts/src/archive/test/ShieldedToken.test.ts @@ -6,7 +6,7 @@ import { tokenType, } from '@midnight-ntwrk/onchain-runtime'; import { beforeEach, describe, expect, it } from 'vitest'; -import type { Maybe } from '../../../artifacts/MockShieldedToken/contract/index.cjs'; // Combined imports +import type { Maybe } from '../../../artifacts/MockShieldedToken/contract/index.js'; // Combined imports import { ShieldedTokenSimulator } from './simulators/ShieldedTokenSimulator.js'; import * as utils from './utils/address.js'; diff --git a/contracts/src/archive/test/mocks/MockShieldedToken.compact b/contracts/src/archive/test/mocks/MockShieldedToken.compact index d32b72ba..68c0fc35 100644 --- a/contracts/src/archive/test/mocks/MockShieldedToken.compact +++ b/contracts/src/archive/test/mocks/MockShieldedToken.compact @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma language_version >= 0.18.0; +pragma language_version >= 0.21.0; import CompactStandardLibrary; import "../../ShieldedToken" prefix ShieldedToken_; diff --git a/contracts/src/archive/test/simulators/ShieldedTokenSimulator.ts b/contracts/src/archive/test/simulators/ShieldedTokenSimulator.ts index 6abf905d..e0b6ae24 100644 --- a/contracts/src/archive/test/simulators/ShieldedTokenSimulator.ts +++ b/contracts/src/archive/test/simulators/ShieldedTokenSimulator.ts @@ -3,7 +3,7 @@ import { type CircuitResults, type CoinPublicKey, type ContractState, - constructorContext, + createConstructorContext, emptyZswapLocalState, QueryContext, } from '@midnight-ntwrk/compact-runtime'; @@ -18,7 +18,7 @@ import { Contract as MockShielded, type SendResult, type ZswapCoinPublicKey, -} from '../../../../artifacts/MockShieldedToken/contract/index.cjs'; // Combined imports +} from '../../../../artifacts/MockShieldedToken/contract/index.js'; // Combined imports import { type ShieldedTokenPrivateState, ShieldedTokenWitnesses, @@ -59,7 +59,7 @@ export class ShieldedTokenSimulator currentContractState, currentZswapLocalState, } = this.contract.initialState( - constructorContext({}, '0'.repeat(64)), + createConstructorContext({}, '0'.repeat(64)), nonce, name, symbol, diff --git a/contracts/src/archive/test/utils/address.ts b/contracts/src/archive/test/utils/address.ts index 441f9c93..cbba8b7b 100644 --- a/contracts/src/archive/test/utils/address.ts +++ b/contracts/src/archive/test/utils/address.ts @@ -2,8 +2,8 @@ import { convertFieldToBytes, encodeCoinPublicKey, } from '@midnight-ntwrk/compact-runtime'; -import { encodeContractAddress } from '@midnight-ntwrk/ledger'; -import type * as Compact from '../../../../artifacts/MockShieldedToken/contract/index.cjs'; +import { encodeContractAddress } from '@midnight-ntwrk/ledger-v7'; +import type * as Compact from '../../../../artifacts/MockShieldedToken/contract/index.js'; const PREFIX_ADDRESS = '0200'; diff --git a/contracts/src/security/Initializable.compact b/contracts/src/security/Initializable.compact index a1855180..ae1b93c9 100644 --- a/contracts/src/security/Initializable.compact +++ b/contracts/src/security/Initializable.compact @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Compact Contracts v0.0.1-alpha.1 (security/Initializable.compact) -pragma language_version >= 0.18.0; +pragma language_version >= 0.21.0; /** * @module Initializable diff --git a/contracts/src/security/Pausable.compact b/contracts/src/security/Pausable.compact index cc474e52..3f118450 100644 --- a/contracts/src/security/Pausable.compact +++ b/contracts/src/security/Pausable.compact @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Compact Contracts v0.0.1-alpha.1 (security/Pausable.compact) -pragma language_version >= 0.18.0; +pragma language_version >= 0.21.0; /** * @module Pausable diff --git a/contracts/src/security/test/Initializable.test.ts b/contracts/src/security/test/Initializable.test.ts index db1a7b58..5f96eea9 100644 --- a/contracts/src/security/test/Initializable.test.ts +++ b/contracts/src/security/test/Initializable.test.ts @@ -10,22 +10,22 @@ describe('Initializable', () => { it('should generate the initial ledger state deterministically', () => { const initializable2 = new InitializableSimulator(); - expect(initializable.getCurrentPublicState()).toEqual( - initializable2.getCurrentPublicState(), + expect(initializable.getPublicState()).toEqual( + initializable2.getPublicState(), ); }); describe('initialize', () => { it('should not be initialized', () => { expect( - initializable.getCurrentPublicState().Initializable__isInitialized, + initializable.getPublicState().Initializable__isInitialized, ).toEqual(false); }); it('should initialize', () => { initializable.initialize(); expect( - initializable.getCurrentPublicState().Initializable__isInitialized, + initializable.getPublicState().Initializable__isInitialized, ).toEqual(true); }); }); diff --git a/contracts/src/security/test/mocks/MockInitializable.compact b/contracts/src/security/test/mocks/MockInitializable.compact index 90c3b2fe..ca5dd3fc 100644 --- a/contracts/src/security/test/mocks/MockInitializable.compact +++ b/contracts/src/security/test/mocks/MockInitializable.compact @@ -1,4 +1,4 @@ -pragma language_version >= 0.18.0; +pragma language_version >= 0.21.0; import CompactStandardLibrary; import "../../Initializable" prefix Initializable_; diff --git a/contracts/src/security/test/mocks/MockPausable.compact b/contracts/src/security/test/mocks/MockPausable.compact index bd1740e2..da9d79a9 100644 --- a/contracts/src/security/test/mocks/MockPausable.compact +++ b/contracts/src/security/test/mocks/MockPausable.compact @@ -1,4 +1,4 @@ -pragma language_version >= 0.18.0; +pragma language_version >= 0.21.0; import CompactStandardLibrary; import "../../Pausable" prefix Pausable_; diff --git a/contracts/src/security/test/simulators/InitializableSimulator.ts b/contracts/src/security/test/simulators/InitializableSimulator.ts index 52bb6530..99a68263 100644 --- a/contracts/src/security/test/simulators/InitializableSimulator.ts +++ b/contracts/src/security/test/simulators/InitializableSimulator.ts @@ -1,93 +1,54 @@ import { - type CircuitContext, - type ContractState, - constructorContext, - QueryContext, - sampleContractAddress, -} from '@midnight-ntwrk/compact-runtime'; + type BaseSimulatorOptions, + createSimulator, +} from '@openzeppelin-compact/contracts-simulator'; import { - type Ledger, ledger, Contract as MockInitializable, -} from '../../../../artifacts/MockInitializable/contract/index.cjs'; +} from '../../../../artifacts/MockInitializable/contract/index.js'; import { - type InitializablePrivateState, + InitializablePrivateState, InitializableWitnesses, } from '../../witnesses/InitializableWitnesses.js'; -import type { IContractSimulator } from '../types/test.js'; /** - * @description A simulator implementation of an utils contract for testing purposes. - * @template P - The private state type, fixed to UtilsPrivateState. - * @template L - The ledger type, fixed to Contract.Ledger. + * Type constructor args */ -export class InitializableSimulator - implements IContractSimulator -{ - /** @description The underlying contract instance managing contract logic. */ - readonly contract: MockInitializable; +type InitializableArgs = readonly []; - /** @description The deployed address of the contract. */ - readonly contractAddress: string; +const InitializableSimulatorBase = createSimulator< + InitializablePrivateState, + ReturnType, + ReturnType, + MockInitializable, + InitializableArgs +>({ + contractFactory: (witnesses) => + new MockInitializable(witnesses), + defaultPrivateState: () => InitializablePrivateState, + contractArgs: () => [], + ledgerExtractor: (state) => ledger(state), + witnessesFactory: () => InitializableWitnesses(), +}); - /** @description The current circuit context, updated by contract operations. */ - circuitContext: CircuitContext; - - /** - * @description Initializes the mock contract. - */ - constructor() { - this.contract = new MockInitializable( - InitializableWitnesses, - ); - const { - currentPrivateState, - currentContractState, - currentZswapLocalState, - } = this.contract.initialState(constructorContext({}, '0'.repeat(64))); - this.circuitContext = { - currentPrivateState, - currentZswapLocalState, - originalState: currentContractState, - transactionContext: new QueryContext( - currentContractState.data, - sampleContractAddress(), - ), - }; - this.contractAddress = this.circuitContext.transactionContext.address; - } - - /** - * @description Retrieves the current public ledger state of the contract. - * @returns The ledger state as defined by the contract. - */ - public getCurrentPublicState(): Ledger { - return ledger(this.circuitContext.transactionContext.state); - } - - /** - * @description Retrieves the current private state of the contract. - * @returns The private state of type UtilsPrivateState. - */ - public getCurrentPrivateState(): InitializablePrivateState { - return this.circuitContext.currentPrivateState; - } - - /** - * @description Retrieves the current contract state. - * @returns The contract state object. - */ - public getCurrentContractState(): ContractState { - return this.circuitContext.originalState; +/** + * Initializable Simulator + */ +export class InitializableSimulator extends InitializableSimulatorBase { + constructor( + options: BaseSimulatorOptions< + InitializablePrivateState, + ReturnType + > = {}, + ) { + super([], options); } /** * @description Initializes the state. */ public initialize() { - this.circuitContext = this.contract.impureCircuits.initialize( - this.circuitContext, - ).context; + this.circuits.impure.initialize(); } /** @@ -95,8 +56,7 @@ export class InitializableSimulator * @throws Will throw "Initializable: contract not initialized" if the contract is not initialized. */ public assertInitialized() { - return this.contract.impureCircuits.assertInitialized(this.circuitContext) - .result; + this.circuits.impure.assertInitialized(); } /** @@ -104,8 +64,6 @@ export class InitializableSimulator * @throws Will throw "Initializable: contract already initialized" if the contract is already initialized. */ public assertNotInitialized() { - return this.contract.impureCircuits.assertNotInitialized( - this.circuitContext, - ).result; + this.circuits.impure.assertNotInitialized(); } } diff --git a/contracts/src/security/test/simulators/PausableSimulator.ts b/contracts/src/security/test/simulators/PausableSimulator.ts index 878bcff0..34ff6779 100644 --- a/contracts/src/security/test/simulators/PausableSimulator.ts +++ b/contracts/src/security/test/simulators/PausableSimulator.ts @@ -1,82 +1,47 @@ import { - type CircuitContext, - type ContractState, - constructorContext, - QueryContext, - sampleContractAddress, -} from '@midnight-ntwrk/compact-runtime'; + type BaseSimulatorOptions, + createSimulator, +} from '@openzeppelin-compact/contracts-simulator'; import { - type Ledger, ledger, Contract as MockPausable, -} from '../../../../artifacts/MockPausable/contract/index.cjs'; +} from '../../../../artifacts/MockPausable/contract/index.js'; import { - type PausablePrivateState, + PausablePrivateState, PausableWitnesses, } from '../../witnesses/PausableWitnesses.js'; -import type { IContractSimulator } from '../types/test.js'; /** - * @description A simulator implementation of an utils contract for testing purposes. - * @template P - The private state type, fixed to UtilsPrivateState. - * @template L - The ledger type, fixed to Contract.Ledger. + * Type constructor args */ -export class PausableSimulator - implements IContractSimulator -{ - /** @description The underlying contract instance managing contract logic. */ - readonly contract: MockPausable; +type PausableArgs = readonly []; - /** @description The deployed address of the contract. */ - readonly contractAddress: string; +const PausableSimulatorBase = createSimulator< + PausablePrivateState, + ReturnType, + ReturnType, + MockPausable, + PausableArgs +>({ + contractFactory: (witnesses) => + new MockPausable(witnesses), + defaultPrivateState: () => PausablePrivateState, + contractArgs: () => [], + ledgerExtractor: (state) => ledger(state), + witnessesFactory: () => PausableWitnesses(), +}); - /** @description The current circuit context, updated by contract operations. */ - circuitContext: CircuitContext; - - /** - * @description Initializes the mock contract. - */ - constructor() { - this.contract = new MockPausable(PausableWitnesses); - const { - currentPrivateState, - currentContractState, - currentZswapLocalState, - } = this.contract.initialState(constructorContext({}, '0'.repeat(64))); - this.circuitContext = { - currentPrivateState, - currentZswapLocalState, - originalState: currentContractState, - transactionContext: new QueryContext( - currentContractState.data, - sampleContractAddress(), - ), - }; - this.contractAddress = this.circuitContext.transactionContext.address; - } - - /** - * @description Retrieves the current public ledger state of the contract. - * @returns The ledger state as defined by the contract. - */ - public getCurrentPublicState(): Ledger { - return ledger(this.circuitContext.transactionContext.state); - } - - /** - * @description Retrieves the current private state of the contract. - * @returns The private state of type UtilsPrivateState. - */ - public getCurrentPrivateState(): PausablePrivateState { - return this.circuitContext.currentPrivateState; - } - - /** - * @description Retrieves the current contract state. - * @returns The contract state object. - */ - public getCurrentContractState(): ContractState { - return this.circuitContext.originalState; +/** + * Pausable Simulator + */ +export class PausableSimulator extends PausableSimulatorBase { + constructor( + options: BaseSimulatorOptions< + PausablePrivateState, + ReturnType + > = {}, + ) { + super([], options); } /** @@ -84,42 +49,34 @@ export class PausableSimulator * @returns True if paused. */ public isPaused(): boolean { - return this.contract.impureCircuits.isPaused(this.circuitContext).result; + return this.circuits.impure.isPaused(); } /** * @description Makes a circuit only callable when the contract is paused. */ public assertPaused() { - this.circuitContext = this.contract.impureCircuits.assertPaused( - this.circuitContext, - ).context; + this.circuits.impure.assertPaused(); } /** * @description Makes a circuit only callable when the contract is not paused. */ public assertNotPaused() { - this.circuitContext = this.contract.impureCircuits.assertNotPaused( - this.circuitContext, - ).context; + this.circuits.impure.assertNotPaused(); } /** * @description Triggers a stopped state. */ public pause() { - this.circuitContext = this.contract.impureCircuits.pause( - this.circuitContext, - ).context; + this.circuits.impure.pause(); } /** * @description Lifts the pause on the contract. */ public unpause() { - this.circuitContext = this.contract.impureCircuits.unpause( - this.circuitContext, - ).context; + this.circuits.impure.unpause(); } } diff --git a/contracts/src/security/test/types/test.ts b/contracts/src/security/test/types/test.ts deleted file mode 100644 index 7a909543..00000000 --- a/contracts/src/security/test/types/test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { - CircuitContext, - ContractState, -} from '@midnight-ntwrk/compact-runtime'; - -/** - * Generic interface for mock contract implementations. - * @template P - The type of the contract's private state. - * @template L - The type of the contract's ledger (public state). - */ -export interface IContractSimulator { - /** The contract's deployed address. */ - readonly contractAddress: string; - - /** The current circuit context. */ - circuitContext: CircuitContext

; - - /** Retrieves the current ledger state. */ - getCurrentPublicState(): L; - - /** Retrieves the current private state. */ - getCurrentPrivateState(): P; - - /** Retrieves the current contract state. */ - getCurrentContractState(): ContractState; -} diff --git a/contracts/src/security/test/utils/address.ts b/contracts/src/security/test/utils/address.ts deleted file mode 100644 index ae55f943..00000000 --- a/contracts/src/security/test/utils/address.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { - convertFieldToBytes, - encodeCoinPublicKey, -} from '@midnight-ntwrk/compact-runtime'; -import { encodeContractAddress } from '@midnight-ntwrk/ledger'; -import type * as Compact from '../../../../artifacts/MockUtils/contract/index.cjs'; - -const PREFIX_ADDRESS = '0200'; - -/** - * @description Converts an ASCII string to its hexadecimal representation, - * left-padded with zeros to a specified length. Useful for generating - * fixed-size hex strings for encoding. - * @param str ASCII string to convert. - * @param len Total desired length of the resulting hex string. Defaults to 64. - * @returns Hexadecimal string representation of `str`, padded to `length` characters. - */ -export const toHexPadded = (str: string, len = 64) => - Buffer.from(str, 'ascii').toString('hex').padStart(len, '0'); - -/** - * @description Generates ZswapCoinPublicKey from `str` for testing purposes. - * @param str String to hexify and encode. - * @returns Encoded `ZswapCoinPublicKey`. - */ -export const encodeToPK = (str: string): Compact.ZswapCoinPublicKey => { - const toHex = Buffer.from(str, 'ascii').toString('hex'); - return { bytes: encodeCoinPublicKey(String(toHex).padStart(64, '0')) }; -}; - -/** - * @description Generates ContractAddress from `str` for testing purposes. - * Prepends 32-byte hex with PREFIX_ADDRESS before encoding. - * @param str String to hexify and encode. - * @returns Encoded `ZswapCoinPublicKey`. - */ -export const encodeToAddress = (str: string): Compact.ContractAddress => { - const toHex = Buffer.from(str, 'ascii').toString('hex'); - const fullAddress = PREFIX_ADDRESS + String(toHex).padStart(64, '0'); - return { bytes: encodeContractAddress(fullAddress) }; -}; - -/** - * @description Generates an Either object for ZswapCoinPublicKey for testing. - * For use when an Either argument is expected. - * @param str String to hexify and encode. - * @returns Defined Either object for ZswapCoinPublicKey. - */ -export const createEitherTestUser = (str: string) => { - return { - is_left: true, - left: encodeToPK(str), - right: encodeToAddress(''), - }; -}; - -/** - * @description Generates an Either object for ContractAddress for testing. - * For use when an Either argument is expected. - * @param str String to hexify and encode. - * @returns Defined Either object for ContractAddress. - */ -export const createEitherTestContractAddress = (str: string) => { - return { - is_left: false, - left: encodeToPK(''), - right: encodeToAddress(str), - }; -}; - -export const ZERO_KEY = { - is_left: true, - left: { bytes: convertFieldToBytes(32, 0n, '') }, - right: encodeToAddress(''), -}; - -export const ZERO_ADDRESS = { - is_left: false, - left: encodeToPK(''), - right: { bytes: convertFieldToBytes(32, 0n, '') }, -}; diff --git a/contracts/src/security/test/utils/test.ts b/contracts/src/security/test/utils/test.ts deleted file mode 100644 index 2fd5a504..00000000 --- a/contracts/src/security/test/utils/test.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { - type CircuitContext, - type CoinPublicKey, - type ContractAddress, - type ContractState, - emptyZswapLocalState, - QueryContext, -} from '@midnight-ntwrk/compact-runtime'; -import type { IContractSimulator } from '../types/test.js'; - -/** - * Constructs a `CircuitContext` from the given state and sender information. - * - * This is typically used at runtime to provide the necessary context - * for executing circuits, including contract state, private state, - * sender identity, and transaction data. - * - * @template P - The type of the contract's private state. - * @param privateState - The current private state of the contract. - * @param contractState - The full contract state, including public and private data. - * @param sender - The public key of the sender (used in the circuit). - * @param contractAddress - The address of the deployed contract. - * @returns A fully populated `CircuitContext` for circuit execution. - * @todo TODO: Move this utility to a generic package for broader reuse across contracts. - */ -export function useCircuitContext

( - privateState: P, - contractState: ContractState, - sender: CoinPublicKey, - contractAddress: ContractAddress, -): CircuitContext

{ - return { - originalState: contractState, - currentPrivateState: privateState, - transactionContext: new QueryContext(contractState.data, contractAddress), - currentZswapLocalState: emptyZswapLocalState(sender), - }; -} - -/** - * Prepares a new `CircuitContext` using the given sender and contract. - * - * Useful for mocking or updating the circuit context with a custom sender. - * - * @template P - The type of the contract's private state. - * @template L - The type of the contract's ledger (public state). - * @template C - The specific type of the contract implementing `MockContract`. - * @param contract - The contract instance implementing `MockContract`. - * @param sender - The public key to set as the sender in the new circuit context. - * @returns A new `CircuitContext` with the sender and updated context values. - * @todo TODO: Move this utility to a generic package for broader reuse across contracts. - */ -export function useCircuitContextSender< - P, - L, - C extends IContractSimulator, ->(contract: C, sender: CoinPublicKey): CircuitContext

{ - const currentPrivateState = contract.getCurrentPrivateState(); - const originalState = contract.getCurrentContractState(); - const contractAddress = contract.contractAddress; - - return { - originalState, - currentPrivateState, - transactionContext: new QueryContext(originalState.data, contractAddress), - currentZswapLocalState: emptyZswapLocalState(sender), - }; -} diff --git a/contracts/src/security/witnesses/InitializableWitnesses.ts b/contracts/src/security/witnesses/InitializableWitnesses.ts index 37d8f58c..9a7513c7 100644 --- a/contracts/src/security/witnesses/InitializableWitnesses.ts +++ b/contracts/src/security/witnesses/InitializableWitnesses.ts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Compact Contracts v0.0.1-alpha.1 (security/witnesses/InitializableWitnesses.ts) -// This is how we type an empty object. export type InitializablePrivateState = Record; -export const InitializableWitnesses = {}; +export const InitializablePrivateState: InitializablePrivateState = {}; +export const InitializableWitnesses = () => ({}); diff --git a/contracts/src/security/witnesses/PausableWitnesses.ts b/contracts/src/security/witnesses/PausableWitnesses.ts index dc36dfac..21895f5a 100644 --- a/contracts/src/security/witnesses/PausableWitnesses.ts +++ b/contracts/src/security/witnesses/PausableWitnesses.ts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Compact Contracts v0.0.1-alpha.1 (security/witnesses/PausableWitnesses.ts) -// This is how we type an empty object. export type PausablePrivateState = Record; -export const PausableWitnesses = {}; +export const PausablePrivateState: PausablePrivateState = {}; +export const PausableWitnesses = () => ({}); diff --git a/contracts/src/token/FungibleToken.compact b/contracts/src/token/FungibleToken.compact index 4623083a..8f604ef4 100644 --- a/contracts/src/token/FungibleToken.compact +++ b/contracts/src/token/FungibleToken.compact @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Compact Contracts v0.0.1-alpha.1 (token/FungibleToken.compact) -pragma language_version >= 0.18.0; +pragma language_version >= 0.21.0; /** * @module FungibleToken @@ -60,7 +60,8 @@ module FungibleToken { * @type {Map>} * @type {Map, Map, Uint<128>>>} _allowances */ - export ledger _allowances: Map, Map, Uint<128>>>; + export ledger _allowances: Map, + Map, Uint<128>>>; export ledger _totalSupply: Uint<128>; @@ -81,10 +82,10 @@ module FungibleToken { * @return {[]} - Empty tuple. */ export circuit initialize( - name_: Opaque<"string">, - symbol_: Opaque<"string">, - decimals_:Uint<8> - ): [] { + name_: Opaque<"string">, + symbol_: Opaque<"string">, + decimals_: Uint<8> + ): [] { Initializable_initialize(); _name = disclose(name_); _symbol = disclose(symbol_); @@ -198,7 +199,10 @@ module FungibleToken { * @param {Uint<128>} value - The amount to transfer. * @return {Boolean} - As per the IERC20 spec, this MUST return true. */ - export circuit transfer(to: Either, value: Uint<128>): Boolean { + export circuit transfer( + to: Either, + value: Uint<128> + ): Boolean { Initializable_assertInitialized(); assert(!Utils_isContractAddress(to), "FungibleToken: Unsafe Transfer"); return _unsafeTransfer(to, value); @@ -223,7 +227,10 @@ module FungibleToken { * @param {Uint<128>} value - The amount to transfer. * @return {Boolean} - As per the IERC20 spec, this MUST return true. */ - export circuit _unsafeTransfer(to: Either, value: Uint<128>): Boolean { + export circuit _unsafeTransfer( + to: Either, + value: Uint<128> + ): Boolean { Initializable_assertInitialized(); const owner = left(ownPublicKey()); _unsafeUncheckedTransfer(owner, to, value); @@ -247,9 +254,9 @@ module FungibleToken { * @return {Uint<128>} - The `spender`'s allowance over `owner`'s tokens. */ export circuit allowance( - owner: Either, - spender: Either - ): Uint<128> { + owner: Either, + spender: Either + ): Uint<128> { Initializable_assertInitialized(); if (!_allowances.member(disclose(owner)) || !_allowances.lookup(owner).member(disclose(spender))) { return 0; @@ -272,7 +279,9 @@ module FungibleToken { * @param {Uint<128>} value - The amount of tokens the `spender` may spend. * @return {Boolean} - Returns a boolean value indicating whether the operation succeeded. */ - export circuit approve(spender: Either, value: Uint<128>): Boolean { + export circuit approve(spender: Either, + value: Uint<128> + ): Boolean { Initializable_assertInitialized(); const owner = left(ownPublicKey()); @@ -281,7 +290,7 @@ module FungibleToken { } /** - * @description Moves `value` tokens from `from` to `to` using the allowance mechanism. + * @description Moves `value` tokens from `fromAddress` to `to` using the allowance mechanism. * `value` is the deducted from the caller's allowance. * * @circuitInfo k=11, rows=1821 @@ -293,25 +302,25 @@ module FungibleToken { * Requirements: * * - Contract is initialized. - * - `from` is not the zero address. - * - `from` must have a balance of at least `value`. + * - `fromAddress` is not the zero address. + * - `fromAddress` must have a balance of at least `value`. * - `to` is not the zero address. * - `to` is not a ContractAddress. - * - The caller has an allowance of `from`'s tokens of at least `value`. + * - The caller has an allowance of `fromAddress`'s tokens of at least `value`. * - * @param {Either} from - The current owner of the tokens for the transfer, either a user or a contract. + * @param {Either} fromAddress - The current owner of the tokens for the transfer, either a user or a contract. * @param {Either} to - The recipient of the transfer, either a user or a contract. * @param {Uint<128>} value - The amount to transfer. * @return {Boolean} - As per the IERC20 spec, this MUST return true. */ export circuit transferFrom( - from: Either, - to: Either, - value: Uint<128> - ): Boolean { + fromAddress: Either, + to: Either, + value: Uint<128> + ): Boolean { Initializable_assertInitialized(); assert(!Utils_isContractAddress(to), "FungibleToken: Unsafe Transfer"); - return _unsafeTransferFrom(from, to, value); + return _unsafeTransferFrom(fromAddress, to, value); } /** @@ -326,31 +335,31 @@ module FungibleToken { * Requirements: * * - Contract is initialized. - * - `from` is not the zero address. - * - `from` must have a balance of at least `value`. + * - `fromAddress` is not the zero address. + * - `fromAddress` must have a balance of at least `value`. * - `to` is not the zero address. - * - The caller has an allowance of `from`'s tokens of at least `value`. + * - The caller has an allowance of `fromAddress`'s tokens of at least `value`. * - * @param {Either} from - The current owner of the tokens for the transfer, either a user or a contract. + * @param {Either} fromAddress - The current owner of the tokens for the transfer, either a user or a contract. * @param {Either} to - The recipient of the transfer, either a user or a contract. * @param {Uint<128>} value - The amount to transfer. * @return {Boolean} - As per the IERC20 spec, this MUST return true. */ export circuit _unsafeTransferFrom( - from: Either, - to: Either, - value: Uint<128> - ): Boolean { + fromAddress: Either, + to: Either, + value: Uint<128> + ): Boolean { Initializable_assertInitialized(); const spender = left(ownPublicKey()); - _spendAllowance(from, spender, value); - _unsafeUncheckedTransfer(from, to, value); + _spendAllowance(fromAddress, spender, value); + _unsafeUncheckedTransfer(fromAddress, to, value); return true; } /** - * @description Moves a `value` amount of tokens from `from` to `to`. + * @description Moves a `value` amount of tokens from `fromAddress` to `to`. * This circuit is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * @@ -363,24 +372,24 @@ module FungibleToken { * Requirements: * * - Contract is initialized. - * - `from` is not be the zero address. - * - `from` must have at least a balance of `value`. + * - `fromAddress` is not be the zero address. + * - `fromAddress` must have at least a balance of `value`. * - `to` must not be the zero address. * - `to` must not be a ContractAddress. * - * @param {Either} from - The owner of the tokens to transfer. + * @param {Either} fromAddress - The owner of the tokens to transfer. * @param {Either} to - The receipient of the transferred tokens. * @param {Uint<128>} value - The amount of tokens to transfer. * @return {[]} - Empty tuple. */ export circuit _transfer( - from: Either, - to: Either, - value: Uint<128> - ): [] { + fromAddress: Either, + to: Either, + value: Uint<128> + ): [] { Initializable_assertInitialized(); assert(!Utils_isContractAddress(to), "FungibleToken: Unsafe Transfer"); - _unsafeUncheckedTransfer(from, to, value); + _unsafeUncheckedTransfer(fromAddress, to, value); } /** @@ -395,28 +404,28 @@ module FungibleToken { * Requirements: * * - Contract is initialized. - * - `from` is not the zero address. + * - `fromAddress` is not the zero address. * - `to` is not the zero address. * - * @param {Either} from - The owner of the tokens to transfer. + * @param {Either} fromAddress - The owner of the tokens to transfer. * @param {Either} to - The receipient of the transferred tokens. * @param {Uint<128>} value - The amount of tokens to transfer. * @return {[]} - Empty tuple. */ export circuit _unsafeUncheckedTransfer( - from: Either, - to: Either, - value: Uint<128> - ): [] { + fromAddress: Either, + to: Either, + value: Uint<128> + ): [] { Initializable_assertInitialized(); - assert(!Utils_isKeyOrAddressZero(from), "FungibleToken: invalid sender"); + assert(!Utils_isKeyOrAddressZero(fromAddress), "FungibleToken: invalid sender"); assert(!Utils_isKeyOrAddressZero(to), "FungibleToken: invalid receiver"); - _update(from, to, value); + _update(fromAddress, to, value); } /** - * @description Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from` + * @description Transfers a `value` amount of tokens from `fromAddress` to `to`, or alternatively mints (or burns) if `fromAddress` * (or `to`) is the zero address. * @dev Checks for a mint overflow in order to output a more readable error message. * @@ -426,27 +435,26 @@ module FungibleToken { * * - Contract is initialized. * - * @param {Either} from - The original owner of the tokens moved (which is 0 if tokens are minted). + * @param {Either} fromAddress - The original owner of the tokens moved (which is 0 if tokens are minted). * @param {Either} to - The recipient of the tokens moved (which is 0 if tokens are burned). - * @param {Uint<128>} value - The amount of tokens moved from `from` to `to`. + * @param {Uint<128>} value - The amount of tokens moved from `fromAddress` to `to`. * @return {[]} - Empty tuple. */ - circuit _update( - from: Either, - to: Either, - value: Uint<128> - ): [] { + circuit _update(fromAddress: Either, + to: Either, + value: Uint<128> + ): [] { Initializable_assertInitialized(); - if (Utils_isKeyOrAddressZero(disclose(from))) { + if (Utils_isKeyOrAddressZero(disclose(fromAddress))) { // Mint const MAX_UINT128 = 340282366920938463463374607431768211455; assert(MAX_UINT128 - _totalSupply >= value, "FungibleToken: arithmetic overflow"); _totalSupply = disclose(_totalSupply + value as Uint<128>); } else { - const fromBal = balanceOf(from); + const fromBal = balanceOf(fromAddress); assert(fromBal >= value, "FungibleToken: insufficient balance"); - _balances.insert(disclose(from), disclose(fromBal - value as Uint<128>)); + _balances.insert(disclose(fromAddress), disclose(fromBal - value as Uint<128>)); } if (Utils_isKeyOrAddressZero(disclose(to))) { @@ -478,10 +486,7 @@ module FungibleToken { * @param {Uint<128>} value - The amount of tokens minted. * @return {[]} - Empty tuple. */ - export circuit _mint( - account: Either, - value: Uint<128> - ): [] { + export circuit _mint(account: Either, value: Uint<128>): [] { Initializable_assertInitialized(); assert(!Utils_isContractAddress(account), "FungibleToken: Unsafe Transfer"); _unsafeMint(account, value); @@ -506,12 +511,12 @@ module FungibleToken { * @return {[]} - Empty tuple. */ export circuit _unsafeMint( - account: Either, - value: Uint<128> - ): [] { + account: Either, + value: Uint<128> + ): [] { Initializable_assertInitialized(); assert(!Utils_isKeyOrAddressZero(account), "FungibleToken: invalid receiver"); - _update(burnAddress(), account, value); + _update(shieldedBurnAddress(), account, value); } /** @@ -530,13 +535,10 @@ module FungibleToken { * @param {Uint<128>} value - The amount of tokens to burn. * @return {[]} - Empty tuple. */ - export circuit _burn( - account: Either, - value: Uint<128> - ): [] { + export circuit _burn(account: Either, value: Uint<128>): [] { Initializable_assertInitialized(); assert(!Utils_isKeyOrAddressZero(account), "FungibleToken: invalid sender"); - _update(account, burnAddress(), value); + _update(account, shieldedBurnAddress(), value); } /** @@ -559,16 +561,19 @@ module FungibleToken { * @return {[]} - Empty tuple. */ export circuit _approve( - owner: Either, - spender: Either, - value: Uint<128> - ): [] { + owner: Either, + spender: Either, + value: Uint<128> + ): [] { Initializable_assertInitialized(); assert(!Utils_isKeyOrAddressZero(owner), "FungibleToken: invalid owner"); assert(!Utils_isKeyOrAddressZero(spender), "FungibleToken: invalid spender"); if (!_allowances.member(disclose(owner))) { // If owner doesn't exist, create and insert a new sub-map directly - _allowances.insert(disclose(owner), default, Uint<128>>>); + _allowances.insert( + disclose(owner), + default, Uint<128>>> + ); } _allowances.lookup(owner).insert(disclose(spender), disclose(value)); } @@ -590,12 +595,15 @@ module FungibleToken { * @return {[]} - Empty tuple. */ export circuit _spendAllowance( - owner: Either, - spender: Either, - value: Uint<128> - ): [] { + owner: Either, + spender: Either, + value: Uint<128> + ): [] { Initializable_assertInitialized(); - assert((_allowances.member(disclose(owner)) && _allowances.lookup(owner).member(disclose(spender))), "FungibleToken: insufficient allowance"); + assert((_allowances.member(disclose(owner)) && + _allowances.lookup(owner).member(disclose(spender))), + "FungibleToken: insufficient allowance" + ); const currentAllowance = _allowances.lookup(owner).lookup(disclose(spender)); const MAX_UINT128 = 340282366920938463463374607431768211455; diff --git a/contracts/src/token/MultiToken.compact b/contracts/src/token/MultiToken.compact index b219059e..649b8076 100644 --- a/contracts/src/token/MultiToken.compact +++ b/contracts/src/token/MultiToken.compact @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Compact Contracts v0.0.1-alpha.1 (token/MultiToken.compact) -pragma language_version >= 0.18.0; +pragma language_version >= 0.21.0; /** * @module MultiToken @@ -21,7 +21,7 @@ pragma language_version >= 0.18.0; * * 1. Batch mint, burn, transfer - Without support for dynamic arrays, * batching transfers is difficult to do without a hacky solution. - * For instance, we could change the `to` and `from` parameters to be + * For instance, we could change the `to` and `fromAddress` parameters to be * vectors. This would change the signature and would be both difficult * to use and easy to misuse. * @@ -76,7 +76,8 @@ module MultiToken { * @type {Map>} * @type {Map, Map, Uint<128>>>} _balances */ - export ledger _balances: Map, Map, Uint<128>>>; + export ledger _balances: Map, + Map, Uint<128>>>; /** * @description Mapping from account to operator approvals. @@ -86,7 +87,8 @@ module MultiToken { * @type {Map>} * @type {Map, Map, Boolean>>} */ - export ledger _operatorApprovals: Map, Map, Boolean>>; + export ledger _operatorApprovals: Map, + Map, Boolean>>; /** * @description Base URI for computing token URIs. @@ -147,7 +149,10 @@ module MultiToken { * @param {Uint<128>} id - The token identifier to query. * return {Uint<128>} - The quantity of `id` tokens that `account` owns. */ - export circuit balanceOf(account: Either, id: Uint<128>): Uint<128> { + export circuit balanceOf( + account: Either, + id: Uint<128> + ): Uint<128> { Initializable_assertInitialized(); if (!_balances.member(disclose(id)) || !_balances.lookup(id).member(disclose(account))) { @@ -172,7 +177,10 @@ module MultiToken { * caller's assets. * @return {[]} - Empty tuple. */ - export circuit setApprovalForAll(operator: Either, approved: Boolean): [] { + export circuit setApprovalForAll( + operator: Either, + approved: Boolean + ): [] { Initializable_assertInitialized(); // TODO: Contract-to-contract calls not yet supported. @@ -194,12 +202,13 @@ module MultiToken { * @return {Boolean} - Whether or not `operator` has permission to handle `account`'s assets. */ export circuit isApprovedForAll( - account: Either, - operator: Either - ): Boolean { + account: Either, + operator: Either + ): Boolean { Initializable_assertInitialized(); - if (!_operatorApprovals.member(disclose(account)) || !_operatorApprovals.lookup(account).member(disclose(operator))) { + if (!_operatorApprovals.member(disclose(account)) || + !_operatorApprovals.lookup(account).member(disclose(operator))) { return false; } @@ -207,8 +216,8 @@ module MultiToken { } /** - * @description Transfers ownership of `value` amount of `id` tokens from `from` to `to`. - * The caller must be `from` or approved to transfer on their behalf. + * @description Transfers ownership of `value` amount of `id` tokens from `fromAddress` to `to`. + * The caller must be `fromAddress` or approved to transfer on their behalf. * * @circuitInfo k=11, rows=1882 * @@ -224,28 +233,28 @@ module MultiToken { * - Contract is initialized. * - `to` is not a ContractAddress. * - `to` is not the zero address. - * - `from` is not the zero address. - * - Caller must be `from` or approved via `setApprovalForAll`. - * - `from` must have an `id` balance of at least `value`. + * - `fromAddress` is not the zero address. + * - Caller must be `fromAddress` or approved via `setApprovalForAll`. + * - `fromAddress` must have an `id` balance of at least `value`. * - * @param {Either} from - The owner from which the transfer originates. + * @param {Either} fromAddress - The owner from which the transfer originates. * @param {Either} to - The recipient of the transferred assets. * @param {Uint<128>} id - The unique identifier of the asset type. * @param {Uint<128>} value - The quantity of `id` tokens to transfer. * @return {[]} - Empty tuple. */ export circuit transferFrom( - from: Either, - to: Either, - id: Uint<128>, - value: Uint<128> - ): [] { + fromAddress: Either, + to: Either, + id: Uint<128>, + value: Uint<128> + ): [] { assert(!Utils_isContractAddress(to), "MultiToken: unsafe transfer"); - _unsafeTransferFrom(from, to, id, value); + _unsafeTransferFrom(fromAddress, to, id, value); } /** - * @description Transfers ownership of `value` amount of `id` tokens from `from` to `to`. + * @description Transfers ownership of `value` amount of `id` tokens from `fromAddress` to `to`. * Does not impose restrictions on the caller, making it suitable for composition * in higher-level contract logic. * @@ -260,62 +269,64 @@ module MultiToken { * - Contract is initialized. * - `to` is not a ContractAddress. * - `to` is not the zero address. - * - `from` is not the zero address. - * - `from` must have an `id` balance of at least `value`. + * - `fromAddress` is not the zero address. + * - `fromAddress` must have an `id` balance of at least `value`. * - * @param {Either} from - The owner from which the transfer originates. + * @param {Either} fromAddress - The owner from which the transfer originates. * @param {Either} to - The recipient of the transferred assets. * @param {Uint<128>} id - The unique identifier of the asset type. * @param {Uint<128>} value - The quantity of `id` tokens to transfer. * @return {[]} - Empty tuple. */ export circuit _transfer( - from: Either, - to: Either, - id: Uint<128>, - value: Uint<128> - ): [] { + fromAddress: Either, + to: Either, + id: Uint<128>, + value: Uint<128> + ): [] { assert(!Utils_isContractAddress(to), "MultiToken: unsafe transfer"); - _unsafeTransfer(from, to, id, value); + _unsafeTransfer(fromAddress, to, id, value); } /** - * @description Transfers a value amount of tokens of type id from from to to. - * This circuit will mint (or burn) if `from` (or `to`) is the zero address. + * @description Transfers a value amount of tokens of type id from fromAddress to to. + * This circuit will mint (or burn) if `fromAddress` (or `to`) is the zero address. * * @circuitInfo k=11, rows=1482 * * Requirements: * * - Contract is initialized. - * - If `from` is not zero, the balance of `id` of `from` must be >= `value`. + * - If `fromAddress` is not zero, the balance of `id` of `fromAddress` must be >= `value`. * - * @param {Either} from - The origin of the transfer. + * @param {Either} fromAddress - The origin of the transfer. * @param {Either} to - The destination of the transfer. * @param {Uint<128>} id - The unique identifier of the asset type. * @param {Uint<128>} value - The quantity of `id` tokens to transfer. * @return {[]} - Empty tuple. */ - circuit _update( - from: Either, - to: Either, - id: Uint<128>, - value: Uint<128> - ): [] { + circuit _update(fromAddress: Either, + to: Either, + id: Uint<128>, + value: Uint<128> + ): [] { Initializable_assertInitialized(); - if (!Utils_isKeyOrAddressZero(disclose(from))) { - const fromBalance = balanceOf(from, id); + if (!Utils_isKeyOrAddressZero(disclose(fromAddress))) { + const fromBalance = balanceOf(fromAddress, id); assert(fromBalance >= value, "MultiToken: insufficient balance"); // overflow not possible const newBalance = fromBalance - value; - _balances.lookup(id).insert(disclose(from), disclose(newBalance)); + _balances.lookup(id).insert(disclose(fromAddress), disclose(newBalance)); } if (!Utils_isKeyOrAddressZero(disclose(to))) { // id not initialized if (!_balances.member(disclose(id))) { - _balances.insert(disclose(id), default, Uint<128>>>); + _balances.insert( + disclose(id), + default, Uint<128>>> + ); _balances.lookup(id).insert(disclose(to), disclose(value as Uint<128>)); } else { const toBalance = balanceOf(to, id), MAX_UINT128 = 340282366920938463463374607431768211455; @@ -327,7 +338,7 @@ module MultiToken { /** * @description Unsafe variant of `transferFrom` which allows transfers to contract addresses. - * The caller must be `from` or approved to transfer on their behalf. + * The caller must be `fromAddress` or approved to transfer on their behalf. * * @circuitInfo k=11, rows=1881 * @@ -339,32 +350,32 @@ module MultiToken { * * - Contract is initialized. * - `to` is not the zero address. - * - `from` is not the zero address. - * - Caller must be `from` or approved via `setApprovalForAll`. - * - `from` must have an `id` balance of at least `value`. + * - `fromAddress` is not the zero address. + * - Caller must be `fromAddress` or approved via `setApprovalForAll`. + * - `fromAddress` must have an `id` balance of at least `value`. * - * @param {Either} from - The owner from which the transfer originates. + * @param {Either} fromAddress - The owner from which the transfer originates. * @param {Either} to - The recipient of the transferred assets. * @param {Uint<128>} id - The unique identifier of the asset type. * @param {Uint<128>} value - The quantity of `id` tokens to transfer. * @return {[]} - Empty tuple. */ export circuit _unsafeTransferFrom( - from: Either, - to: Either, - id: Uint<128>, - value: Uint<128> - ): [] { + fromAddress: Either, + to: Either, + id: Uint<128>, + value: Uint<128> + ): [] { Initializable_assertInitialized(); // TODO: Contract-to-contract calls not yet supported. // Once available, handle ContractAddress recipients here. const caller = left(ownPublicKey()); - if (disclose(from) != caller) { - assert(isApprovedForAll(from, caller), "MultiToken: unauthorized operator"); + if (disclose(fromAddress) != caller) { + assert(isApprovedForAll(fromAddress, caller), "MultiToken: unauthorized operator"); } - _unsafeTransfer(from, to, id, value); + _unsafeTransfer(fromAddress, to, id, value); } /** @@ -381,27 +392,27 @@ module MultiToken { * Requirements: * * - Contract is initialized. - * - `from` is not the zero address. + * - `fromAddress` is not the zero address. * - `to` is not the zero address. - * - `from` must have an `id` balance of at least `value`. + * - `fromAddress` must have an `id` balance of at least `value`. * - * @param {Either} from - The owner from which the transfer originates. + * @param {Either} fromAddress - The owner from which the transfer originates. * @param {Either} to - The recipient of the transferred assets. * @param {Uint<128>} id - The unique identifier of the asset type. * @param {Uint<128>} value - The quantity of `id` tokens to transfer. * @return {[]} - Empty tuple. */ export circuit _unsafeTransfer( - from: Either, - to: Either, - id: Uint<128>, - value: Uint<128> - ): [] { + fromAddress: Either, + to: Either, + id: Uint<128>, + value: Uint<128> + ): [] { Initializable_assertInitialized(); - assert(!Utils_isKeyOrAddressZero(from), "MultiToken: invalid sender"); + assert(!Utils_isKeyOrAddressZero(fromAddress), "MultiToken: invalid sender"); assert(!Utils_isKeyOrAddressZero(to), "MultiToken: invalid receiver"); - _update(from, to, id, value); + _update(fromAddress, to, id, value); } /** @@ -453,7 +464,10 @@ module MultiToken { * @param {Uint<128>} value - The quantity of `id` tokens that are minted to `to`. * @return {[]} - Empty tuple. */ - export circuit _mint(to: Either, id: Uint<128>, value: Uint<128>): [] { + export circuit _mint(to: Either, + id: Uint<128>, + value: Uint<128> + ): [] { assert(!Utils_isContractAddress(to), "MultiToken: unsafe transfer"); _unsafeMint(to, id, value); } @@ -477,34 +491,41 @@ module MultiToken { * @param {Uint<128>} value - The quantity of `id` tokens that are minted to `to`. * @return {[]} - Empty tuple. */ - export circuit _unsafeMint(to: Either, id: Uint<128>, value: Uint<128>): [] { + export circuit _unsafeMint( + to: Either, + id: Uint<128>, + value: Uint<128> + ): [] { Initializable_assertInitialized(); assert(!Utils_isKeyOrAddressZero(to), "MultiToken: invalid receiver"); - _update(burnAddress(), to, id, value); + _update(shieldedBurnAddress(), to, id, value); } /** - * @description Destroys a `value` amount of tokens of type `token_id` from `from`. + * @description Destroys a `value` amount of tokens of type `token_id` from `fromAddress`. * * @circuitInfo k=10, rows=688 * * Requirements: * * - Contract is initialized. - * - `from` is not the zero address. - * - `from` must have an `id` balance of at least `value`. + * - `fromAddress` is not the zero address. + * - `fromAddress` must have an `id` balance of at least `value`. * - * @param {Either} from - The owner whose tokens will be destroyed. + * @param {Either} fromAddress - The owner whose tokens will be destroyed. * @param {Uint<128>} id - The unique identifier of the token type. - * @param {Uint<128>} value - The quantity of `id` tokens that will be destroyed from `from`. + * @param {Uint<128>} value - The quantity of `id` tokens that will be destroyed from `fromAddress`. * @return {[]} - Empty tuple. */ - export circuit _burn(from: Either, id: Uint<128>, value: Uint<128>): [] { + export circuit _burn(fromAddress: Either, + id: Uint<128>, + value: Uint<128> + ): [] { Initializable_assertInitialized(); - assert(!Utils_isKeyOrAddressZero(from), "MultiToken: invalid sender"); - _update(from, burnAddress(), id, value); + assert(!Utils_isKeyOrAddressZero(fromAddress), "MultiToken: invalid sender"); + _update(fromAddress, shieldedBurnAddress(), id, value); } /** @@ -528,15 +549,18 @@ module MultiToken { * @return {[]} - Empty tuple. */ export circuit _setApprovalForAll( - owner: Either, - operator: Either, - approved: Boolean - ): [] { + owner: Either, + operator: Either, + approved: Boolean + ): [] { Initializable_assertInitialized(); assert(!Utils_isKeyOrAddressZero(operator), "MultiToken: invalid operator"); if (!_operatorApprovals.member(disclose(owner))) { - _operatorApprovals.insert(disclose(owner), default, Boolean>>); + _operatorApprovals.insert( + disclose(owner), + default, Boolean>> + ); } _operatorApprovals.lookup(owner).insert(disclose(operator), disclose(approved)); diff --git a/contracts/src/token/NonFungibleToken.compact b/contracts/src/token/NonFungibleToken.compact index 8cfb153a..13fa4f97 100644 --- a/contracts/src/token/NonFungibleToken.compact +++ b/contracts/src/token/NonFungibleToken.compact @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Compact Contracts v0.0.1-alpha.1 (token/NonFungibleToken.compact) -pragma language_version >= 0.18.0; +pragma language_version >= 0.21.0; /** * @module NonFungibleToken @@ -83,7 +83,8 @@ module NonFungibleToken { * @type {Map>} * @type {Map, Map, Boolean>>} _operatorApprovals */ - export ledger _operatorApprovals: Map, Map, Boolean>>; + export ledger _operatorApprovals: Map, + Map, Boolean>>; /** * @description Mapping from token IDs to their metadata URIs. @@ -258,17 +259,10 @@ module NonFungibleToken { * @param {Uint<128>} tokenId - The token `to` may be permitted to transfer * @return {[]} - Empty tuple. */ - export circuit approve( - to: Either, - tokenId: Uint<128> - ): [] { + export circuit approve(to: Either, tokenId: Uint<128>): [] { Initializable_assertInitialized(); - const auth = left(ownPublicKey()); - _approve( - to, - tokenId, - auth - ); + const auth = left(ownPublicKey()); + _approve(to, tokenId, auth); } /** @@ -307,16 +301,12 @@ module NonFungibleToken { * @return {[]} - Empty tuple. */ export circuit setApprovalForAll( - operator: Either, - approved: Boolean - ): [] { + operator: Either, + approved: Boolean + ): [] { Initializable_assertInitialized(); - const owner = left(ownPublicKey()); - _setApprovalForAll( - owner, - operator, - approved - ); + const owner = left(ownPublicKey()); + _setApprovalForAll(owner, operator, approved); } /** @@ -333,11 +323,12 @@ module NonFungibleToken { * @return {Boolean} - A boolean determining if `operator` is allowed to manage all of the tokens of `owner` */ export circuit isApprovedForAll( - owner: Either, - operator: Either - ): Boolean { + owner: Either, + operator: Either + ): Boolean { Initializable_assertInitialized(); - if (_operatorApprovals.member(disclose(owner)) && _operatorApprovals.lookup(owner).member(disclose(operator))) { + if (_operatorApprovals.member(disclose(owner)) && + _operatorApprovals.lookup(owner).member(disclose(operator))) { return _operatorApprovals.lookup(owner).lookup(disclose(operator)); } else { return false; @@ -345,7 +336,7 @@ module NonFungibleToken { } /** - * @description Transfers `tokenId` token from `from` to `to`. + * @description Transfers `tokenId` token from `fromAddress` to `to`. * * @notice Transfers to contract addresses are currently disallowed until contract-to-contract interactions * are supported in Compact. This restriction prevents assets from being inadvertently locked in contracts that cannot @@ -356,30 +347,30 @@ module NonFungibleToken { * Requirements: * * - The contract is initialized. - * - `from` is not the zero address. + * - `fromAddress` is not the zero address. * - `to` is not the zero address. * - `to` is not a ContractAddress. - * - `tokenId` token must be owned by `from`. - * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - `tokenId` token must be owned by `fromAddress`. + * - If the caller is not `fromAddress`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - * @param {Either} from - The source account from which the token is being transfered + * @param {Either} fromAddress - The source account from which the token is being transfered * @param {Either} to - The target account to transfer token to * @param {Uint<128>} tokenId - The token being transfered * @return {[]} - Empty tuple. */ export circuit transferFrom( - from: Either, - to: Either, - tokenId: Uint<128> - ): [] { + fromAddress: Either, + to: Either, + tokenId: Uint<128> + ): [] { Initializable_assertInitialized(); assert(!Utils_isContractAddress(to), "NonFungibleToken: Unsafe Transfer"); - _unsafeTransferFrom(from, to, tokenId); + _unsafeTransferFrom(fromAddress, to, tokenId); } /** - * @description Transfers `tokenId` token from `from` to `to`. It does NOT check if the recipient is a ContractAddress. + * @description Transfers `tokenId` token from `fromAddress` to `to`. It does NOT check if the recipient is a ContractAddress. * * WARNING: Transfers to contract addresses are considered unsafe because contract-to-contract calls * are not currently supported. Tokens sent to a contract address may become irretrievable. @@ -390,32 +381,28 @@ module NonFungibleToken { * Requirements: * * - The contract is initialized. - * - `from` is not the zero address. + * - `fromAddress` is not the zero address. * - `to` is not the zero address. - * - `tokenId` token must be owned by `from`. - * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - `tokenId` token must be owned by `fromAddress`. + * - If the caller is not `fromAddress`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - * @param {Either} from - The source account from which the token is being transfered + * @param {Either} fromAddress - The source account from which the token is being transfered * @param {Either} to - The target account to transfer token to * @param {Uint<128>} tokenId - The token being transfered * @return {[]} - Empty tuple. */ export circuit _unsafeTransferFrom( - from: Either, - to: Either, - tokenId: Uint<128> - ): [] { + fromAddress: Either, + to: Either, + tokenId: Uint<128> + ): [] { Initializable_assertInitialized(); assert(!Utils_isKeyOrAddressZero(to), "NonFungibleToken: Invalid Receiver"); // Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists - // (from != 0). Therefore, it is not needed to verify that the return value is not 0 here. - const auth = left(ownPublicKey()); - const previousOwner = _update( - to, - tokenId, - auth - ); - assert(previousOwner == from, "NonFungibleToken: Incorrect Owner"); + // (fromAddress != 0). Therefore, it is not needed to verify that the return value is not 0 here. + const auth = left(ownPublicKey()); + const previousOwner = _update(to, tokenId, auth); + assert(previousOwner == fromAddress, "NonFungibleToken: Incorrect Owner"); } /** @@ -433,7 +420,7 @@ module NonFungibleToken { export circuit _ownerOf(tokenId: Uint<128>): Either { Initializable_assertInitialized(); if (!_owners.member(disclose(tokenId))) { - return burnAddress(); + return shieldedBurnAddress(); } return _owners.lookup(disclose(tokenId)); @@ -454,7 +441,7 @@ module NonFungibleToken { export circuit _getApproved(tokenId: Uint<128>): Either { Initializable_assertInitialized(); if (!_tokenApprovals.member(disclose(tokenId))) { - return burnAddress(); + return shieldedBurnAddress(); } return _tokenApprovals.lookup(disclose(tokenId)); } @@ -478,15 +465,15 @@ module NonFungibleToken { * @return {Boolean} - A boolean determining if `spender` may manage `tokenId` */ export circuit _isAuthorized( - owner: Either, - spender: Either, - tokenId: Uint<128> - ): Boolean { + owner: Either, + spender: Either, + tokenId: Uint<128> + ): Boolean { Initializable_assertInitialized(); - return ( - !Utils_isKeyOrAddressZero(disclose(spender)) && - (disclose(owner) == disclose(spender) || isApprovedForAll(owner, spender) || _getApproved(tokenId) == disclose(spender)) - ); + return (!Utils_isKeyOrAddressZero(disclose(spender)) && + (disclose(owner) == disclose(spender) || + isApprovedForAll(owner, spender) || + _getApproved(tokenId) == disclose(spender))); } /** @@ -508,10 +495,10 @@ module NonFungibleToken { * @return {[]} - Empty tuple. */ export circuit _checkAuthorized( - owner: Either, - spender: Either, - tokenId: Uint<128> - ): [] { + owner: Either, + spender: Either, + tokenId: Uint<128> + ): [] { Initializable_assertInitialized(); if (!_isAuthorized(owner, spender, tokenId)) { assert(!Utils_isKeyOrAddressZero(owner), "NonFungibleToken: Nonexistent Token"); @@ -536,25 +523,24 @@ module NonFungibleToken { * @param {Either} auth - An account authorized to transfer the token * @return {Either} - Owner of the token before it was transfered */ - circuit _update( - to: Either, - tokenId: Uint<128>, - auth: Either - ): Either { + circuit _update(to: Either, + tokenId: Uint<128>, + auth: Either + ): Either { Initializable_assertInitialized(); - const from = _ownerOf(tokenId); + const fromAddress = _ownerOf(tokenId); // Perform (optional) operator check if (!Utils_isKeyOrAddressZero(disclose(auth))) { - _checkAuthorized(from, auth, tokenId); + _checkAuthorized(fromAddress, auth, tokenId); } // Execute the update - if (!Utils_isKeyOrAddressZero(disclose(from))) { + if (!Utils_isKeyOrAddressZero(disclose(fromAddress))) { // Clear approval. No need to re-authorize - _approve(burnAddress(), tokenId, burnAddress()); - const newBalance = _balances.lookup(disclose(from)) - 1 as Uint<128>; - _balances.insert(disclose(from), disclose(newBalance)); + _approve(shieldedBurnAddress(), tokenId, shieldedBurnAddress()); + const newBalance = _balances.lookup(disclose(fromAddress)) - 1 as Uint<128>; + _balances.insert(disclose(fromAddress), disclose(newBalance)); } if (!Utils_isKeyOrAddressZero(disclose(to))) { @@ -567,7 +553,7 @@ module NonFungibleToken { _owners.insert(disclose(tokenId), disclose(to)); - return from; + return fromAddress; } /** @@ -586,10 +572,7 @@ module NonFungibleToken { * @param {Uint<128>} tokenId - The token to transfer * @return {[]} - Empty tuple. */ - export circuit _mint( - to: Either, - tokenId: Uint<128> - ): [] { + export circuit _mint(to: Either, tokenId: Uint<128>): [] { Initializable_assertInitialized(); assert(!Utils_isContractAddress(to), "NonFungibleToken: Unsafe Transfer"); @@ -616,13 +599,13 @@ module NonFungibleToken { * @return {[]} - Empty tuple. */ export circuit _unsafeMint( - to: Either, - tokenId: Uint<128> - ): [] { + to: Either, + tokenId: Uint<128> + ): [] { Initializable_assertInitialized(); assert(!Utils_isKeyOrAddressZero(to), "NonFungibleToken: Invalid Receiver"); - const previousOwner = _update(to, tokenId, burnAddress()); + const previousOwner = _update(to, tokenId, shieldedBurnAddress()); assert(Utils_isKeyOrAddressZero(previousOwner), "NonFungibleToken: Invalid Sender"); } @@ -644,12 +627,12 @@ module NonFungibleToken { */ export circuit _burn(tokenId: Uint<128>): [] { Initializable_assertInitialized(); - const previousOwner = _update(burnAddress(), tokenId, burnAddress()); + const previousOwner = _update(shieldedBurnAddress(), tokenId, shieldedBurnAddress()); assert(!Utils_isKeyOrAddressZero(previousOwner), "NonFungibleToken: Invalid Sender"); } /** - * @description Transfers `tokenId` from `from` to `to`. + * @description Transfers `tokenId` from `fromAddress` to `to`. * As opposed to {transferFrom}, this imposes no restrictions on ownPublicKey(). * * @notice Transfers to contract addresses are currently disallowed until contract-to-contract @@ -663,26 +646,26 @@ module NonFungibleToken { * - The contract is initialized. * - `to` is not the zero address. * - `to` is not a ContractAddress. - * - `tokenId` token must be owned by `from`. + * - `tokenId` token must be owned by `fromAddress`. * - * @param {Either} from - The source account of the token transfer + * @param {Either} fromAddress - The source account of the token transfer * @param {Either} to - The target account of the token transfer * @param {Uint<128>} tokenId - The token to transfer * @return {[]} - Empty tuple. */ export circuit _transfer( - from: Either, - to: Either, - tokenId: Uint<128> - ): [] { + fromAddress: Either, + to: Either, + tokenId: Uint<128> + ): [] { Initializable_assertInitialized(); assert(!Utils_isContractAddress(to), "NonFungibleToken: Unsafe Transfer"); - _unsafeTransfer(from, to, tokenId); + _unsafeTransfer(fromAddress, to, tokenId); } /** - * @description Transfers `tokenId` from `from` to `to`. + * @description Transfers `tokenId` from `fromAddress` to `to`. * As opposed to {_unsafeTransferFrom}, this imposes no restrictions on ownPublicKey(). * It does NOT check if the recipient is a ContractAddress. * @@ -692,29 +675,29 @@ module NonFungibleToken { * * - The contract is initialized. * - `to` is not the zero address. - * - `tokenId` token must be owned by `from`. + * - `tokenId` token must be owned by `fromAddress`. * * WARNING: Transfers to contract addresses are considered unsafe because contract-to-contract * calls are not currently supported. Tokens sent to a contract address may become irretrievable. * Once contract-to-contract calls are supported, this circuit may be deprecated. * - * @param {Either} from - The source account of the token transfer + * @param {Either} fromAddress - The source account of the token transfer * @param {Either} to - The target account of the token transfer * @param {Uint<128>} tokenId - The token to transfer * @return {[]} - Empty tuple. */ export circuit _unsafeTransfer( - from: Either, - to: Either, - tokenId: Uint<128> - ): [] { + fromAddress: Either, + to: Either, + tokenId: Uint<128> + ): [] { Initializable_assertInitialized(); assert(!Utils_isKeyOrAddressZero(to), "NonFungibleToken: Invalid Receiver"); - const previousOwner = _update(to, tokenId, burnAddress()); + const previousOwner = _update(to, tokenId, shieldedBurnAddress()); assert(!Utils_isKeyOrAddressZero(previousOwner), "NonFungibleToken: Nonexistent Token"); - assert(previousOwner == from, "NonFungibleToken: Incorrect Owner"); + assert(previousOwner == fromAddress, "NonFungibleToken: Incorrect Owner"); } /** @@ -734,16 +717,18 @@ module NonFungibleToken { * @return {[]} - Empty tuple. */ export circuit _approve( - to: Either, - tokenId: Uint<128>, - auth: Either - ): [] { + to: Either, + tokenId: Uint<128>, + auth: Either + ): [] { Initializable_assertInitialized(); if (!Utils_isKeyOrAddressZero(disclose(auth))) { const owner = _requireOwned(tokenId); // We do not use _isAuthorized because single-token approvals should not be able to call approve - assert((owner == disclose(auth) || isApprovedForAll(owner, auth)), "NonFungibleToken: Invalid Approver"); + assert((owner == disclose(auth) || isApprovedForAll(owner, auth)), + "NonFungibleToken: Invalid Approver" + ); } _tokenApprovals.insert(disclose(tokenId), disclose(to)); @@ -765,10 +750,10 @@ module NonFungibleToken { * @return {[]} - Empty tuple. */ export circuit _setApprovalForAll( - owner: Either, - operator: Either, - approved: Boolean - ): [] { + owner: Either, + operator: Either, + approved: Boolean + ): [] { Initializable_assertInitialized(); assert(!Utils_isKeyOrAddressZero(operator), "NonFungibleToken: Invalid Operator"); @@ -776,7 +761,7 @@ module NonFungibleToken { _operatorApprovals.insert( disclose(owner), default, Boolean>> - ); + ); } _operatorApprovals.lookup(owner).insert(disclose(operator), disclose(approved)); diff --git a/contracts/src/token/test/FungibleToken.test.ts b/contracts/src/token/test/FungibleToken.test.ts index ed0c4142..8a2cdc1a 100644 --- a/contracts/src/token/test/FungibleToken.test.ts +++ b/contracts/src/token/test/FungibleToken.test.ts @@ -1,7 +1,6 @@ -import type { CoinPublicKey } from '@midnight-ntwrk/compact-runtime'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; +import * as utils from '#test-utils/address.js'; import { FungibleTokenSimulator } from './simulators/FungibleTokenSimulator.js'; -import * as utils from './utils/address.js'; // Metadata const EMPTY_STRING = ''; @@ -16,17 +15,15 @@ const BAD_INIT = false; const AMOUNT: bigint = BigInt(250); const MAX_UINT128 = BigInt(2 ** 128) - BigInt(1); -// Callers -const OWNER = utils.toHexPadded('OWNER'); -const SPENDER = utils.toHexPadded('SPENDER'); -const UNAUTHORIZED = utils.toHexPadded('UNAUTHORIZED'); -const ZERO = utils.toHexPadded(''); - -// Encoded PK/Addresses -const Z_OWNER = utils.createEitherTestUser('OWNER'); -const Z_RECIPIENT = utils.createEitherTestUser('RECIPIENT'); -const Z_SPENDER = utils.createEitherTestUser('SPENDER'); -const Z_OTHER = utils.createEitherTestUser('OTHER'); +// PKs +const [OWNER, Z_OWNER] = utils.generateEitherPubKeyPair('OWNER'); +const [SPENDER, Z_SPENDER] = utils.generateEitherPubKeyPair('SPENDER'); +const [UNAUTHORIZED] = utils.generateEitherPubKeyPair('UNAUTHORIZED'); +const [ZERO] = utils.generateEitherPubKeyPair(''); +const [, Z_RECIPIENT] = utils.generateEitherPubKeyPair('RECIPIENT'); +const [, Z_OTHER] = utils.generateEitherPubKeyPair('OTHER'); + +// Encoded contract addresses const Z_OWNER_CONTRACT = utils.createEitherTestContractAddress('OWNER_CONTRACT'); const Z_RECIPIENT_CONTRACT = @@ -44,7 +41,6 @@ const recipientTypes = [ ] as const; let token: FungibleTokenSimulator; -let caller: CoinPublicKey; describe('FungibleToken', () => { describe('before initialization', () => { @@ -155,8 +151,7 @@ describe('FungibleToken', () => { it('should transfer partial', () => { const partialAmt = AMOUNT - 1n; - caller = OWNER; - const txSuccess = token.transfer(Z_RECIPIENT, partialAmt, caller); + const txSuccess = token.as(OWNER).transfer(Z_RECIPIENT, partialAmt); expect(txSuccess).toBe(true); expect(token.balanceOf(Z_OWNER)).toEqual(1n); @@ -164,8 +159,7 @@ describe('FungibleToken', () => { }); it('should transfer full', () => { - caller = OWNER; - const txSuccess = token.transfer(Z_RECIPIENT, AMOUNT, caller); + const txSuccess = token.as(OWNER).transfer(Z_RECIPIENT, AMOUNT); expect(txSuccess).toBe(true); expect(token.balanceOf(Z_OWNER)).toEqual(0n); @@ -173,31 +167,25 @@ describe('FungibleToken', () => { }); it('should fail with insufficient balance', () => { - caller = OWNER; - expect(() => { - token.transfer(Z_RECIPIENT, AMOUNT + 1n, caller); + token.as(OWNER).transfer(Z_RECIPIENT, AMOUNT + 1n); }).toThrow('FungibleToken: insufficient balance'); }); it('should fail with transfer from zero', () => { - caller = ZERO; - expect(() => { - token.transfer(Z_RECIPIENT, AMOUNT, caller); + token.as(ZERO).transfer(Z_RECIPIENT, AMOUNT); }).toThrow('FungibleToken: invalid sender'); }); it('should fail with transfer to zero', () => { - caller = OWNER; - expect(() => { - token.transfer(utils.ZERO_KEY, AMOUNT, caller); + token.as(OWNER).transfer(utils.ZERO_KEY, AMOUNT); }).toThrow('FungibleToken: invalid receiver'); }); it('should allow transfer of 0 tokens', () => { - const txSuccess = token.transfer(Z_RECIPIENT, 0n, caller); + const txSuccess = token.as(OWNER).transfer(Z_RECIPIENT, 0n); expect(txSuccess).toBe(true); expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); @@ -205,10 +193,8 @@ describe('FungibleToken', () => { }); it('should handle transfer with empty _balances', () => { - caller = SPENDER; - expect(() => { - token.transfer(Z_RECIPIENT, 1n, caller); + token.as(SPENDER).transfer(Z_RECIPIENT, 1n); }).toThrow('FungibleToken: insufficient balance'); }); @@ -236,12 +222,9 @@ describe('FungibleToken', () => { it('should transfer partial', () => { const partialAmt = AMOUNT - 1n; - caller = OWNER; - const txSuccess = token._unsafeTransfer( - recipient, - partialAmt, - caller, - ); + const txSuccess = token + .as(OWNER) + ._unsafeTransfer(recipient, partialAmt); expect(txSuccess).toBe(true); expect(token.balanceOf(Z_OWNER)).toEqual(1n); @@ -249,8 +232,7 @@ describe('FungibleToken', () => { }); it('should transfer full', () => { - caller = OWNER; - const txSuccess = token._unsafeTransfer(recipient, AMOUNT, caller); + const txSuccess = token.as(OWNER)._unsafeTransfer(recipient, AMOUNT); expect(txSuccess).toBe(true); expect(token.balanceOf(Z_OWNER)).toEqual(0n); @@ -258,24 +240,19 @@ describe('FungibleToken', () => { }); it('should fail with insufficient balance', () => { - caller = OWNER; - expect(() => { - token._unsafeTransfer(recipient, AMOUNT + 1n, caller); + token.as(OWNER)._unsafeTransfer(recipient, AMOUNT + 1n); }).toThrow('FungibleToken: insufficient balance'); }); it('should fail with transfer from zero', () => { - caller = ZERO; - expect(() => { - token._unsafeTransfer(recipient, AMOUNT, caller); + token.as(ZERO)._unsafeTransfer(recipient, AMOUNT); }).toThrow('FungibleToken: invalid sender'); }); it('should allow transfer of 0 tokens', () => { - caller = OWNER; - const txSuccess = token._unsafeTransfer(recipient, 0n, caller); + const txSuccess = token.as(OWNER)._unsafeTransfer(recipient, 0n); expect(txSuccess).toBe(true); expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); @@ -283,27 +260,21 @@ describe('FungibleToken', () => { }); it('should handle transfer with empty _balances', () => { - caller = SPENDER; - expect(() => { - token._unsafeTransfer(recipient, 1n, caller); + token.as(SPENDER)._unsafeTransfer(recipient, 1n); }).toThrow('FungibleToken: insufficient balance'); }); }); it('should fail with transfer to zero (pk)', () => { - caller = OWNER; - expect(() => { - token._unsafeTransfer(utils.ZERO_KEY, AMOUNT, caller); + token.as(OWNER)._unsafeTransfer(utils.ZERO_KEY, AMOUNT); }).toThrow('FungibleToken: invalid receiver'); }); it('should fail with transfer to zero (contract)', () => { - caller = OWNER; - expect(() => { - token._unsafeTransfer(utils.ZERO_ADDRESS, AMOUNT, caller); + token.as(OWNER)._unsafeTransfer(utils.ZERO_ADDRESS, AMOUNT); }).toThrow('FungibleToken: invalid receiver'); }); }); @@ -314,57 +285,46 @@ describe('FungibleToken', () => { }); it('should approve and update allowance', () => { - caller = OWNER; - - token.approve(Z_SPENDER, AMOUNT, caller); + token.as(OWNER).approve(Z_SPENDER, AMOUNT); expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(AMOUNT); }); it('should approve and update allowance for multiple spenders', () => { - caller = OWNER; - - token.approve(Z_SPENDER, AMOUNT, caller); + token.as(OWNER).approve(Z_SPENDER, AMOUNT); expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(AMOUNT); - token.approve(Z_OTHER, AMOUNT, caller); + token.as(OWNER).approve(Z_OTHER, AMOUNT); expect(token.allowance(Z_OWNER, Z_OTHER)).toEqual(AMOUNT); expect(token.allowance(Z_OWNER, Z_RECIPIENT)).toEqual(0n); }); it('should fail when approve from zero', () => { - caller = ZERO; - expect(() => { - token.approve(Z_SPENDER, AMOUNT, caller); + token.as(ZERO).approve(Z_SPENDER, AMOUNT); }).toThrow('FungibleToken: invalid owner'); }); it('should fail when approve to zero', () => { - caller = OWNER; - expect(() => { - token.approve(utils.ZERO_KEY, AMOUNT, caller); + token.as(OWNER).approve(utils.ZERO_KEY, AMOUNT); }).toThrow('FungibleToken: invalid spender'); }); it('should transfer exact allowance and fail subsequent transfer', () => { token._mint(Z_OWNER, AMOUNT); - caller = OWNER; - token.approve(Z_SPENDER, AMOUNT, caller); + token.as(OWNER).approve(Z_SPENDER, AMOUNT); - caller = SPENDER; - token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); + token.as(SPENDER).transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT); expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); expect(() => { - token.transferFrom(Z_OWNER, Z_RECIPIENT, 1n, caller); + token.as(SPENDER).transferFrom(Z_OWNER, Z_RECIPIENT, 1n); }).toThrow('FungibleToken: insufficient allowance'); }); it('should allow approve of 0 tokens', () => { - caller = OWNER; - token.approve(Z_SPENDER, 0n, caller); + token.as(OWNER).approve(Z_SPENDER, 0n); expect(token.allowance(Z_OWNER, Z_SPENDER)).toEqual(0n); }); @@ -375,9 +335,7 @@ describe('FungibleToken', () => { describe('transferFrom', () => { beforeEach(() => { - caller = OWNER; - - token.approve(Z_SPENDER, AMOUNT, caller); + token.as(OWNER).approve(Z_SPENDER, AMOUNT); token._mint(Z_OWNER, AMOUNT); }); @@ -386,15 +344,11 @@ describe('FungibleToken', () => { }); it('should transferFrom spender (partial)', () => { - caller = SPENDER; const partialAmt = AMOUNT - 1n; - const txSuccess = token.transferFrom( - Z_OWNER, - Z_RECIPIENT, - partialAmt, - caller, - ); + const txSuccess = token + .as(SPENDER) + .transferFrom(Z_OWNER, Z_RECIPIENT, partialAmt); expect(txSuccess).toBe(true); // Check balances @@ -405,14 +359,9 @@ describe('FungibleToken', () => { }); it('should transferFrom spender (full)', () => { - caller = SPENDER; - - const txSuccess = token.transferFrom( - Z_OWNER, - Z_RECIPIENT, - AMOUNT, - caller, - ); + const txSuccess = token + .as(SPENDER) + .transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT); expect(txSuccess).toBe(true); // Check balances @@ -423,16 +372,11 @@ describe('FungibleToken', () => { }); it('should transferFrom and not consume infinite allowance', () => { - caller = OWNER; - token.approve(Z_SPENDER, MAX_UINT128, caller); - - caller = SPENDER; - const txSuccess = token.transferFrom( - Z_OWNER, - Z_RECIPIENT, - AMOUNT, - caller, - ); + token.as(OWNER).approve(Z_SPENDER, MAX_UINT128); + + const txSuccess = token + .as(SPENDER) + .transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT); expect(txSuccess).toBe(true); // Check balances @@ -443,60 +387,48 @@ describe('FungibleToken', () => { }); it('should fail when transfer amount exceeds allowance', () => { - caller = SPENDER; - expect(() => { - token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT + 1n); + token.as(SPENDER).transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT + 1n); }).toThrow('FungibleToken: insufficient allowance'); }); it('should fail when transfer amount exceeds balance', () => { - caller = OWNER; // Increase allowance > balance - token.approve(Z_SPENDER, AMOUNT + 1n, caller); + token.as(OWNER).approve(Z_SPENDER, AMOUNT + 1n); - caller = SPENDER; expect(() => { - token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT + 1n, caller); + token.as(SPENDER).transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT + 1n); }).toThrow('FungibleToken: insufficient balance'); }); it('should fail when spender does not have allowance', () => { - caller = UNAUTHORIZED; - expect(() => { - token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); + token.as(UNAUTHORIZED).transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT); }).toThrow('FungibleToken: insufficient allowance'); }); it('should fail to transferFrom zero address', () => { - caller = ZERO; - expect(() => { - token.transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT, caller); + token.as(ZERO).transferFrom(Z_OWNER, Z_RECIPIENT, AMOUNT); }).toThrow('FungibleToken: insufficient allowance'); }); it('should fail to transferFrom to the zero address', () => { - caller = SPENDER; - expect(() => { - token.transferFrom(Z_OWNER, utils.ZERO_KEY, AMOUNT, caller); + token.as(SPENDER).transferFrom(Z_OWNER, utils.ZERO_KEY, AMOUNT); }).toThrow('FungibleToken: invalid receiver'); }); it('should fail when transferring to a contract', () => { expect(() => { - token.transferFrom(Z_OWNER, Z_OWNER_CONTRACT, AMOUNT, caller); + token.as(OWNER).transferFrom(Z_OWNER, Z_OWNER_CONTRACT, AMOUNT); }).toThrow('FungibleToken: Unsafe Transfer'); }); }); describe('_unsafeTransferFrom', () => { beforeEach(() => { - caller = OWNER; - - token.approve(Z_SPENDER, AMOUNT, caller); + token.as(OWNER).approve(Z_SPENDER, AMOUNT); token._mint(Z_OWNER, AMOUNT); }); @@ -508,15 +440,11 @@ describe('FungibleToken', () => { recipientTypes, )('when the recipient is a %s', (_, recipient) => { it('should transferFrom spender (partial)', () => { - caller = SPENDER; const partialAmt = AMOUNT - 1n; - const txSuccess = token._unsafeTransferFrom( - Z_OWNER, - recipient, - partialAmt, - caller, - ); + const txSuccess = token + .as(SPENDER) + ._unsafeTransferFrom(Z_OWNER, recipient, partialAmt); expect(txSuccess).toBe(true); // Check balances @@ -527,14 +455,9 @@ describe('FungibleToken', () => { }); it('should transferFrom spender (full)', () => { - caller = SPENDER; - - const txSuccess = token._unsafeTransferFrom( - Z_OWNER, - recipient, - AMOUNT, - caller, - ); + const txSuccess = token + .as(SPENDER) + ._unsafeTransferFrom(Z_OWNER, recipient, AMOUNT); expect(txSuccess).toBe(true); // Check balances @@ -545,16 +468,11 @@ describe('FungibleToken', () => { }); it('should transferFrom and not consume infinite allowance', () => { - caller = OWNER; - token.approve(Z_SPENDER, MAX_UINT128, caller); - - caller = SPENDER; - const txSuccess = token._unsafeTransferFrom( - Z_OWNER, - recipient, - AMOUNT, - caller, - ); + token.as(OWNER).approve(Z_SPENDER, MAX_UINT128); + + const txSuccess = token + .as(SPENDER) + ._unsafeTransferFrom(Z_OWNER, recipient, AMOUNT); expect(txSuccess).toBe(true); // Check balances @@ -565,59 +483,52 @@ describe('FungibleToken', () => { }); it('should fail when transfer amount exceeds allowance', () => { - caller = SPENDER; - expect(() => { - token._unsafeTransferFrom(Z_OWNER, recipient, AMOUNT + 1n); + token + .as(SPENDER) + ._unsafeTransferFrom(Z_OWNER, recipient, AMOUNT + 1n); }).toThrow('FungibleToken: insufficient allowance'); }); it('should fail when transfer amount exceeds balance', () => { - caller = OWNER; // Increase allowance > balance - token.approve(Z_SPENDER, AMOUNT + 1n, caller); + token.as(OWNER).approve(Z_SPENDER, AMOUNT + 1n); - caller = SPENDER; expect(() => { - token._unsafeTransferFrom(Z_OWNER, recipient, AMOUNT + 1n, caller); + token + .as(SPENDER) + ._unsafeTransferFrom(Z_OWNER, recipient, AMOUNT + 1n); }).toThrow('FungibleToken: insufficient balance'); }); it('should fail when spender does not have allowance', () => { - caller = UNAUTHORIZED; - expect(() => { - token._unsafeTransferFrom(Z_OWNER, recipient, AMOUNT, caller); + token + .as(UNAUTHORIZED) + ._unsafeTransferFrom(Z_OWNER, recipient, AMOUNT); }).toThrow('FungibleToken: insufficient allowance'); }); it('should fail to transfer from the zero address', () => { - caller = ZERO; - expect(() => { - token._unsafeTransferFrom(Z_OWNER, recipient, AMOUNT, caller); + token.as(ZERO)._unsafeTransferFrom(Z_OWNER, recipient, AMOUNT); }).toThrow('FungibleToken: insufficient allowance'); }); }); it('should fail to transfer to the zero address (pk)', () => { - caller = SPENDER; - expect(() => { - token._unsafeTransferFrom(Z_OWNER, utils.ZERO_KEY, AMOUNT, caller); + token + .as(SPENDER) + ._unsafeTransferFrom(Z_OWNER, utils.ZERO_KEY, AMOUNT); }).toThrow('FungibleToken: invalid receiver'); }); it('should fail to transfer to the zero address (contract)', () => { - caller = SPENDER; - expect(() => { - token._unsafeTransferFrom( - Z_OWNER, - utils.ZERO_ADDRESS, - AMOUNT, - caller, - ); + token + .as(SPENDER) + ._unsafeTransferFrom(Z_OWNER, utils.ZERO_ADDRESS, AMOUNT); }).toThrow('FungibleToken: invalid receiver'); }); }); @@ -915,8 +826,7 @@ describe('FungibleToken', () => { expect(token.totalSupply()).toEqual(AMOUNT); expect(token.balanceOf(Z_OWNER)).toEqual(AMOUNT); - caller = OWNER; - token.transfer(Z_RECIPIENT, AMOUNT - 1n, caller); + token.as(OWNER).transfer(Z_RECIPIENT, AMOUNT - 1n); expect(token.balanceOf(Z_OWNER)).toEqual(1n); expect(token.balanceOf(Z_RECIPIENT)).toEqual(AMOUNT - 1n); diff --git a/contracts/src/token/test/MultiToken.test.ts b/contracts/src/token/test/MultiToken.test.ts index d9bac0d7..d8a8a707 100644 --- a/contracts/src/token/test/MultiToken.test.ts +++ b/contracts/src/token/test/MultiToken.test.ts @@ -1,8 +1,7 @@ -import type { CoinPublicKey } from '@midnight-ntwrk/compact-runtime'; import { beforeEach, describe, expect, it } from 'vitest'; -import type { Maybe } from '../../../artifacts/MockMultiToken/contract/index.cjs'; // Combined imports +import * as utils from '#test-utils/address.js'; +import type { Maybe } from '../../../artifacts/MockMultiToken/contract/index.js'; // Combined imports import { MultiTokenSimulator } from './simulators/MultiTokenSimulator.js'; -import * as utils from './utils/address.js'; // URIs const NO_STRING = ''; @@ -19,17 +18,15 @@ const TOKEN_ID: bigint = BigInt(1); const TOKEN_ID2: bigint = BigInt(22); const NONEXISTENT_ID: bigint = BigInt(987654321); -// Callers -const OWNER = utils.toHexPadded('OWNER'); -const SPENDER = utils.toHexPadded('SPENDER'); -const UNAUTHORIZED = utils.toHexPadded('UNAUTHORIZED'); -const ZERO = utils.toHexPadded(''); - -// Encoded PK/Addresses -const Z_OWNER = utils.createEitherTestUser('OWNER'); -const Z_RECIPIENT = utils.createEitherTestUser('RECIPIENT'); -const Z_SPENDER = utils.createEitherTestUser('SPENDER'); -const Z_OTHER = utils.createEitherTestUser('OTHER'); +// PKs +const [OWNER, Z_OWNER] = utils.generateEitherPubKeyPair('OWNER'); +const [SPENDER, Z_SPENDER] = utils.generateEitherPubKeyPair('SPENDER'); +const [UNAUTHORIZED] = utils.generateEitherPubKeyPair('UNAUTHORIZED'); +const [ZERO] = utils.generateEitherPubKeyPair(''); +const [, Z_RECIPIENT] = utils.generateEitherPubKeyPair('RECIPIENT'); +const [OTHER, Z_OTHER] = utils.generateEitherPubKeyPair('OTHER'); + +// Encoded contract addresses const Z_OWNER_CONTRACT = utils.createEitherTestContractAddress('OWNER_CONTRACT'); const Z_RECIPIENT_CONTRACT = @@ -63,7 +60,6 @@ const callerTypes = [ ] as const; let token: MultiTokenSimulator; -let caller: CoinPublicKey; describe('MultiToken', () => { describe('before initialization', () => { @@ -174,42 +170,37 @@ describe('MultiToken', () => { }); it('should handle approving owner as operator', () => { - token.setApprovalForAll(Z_OWNER, true, OWNER); + token.as(OWNER).setApprovalForAll(Z_OWNER, true); expect(token.isApprovedForAll(Z_OWNER, Z_OWNER)).toBe(true); }); it('should handle multiple approvals of same operator', () => { - token.setApprovalForAll(Z_SPENDER, true, OWNER); - token.setApprovalForAll(Z_SPENDER, true, OWNER); + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); }); it('should handle revoking non-existent approval', () => { - token.setApprovalForAll(Z_SPENDER, false, OWNER); + token.as(OWNER).setApprovalForAll(Z_SPENDER, false); expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(false); }); }); describe('setApprovalForAll', () => { it('should return false when set to false', () => { - caller = OWNER; - - token.setApprovalForAll(Z_SPENDER, false, caller); + token.as(OWNER).setApprovalForAll(Z_SPENDER, false); expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(false); }); it('should fail when attempting to approve zero address as an operator', () => { - caller = OWNER; - expect(() => { - token.setApprovalForAll(utils.ZERO_KEY, true); + token.as(OWNER).setApprovalForAll(utils.ZERO_KEY, true); }).toThrow('MultiToken: invalid operator'); }); describe('when spender is approved as an operator', () => { beforeEach(() => { - caller = OWNER; - token.setApprovalForAll(Z_SPENDER, true, caller); + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); }); it('should return true when set to true', () => { @@ -237,16 +228,15 @@ describe('MultiToken', () => { expect(token.balanceOf(Z_RECIPIENT, TOKEN_ID)).toEqual(0n); }); - describe.each(callerTypes)('when the caller is the %s', (_, _caller) => { + describe.each(callerTypes)('when the caller is the %s', (_, caller) => { beforeEach(() => { - if (_caller === SPENDER) { + if (caller === SPENDER) { token._setApprovalForAll(Z_OWNER, Z_SPENDER, true); } - caller = _caller; }); it('should transfer whole', () => { - token.transferFrom(Z_OWNER, Z_RECIPIENT, TOKEN_ID, AMOUNT, caller); + token.as(caller).transferFrom(Z_OWNER, Z_RECIPIENT, TOKEN_ID, AMOUNT); expect(token.balanceOf(Z_OWNER, TOKEN_ID)).toEqual(0n); expect(token.balanceOf(Z_RECIPIENT, TOKEN_ID)).toEqual(AMOUNT); @@ -254,13 +244,9 @@ describe('MultiToken', () => { it('should transfer partial', () => { const partialAmt = AMOUNT - 1n; - token.transferFrom( - Z_OWNER, - Z_RECIPIENT, - TOKEN_ID, - partialAmt, - caller, - ); + token + .as(caller) + .transferFrom(Z_OWNER, Z_RECIPIENT, TOKEN_ID, partialAmt); expect(token.balanceOf(Z_OWNER, TOKEN_ID)).toEqual( AMOUNT - partialAmt, @@ -269,14 +255,14 @@ describe('MultiToken', () => { }); it('should allow transfer of 0 tokens', () => { - token.transferFrom(Z_OWNER, Z_RECIPIENT, TOKEN_ID, 0n, caller); + token.as(caller).transferFrom(Z_OWNER, Z_RECIPIENT, TOKEN_ID, 0n); expect(token.balanceOf(Z_OWNER, TOKEN_ID)).toEqual(AMOUNT); expect(token.balanceOf(Z_RECIPIENT, TOKEN_ID)).toEqual(0n); }); it('should handle self-transfer', () => { - token.transferFrom(Z_OWNER, Z_OWNER, TOKEN_ID, AMOUNT, caller); + token.as(caller).transferFrom(Z_OWNER, Z_OWNER, TOKEN_ID, AMOUNT); expect(token.balanceOf(Z_OWNER, TOKEN_ID)).toEqual(AMOUNT); }); @@ -284,185 +270,140 @@ describe('MultiToken', () => { // Mint rest of tokens to == MAX_UINT128 token._mint(Z_OWNER, TOKEN_ID, MAX_UINT128 - AMOUNT); - token.transferFrom( - Z_OWNER, - Z_RECIPIENT, - TOKEN_ID, - MAX_UINT128, - caller, - ); + token + .as(caller) + .transferFrom(Z_OWNER, Z_RECIPIENT, TOKEN_ID, MAX_UINT128); expect(token.balanceOf(Z_RECIPIENT, TOKEN_ID)).toEqual(MAX_UINT128); }); it('should handle rapid state changes', () => { // Approve -> Transfer -> Revoke -> Approve - caller = OWNER; - token.setApprovalForAll(Z_SPENDER, true, caller); + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); - token.transferFrom(Z_OWNER, Z_RECIPIENT, TOKEN_ID, AMOUNT, SPENDER); + token + .as(SPENDER) + .transferFrom(Z_OWNER, Z_RECIPIENT, TOKEN_ID, AMOUNT); expect(token.balanceOf(Z_RECIPIENT, TOKEN_ID)).toEqual(AMOUNT); - token.setApprovalForAll(Z_SPENDER, false, caller); + token.as(OWNER).setApprovalForAll(Z_SPENDER, false); expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(false); - token.setApprovalForAll(Z_SPENDER, true, caller); + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); }); - it('should handle concurrent operations on same token ID', () => { - token._mint(Z_OWNER, TOKEN_ID, AMOUNT * 2n); - - // Set up two spenders - token.setApprovalForAll(Z_SPENDER, true, caller); - token.setApprovalForAll(Z_OTHER, true, caller); - - // First spender transfers half - token.transferFrom(Z_OWNER, Z_RECIPIENT, TOKEN_ID, AMOUNT, SPENDER); - expect(token.balanceOf(Z_RECIPIENT, TOKEN_ID)).toEqual(AMOUNT); - - // Second spender transfers remaining - token.transferFrom(Z_OWNER, Z_RECIPIENT, TOKEN_ID, AMOUNT, SPENDER); - expect(token.balanceOf(Z_RECIPIENT, TOKEN_ID)).toEqual(AMOUNT * 2n); - }); - it('should fail with insufficient balance', () => { expect(() => { - token.transferFrom( - Z_OWNER, - Z_RECIPIENT, - TOKEN_ID, - AMOUNT + 1n, - caller, - ); + token + .as(caller) + .transferFrom(Z_OWNER, Z_RECIPIENT, TOKEN_ID, AMOUNT + 1n); }).toThrow('MultiToken: insufficient balance'); }); it('should fail with nonexistent id', () => { expect(() => { - token.transferFrom( - Z_OWNER, - Z_RECIPIENT, - NONEXISTENT_ID, - AMOUNT, - caller, - ); + token + .as(caller) + .transferFrom(Z_OWNER, Z_RECIPIENT, NONEXISTENT_ID, AMOUNT); }).toThrow('MultiToken: insufficient balance'); }); it('should fail with transfer from zero', () => { expect(() => { - token.transferFrom( - utils.ZERO_KEY, - Z_RECIPIENT, - TOKEN_ID, - AMOUNT, - caller, - ); + token + .as(caller) + .transferFrom(utils.ZERO_KEY, Z_RECIPIENT, TOKEN_ID, AMOUNT); }).toThrow('MultiToken: unauthorized operator'); }); it('should fail with transfer to zero (pk)', () => { expect(() => { - token.transferFrom( - Z_OWNER, - utils.ZERO_KEY, - TOKEN_ID, - AMOUNT, - caller, - ); + token + .as(caller) + .transferFrom(Z_OWNER, utils.ZERO_KEY, TOKEN_ID, AMOUNT); }).toThrow('MultiToken: invalid receiver'); }); it('should fail with transfer to zero (contract)', () => { expect(() => { - token.transferFrom( - Z_OWNER, - utils.ZERO_ADDRESS, - TOKEN_ID, - AMOUNT, - caller, - ); + token + .as(caller) + .transferFrom(Z_OWNER, utils.ZERO_ADDRESS, TOKEN_ID, AMOUNT); }).toThrow('MultiToken: unsafe transfer'); }); it('should fail when transferring to a contract address', () => { expect(() => { - token.transferFrom( - Z_OWNER, - Z_RECIPIENT_CONTRACT, - TOKEN_ID, - AMOUNT, - caller, - ); + token + .as(caller) + .transferFrom(Z_OWNER, Z_RECIPIENT_CONTRACT, TOKEN_ID, AMOUNT); }).toThrow('MultiToken: unsafe transfer'); }); }); - describe('when the caller is unauthorized', () => { - beforeEach(() => { - caller = UNAUTHORIZED; - }); + it('should handle concurrent operations on same token ID', () => { + token._mint(Z_OWNER, TOKEN_ID, AMOUNT * 2n); + + // Set up two spenders + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); + token.as(OWNER).setApprovalForAll(Z_OTHER, true); + // First spender transfers half + token.as(SPENDER).transferFrom(Z_OWNER, Z_RECIPIENT, TOKEN_ID, AMOUNT); + expect(token.balanceOf(Z_RECIPIENT, TOKEN_ID)).toEqual(AMOUNT); + + // Second spender transfers remaining + token.as(OTHER).transferFrom(Z_OWNER, Z_RECIPIENT, TOKEN_ID, AMOUNT); + expect(token.balanceOf(Z_RECIPIENT, TOKEN_ID)).toEqual(AMOUNT * 2n); + }); + + describe('when the caller is unauthorized', () => { it('should fail when transfer whole', () => { expect(() => { - token.transferFrom(Z_OWNER, Z_RECIPIENT, TOKEN_ID, AMOUNT, caller); + token + .as(UNAUTHORIZED) + .transferFrom(Z_OWNER, Z_RECIPIENT, TOKEN_ID, AMOUNT); }).toThrow('MultiToken: unauthorized operator'); }); it('should fail when transfer partial', () => { expect(() => { const partialAmt = AMOUNT - 1n; - token.transferFrom( - Z_OWNER, - Z_RECIPIENT, - TOKEN_ID, - partialAmt, - caller, - ); + token + .as(UNAUTHORIZED) + .transferFrom(Z_OWNER, Z_RECIPIENT, TOKEN_ID, partialAmt); }).toThrow('MultiToken: unauthorized operator'); }); it('should fail when transfer zero', () => { expect(() => { - token.transferFrom(Z_OWNER, Z_RECIPIENT, TOKEN_ID, 0n, caller); + token + .as(UNAUTHORIZED) + .transferFrom(Z_OWNER, Z_RECIPIENT, TOKEN_ID, 0n); }).toThrow('MultiToken: unauthorized operator'); }); it('should fail with insufficient balance', () => { expect(() => { - token.transferFrom( - Z_OWNER, - Z_RECIPIENT, - TOKEN_ID, - AMOUNT + 1n, - caller, - ); + token + .as(UNAUTHORIZED) + .transferFrom(Z_OWNER, Z_RECIPIENT, TOKEN_ID, AMOUNT + 1n); }).toThrow('MultiToken: unauthorized operator'); }); it('should fail with nonexistent id', () => { expect(() => { - token.transferFrom( - Z_OWNER, - Z_RECIPIENT, - NONEXISTENT_ID, - AMOUNT, - caller, - ); + token + .as(UNAUTHORIZED) + .transferFrom(Z_OWNER, Z_RECIPIENT, NONEXISTENT_ID, AMOUNT); }).toThrow('MultiToken: unauthorized operator'); }); it('should fail with transfer from zero', () => { - caller = ZERO; - expect(() => { - token.transferFrom( - utils.ZERO_KEY, - Z_RECIPIENT, - TOKEN_ID, - AMOUNT, - caller, - ); + token + .as(ZERO) + .transferFrom(utils.ZERO_KEY, Z_RECIPIENT, TOKEN_ID, AMOUNT); }).toThrow('MultiToken: invalid sender'); }); }); @@ -473,25 +414,20 @@ describe('MultiToken', () => { token._mint(Z_OWNER, TOKEN_ID, AMOUNT); }); - describe.each(callerTypes)('when the caller is the %s', (_, _caller) => { + describe.each(callerTypes)('when the caller is the %s', (_, caller) => { beforeEach(() => { - if (_caller === SPENDER) { + if (caller === SPENDER) { token._setApprovalForAll(Z_OWNER, Z_SPENDER, true); } - caller = _caller; }); describe.each( recipientTypes, )('when the recipient is a %s', (_, recipient) => { it('should transfer whole', () => { - token._unsafeTransferFrom( - Z_OWNER, - recipient, - TOKEN_ID, - AMOUNT, - caller, - ); + token + .as(caller) + ._unsafeTransferFrom(Z_OWNER, recipient, TOKEN_ID, AMOUNT); expect(token.balanceOf(Z_OWNER, TOKEN_ID)).toEqual(0n); expect(token.balanceOf(recipient, TOKEN_ID)).toEqual(AMOUNT); @@ -499,13 +435,9 @@ describe('MultiToken', () => { it('should transfer partial', () => { const partialAmt = AMOUNT - 1n; - token._unsafeTransferFrom( - Z_OWNER, - recipient, - TOKEN_ID, - partialAmt, - caller, - ); + token + .as(caller) + ._unsafeTransferFrom(Z_OWNER, recipient, TOKEN_ID, partialAmt); expect(token.balanceOf(Z_OWNER, TOKEN_ID)).toEqual( AMOUNT - partialAmt, @@ -514,20 +446,18 @@ describe('MultiToken', () => { }); it('should allow transfer of 0 tokens', () => { - token._unsafeTransferFrom(Z_OWNER, recipient, TOKEN_ID, 0n, caller); + token + .as(caller) + ._unsafeTransferFrom(Z_OWNER, recipient, TOKEN_ID, 0n); expect(token.balanceOf(Z_OWNER, TOKEN_ID)).toEqual(AMOUNT); expect(token.balanceOf(recipient, TOKEN_ID)).toEqual(0n); }); it('should handle self-transfer', () => { - token._unsafeTransferFrom( - Z_OWNER, - Z_OWNER, - TOKEN_ID, - AMOUNT, - caller, - ); + token + .as(caller) + ._unsafeTransferFrom(Z_OWNER, Z_OWNER, TOKEN_ID, AMOUNT); expect(token.balanceOf(Z_OWNER, TOKEN_ID)).toEqual(AMOUNT); }); @@ -535,207 +465,165 @@ describe('MultiToken', () => { // Mint rest of tokens to == MAX_UINT128 token._mint(Z_OWNER, TOKEN_ID, MAX_UINT128 - AMOUNT); - token._unsafeTransferFrom( - Z_OWNER, - recipient, - TOKEN_ID, - MAX_UINT128, - caller, - ); + token + .as(caller) + ._unsafeTransferFrom(Z_OWNER, recipient, TOKEN_ID, MAX_UINT128); expect(token.balanceOf(recipient, TOKEN_ID)).toEqual(MAX_UINT128); }); it('should handle rapid state changes', () => { // Approve -> Transfer -> Revoke -> Approve - caller = OWNER; - token.setApprovalForAll(Z_SPENDER, true, caller); + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); - token._unsafeTransferFrom( - Z_OWNER, - recipient, - TOKEN_ID, - AMOUNT, - SPENDER, - ); + token + .as(OWNER) + ._unsafeTransferFrom(Z_OWNER, recipient, TOKEN_ID, AMOUNT); expect(token.balanceOf(recipient, TOKEN_ID)).toEqual(AMOUNT); - token.setApprovalForAll(Z_SPENDER, false, caller); + token.as(OWNER).setApprovalForAll(Z_SPENDER, false); expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(false); - token.setApprovalForAll(Z_SPENDER, true, caller); + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); }); - it('should handle concurrent operations on same token ID', () => { - token._mint(Z_OWNER, TOKEN_ID, AMOUNT * 2n); - - // Set up two spenders - token.setApprovalForAll(Z_SPENDER, true, caller); - token.setApprovalForAll(Z_OTHER, true, caller); - - // First spender transfers half - token._unsafeTransferFrom( - Z_OWNER, - recipient, - TOKEN_ID, - AMOUNT, - SPENDER, - ); - expect(token.balanceOf(recipient, TOKEN_ID)).toEqual(AMOUNT); - - // Second spender transfers remaining - token._unsafeTransferFrom( - Z_OWNER, - recipient, - TOKEN_ID, - AMOUNT, - SPENDER, - ); - expect(token.balanceOf(recipient, TOKEN_ID)).toEqual(AMOUNT * 2n); - }); - it('should fail with insufficient balance', () => { expect(() => { - token._unsafeTransferFrom( - Z_OWNER, - recipient, - TOKEN_ID, - AMOUNT + 1n, - caller, - ); + token + .as(caller) + ._unsafeTransferFrom(Z_OWNER, recipient, TOKEN_ID, AMOUNT + 1n); }).toThrow('MultiToken: insufficient balance'); }); it('should fail with nonexistent id', () => { expect(() => { - token._unsafeTransferFrom( - Z_OWNER, - recipient, - NONEXISTENT_ID, - AMOUNT, - caller, - ); + token + .as(caller) + ._unsafeTransferFrom( + Z_OWNER, + recipient, + NONEXISTENT_ID, + AMOUNT, + ); }).toThrow('MultiToken: insufficient balance'); }); it('should fail with transfer from zero', () => { expect(() => { - token._unsafeTransferFrom( - utils.ZERO_KEY, - recipient, - TOKEN_ID, - AMOUNT, - caller, - ); + token + .as(caller) + ._unsafeTransferFrom( + utils.ZERO_KEY, + recipient, + TOKEN_ID, + AMOUNT, + ); }).toThrow('MultiToken: unauthorized operator'); }); }); it('should fail with transfer to zero (pk)', () => { expect(() => { - token._unsafeTransferFrom( - Z_OWNER, - utils.ZERO_KEY, - TOKEN_ID, - AMOUNT, - caller, - ); + token + .as(caller) + ._unsafeTransferFrom(Z_OWNER, utils.ZERO_KEY, TOKEN_ID, AMOUNT); }).toThrow('MultiToken: invalid receiver'); }); it('should fail with transfer to zero (contract)', () => { expect(() => { - token._unsafeTransferFrom( - Z_OWNER, - utils.ZERO_ADDRESS, - TOKEN_ID, - AMOUNT, - caller, - ); + token + .as(caller) + ._unsafeTransferFrom( + Z_OWNER, + utils.ZERO_ADDRESS, + TOKEN_ID, + AMOUNT, + ); }).toThrow('MultiToken: invalid receiver'); }); }); - describe('when the caller is unauthorized', () => { - beforeEach(() => { - caller = UNAUTHORIZED; - }); + it('should handle concurrent operations on same token ID', () => { + token._mint(Z_OWNER, TOKEN_ID, AMOUNT * 2n); + + // Set up two spenders + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); + token.as(OWNER).setApprovalForAll(Z_OTHER, true); + + // First spender transfers half + token + .as(SPENDER) + ._unsafeTransferFrom(Z_OWNER, Z_RECIPIENT, TOKEN_ID, AMOUNT); + expect(token.balanceOf(Z_RECIPIENT, TOKEN_ID)).toEqual(AMOUNT); + // Second spender transfers remaining + token + .as(OTHER) + ._unsafeTransferFrom(Z_OWNER, Z_RECIPIENT, TOKEN_ID, AMOUNT); + expect(token.balanceOf(Z_RECIPIENT, TOKEN_ID)).toEqual(AMOUNT * 2n); + }); + + describe('when the caller is unauthorized', () => { describe.each( recipientTypes, )('when recipient is %s', (_, recipient) => { it('should fail when transfer whole', () => { expect(() => { - token._unsafeTransferFrom( - Z_OWNER, - recipient, - TOKEN_ID, - AMOUNT, - caller, - ); + token + .as(UNAUTHORIZED) + ._unsafeTransferFrom(Z_OWNER, recipient, TOKEN_ID, AMOUNT); }).toThrow('MultiToken: unauthorized operator'); }); it('should fail when transfer partial', () => { expect(() => { const partialAmt = AMOUNT - 1n; - token._unsafeTransferFrom( - Z_OWNER, - recipient, - TOKEN_ID, - partialAmt, - caller, - ); + token + .as(UNAUTHORIZED) + ._unsafeTransferFrom(Z_OWNER, recipient, TOKEN_ID, partialAmt); }).toThrow('MultiToken: unauthorized operator'); }); it('should fail when transfer zero', () => { expect(() => { - token._unsafeTransferFrom( - Z_OWNER, - recipient, - TOKEN_ID, - 0n, - caller, - ); + token + .as(UNAUTHORIZED) + ._unsafeTransferFrom(Z_OWNER, recipient, TOKEN_ID, 0n); }).toThrow('MultiToken: unauthorized operator'); }); it('should fail with insufficient balance', () => { expect(() => { - token._unsafeTransferFrom( - Z_OWNER, - recipient, - TOKEN_ID, - AMOUNT + 1n, - caller, - ); + token + .as(UNAUTHORIZED) + ._unsafeTransferFrom(Z_OWNER, recipient, TOKEN_ID, AMOUNT + 1n); }).toThrow('MultiToken: unauthorized operator'); }); it('should fail with nonexistent id', () => { expect(() => { - token._unsafeTransferFrom( - Z_OWNER, - recipient, - NONEXISTENT_ID, - AMOUNT, - caller, - ); + token + .as(UNAUTHORIZED) + ._unsafeTransferFrom( + Z_OWNER, + recipient, + NONEXISTENT_ID, + AMOUNT, + ); }).toThrow('MultiToken: unauthorized operator'); }); it('should fail with transfer from zero', () => { - caller = ZERO; - expect(() => { - token._unsafeTransferFrom( - utils.ZERO_KEY, - recipient, - TOKEN_ID, - AMOUNT, - caller, - ); + token + .as(ZERO) + ._unsafeTransferFrom( + utils.ZERO_KEY, + recipient, + TOKEN_ID, + AMOUNT, + ); }).toThrow('MultiToken: invalid sender'); }); }); diff --git a/contracts/src/token/test/mocks/MockFungibleToken.compact b/contracts/src/token/test/mocks/MockFungibleToken.compact index 0bede13b..2b86c588 100644 --- a/contracts/src/token/test/mocks/MockFungibleToken.compact +++ b/contracts/src/token/test/mocks/MockFungibleToken.compact @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT -pragma language_version >= 0.18.0; +pragma language_version >= 0.21.0; import CompactStandardLibrary; @@ -62,19 +62,19 @@ export circuit _unsafeTransfer(to: Either, } export circuit transferFrom( - from: Either, + fromAddress: Either, to: Either, value: Uint<128> ): Boolean { - return FungibleToken_transferFrom(from, to, value); + return FungibleToken_transferFrom(fromAddress, to, value); } export circuit _unsafeTransferFrom( - from: Either, + fromAddress: Either, to: Either, value: Uint<128> ): Boolean { - return FungibleToken__unsafeTransferFrom(from, to, value); + return FungibleToken__unsafeTransferFrom(fromAddress, to, value); } export circuit approve(spender: Either, value: Uint<128>): Boolean { @@ -90,19 +90,19 @@ export circuit _approve( } export circuit _transfer( - from: Either, + fromAddress: Either, to: Either, value: Uint<128> ): [] { - return FungibleToken__transfer(from, to, value); + return FungibleToken__transfer(fromAddress, to, value); } export circuit _unsafeUncheckedTransfer( - from: Either, + fromAddress: Either, to: Either, value: Uint<128> ): [] { - return FungibleToken__unsafeUncheckedTransfer(from, to, value); + return FungibleToken__unsafeUncheckedTransfer(fromAddress, to, value); } export circuit _mint( diff --git a/contracts/src/token/test/mocks/MockMultiToken.compact b/contracts/src/token/test/mocks/MockMultiToken.compact index 94aa2b1a..37d89fd1 100644 --- a/contracts/src/token/test/mocks/MockMultiToken.compact +++ b/contracts/src/token/test/mocks/MockMultiToken.compact @@ -1,4 +1,4 @@ -pragma language_version >= 0.18.0; +pragma language_version >= 0.21.0; import CompactStandardLibrary; import "../../MultiToken" prefix MultiToken_; @@ -44,39 +44,39 @@ export circuit isApprovedForAll( } export circuit transferFrom( - from: Either, + fromAddress: Either, to: Either, id: Uint<128>, value: Uint<128> ): [] { - return MultiToken_transferFrom(from, to, id, value); + return MultiToken_transferFrom(fromAddress, to, id, value); } export circuit _unsafeTransferFrom( - from: Either, + fromAddress: Either, to: Either, id: Uint<128>, value: Uint<128> ): [] { - return MultiToken__unsafeTransferFrom(from, to, id, value); + return MultiToken__unsafeTransferFrom(fromAddress, to, id, value); } export circuit _transfer( - from: Either, + fromAddress: Either, to: Either, id: Uint<128>, value: Uint<128> ): [] { - return MultiToken__transfer(from, to, id, value); + return MultiToken__transfer(fromAddress, to, id, value); } export circuit _unsafeTransfer( - from: Either, + fromAddress: Either, to: Either, id: Uint<128>, value: Uint<128> ): [] { - return MultiToken__unsafeTransfer(from, to, id, value); + return MultiToken__unsafeTransfer(fromAddress, to, id, value); } export circuit _setURI(newURI: Opaque<"string">): [] { @@ -91,8 +91,8 @@ export circuit _unsafeMint(to: Either, id: return MultiToken__unsafeMint(to, id, value); } -export circuit _burn(from: Either, id: Uint<128>, value: Uint<128>): [] { - return MultiToken__burn(from, id, value); +export circuit _burn(fromAddress: Either, id: Uint<128>, value: Uint<128>): [] { + return MultiToken__burn(fromAddress, id, value); } export circuit _setApprovalForAll( diff --git a/contracts/src/token/test/mocks/MockNonFungibleToken.compact b/contracts/src/token/test/mocks/MockNonFungibleToken.compact index 287c7648..a7515486 100644 --- a/contracts/src/token/test/mocks/MockNonFungibleToken.compact +++ b/contracts/src/token/test/mocks/MockNonFungibleToken.compact @@ -1,4 +1,4 @@ -pragma language_version >= 0.18.0; +pragma language_version >= 0.21.0; import CompactStandardLibrary; @@ -68,11 +68,11 @@ export circuit isApprovedForAll( } export circuit transferFrom( - from: Either, + fromAddress: Either, to: Either, tokenId: Uint<128> ): [] { - return NonFungibleToken_transferFrom(from, to, tokenId); + return NonFungibleToken_transferFrom(fromAddress, to, tokenId); } export circuit _requireOwned(tokenId: Uint<128>): Either { @@ -131,11 +131,11 @@ export circuit _burn(tokenId: Uint<128>): [] { } export circuit _transfer( - from: Either, + fromAddress: Either, to: Either, tokenId: Uint<128> ): [] { - return NonFungibleToken__transfer(from, to, tokenId); + return NonFungibleToken__transfer(fromAddress, to, tokenId); } export circuit _setTokenURI(tokenId: Uint<128>, tokenURI: Opaque<"string">): [] { @@ -143,19 +143,19 @@ export circuit _setTokenURI(tokenId: Uint<128>, tokenURI: Opaque<"string">): [] } export circuit _unsafeTransferFrom( - from: Either, + fromAddress: Either, to: Either, tokenId: Uint<128> ): [] { - return NonFungibleToken__unsafeTransferFrom(from, to, tokenId); + return NonFungibleToken__unsafeTransferFrom(fromAddress, to, tokenId); } export circuit _unsafeTransfer( - from: Either, + fromAddress: Either, to: Either, tokenId: Uint<128> ): [] { - return NonFungibleToken__unsafeTransfer(from, to, tokenId); + return NonFungibleToken__unsafeTransfer(fromAddress, to, tokenId); } export circuit _unsafeMint( diff --git a/contracts/src/token/test/nonFungibleToken.test.ts b/contracts/src/token/test/nonFungibleToken.test.ts index d58ca060..7f8a5531 100644 --- a/contracts/src/token/test/nonFungibleToken.test.ts +++ b/contracts/src/token/test/nonFungibleToken.test.ts @@ -1,13 +1,11 @@ -import type { CoinPublicKey } from '@midnight-ntwrk/compact-runtime'; import { beforeEach, describe, expect, it } from 'vitest'; -import { NonFungibleTokenSimulator } from './simulators/NonFungibleTokenSimulator.js'; import { createEitherTestContractAddress, - createEitherTestUser, - toHexPadded, + generateEitherPubKeyPair, ZERO_ADDRESS, ZERO_KEY, -} from './utils/address.js'; +} from '#test-utils/address.js'; +import { NonFungibleTokenSimulator } from './simulators/NonFungibleTokenSimulator.js'; // Contract Metadata const NAME = 'NAME'; @@ -25,21 +23,17 @@ const SOME_URI = 'https://openzeppelin.example'; const EMPTY_URI = ''; const AMOUNT: bigint = BigInt(1); -// Callers -const OWNER = toHexPadded('OWNER'); -const SPENDER = toHexPadded('SPENDER'); -const UNAUTHORIZED = toHexPadded('UNAUTHORIZED'); - -// Encoded PK/Addresses -const Z_OWNER = createEitherTestUser('OWNER'); -const Z_SPENDER = createEitherTestUser('SPENDER'); -const Z_RECIPIENT = createEitherTestUser('RECIPIENT'); -const Z_OTHER = createEitherTestUser('OTHER'); -const Z_UNAUTHORIZED = createEitherTestUser('UNAUTHORIZED'); +// PKs +const [OWNER, Z_OWNER] = generateEitherPubKeyPair('OWNER'); +const [SPENDER, Z_SPENDER] = generateEitherPubKeyPair('SPENDER'); +const [UNAUTHORIZED, Z_UNAUTHORIZED] = generateEitherPubKeyPair('UNAUTHORIZED'); +const [, Z_RECIPIENT] = generateEitherPubKeyPair('RECIPIENT'); +const [, Z_OTHER] = generateEitherPubKeyPair('OTHER'); + +// Encoded contract addresses const SOME_CONTRACT = createEitherTestContractAddress('CONTRACT'); let token: NonFungibleTokenSimulator; -let _caller: CoinPublicKey; describe('NonFungibleToken', () => { describe('initializer and metadata', () => { @@ -223,65 +217,54 @@ describe('NonFungibleToken', () => { }); it('should throw if not owner', () => { - _caller = UNAUTHORIZED; expect(() => { - token.approve(Z_SPENDER, TOKENID_1, _caller); + token.as(UNAUTHORIZED).approve(Z_SPENDER, TOKENID_1); }).toThrow('NonFungibleToken: Invalid Approver'); }); it('should approve spender', () => { - _caller = OWNER; - token.approve(Z_SPENDER, TOKENID_1, _caller); + token.as(OWNER).approve(Z_SPENDER, TOKENID_1); expect(token.getApproved(TOKENID_1)).toEqual(Z_SPENDER); }); it('should allow operator to approve', () => { - _caller = OWNER; - token.setApprovalForAll(Z_SPENDER, true, _caller); - _caller = SPENDER; - token.approve(Z_OTHER, TOKENID_1, _caller); + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); + token.as(SPENDER).approve(Z_OTHER, TOKENID_1); expect(token.getApproved(TOKENID_1)).toEqual(Z_OTHER); }); it('spender approved for only TOKENID_1 should not be able to approve', () => { - _caller = OWNER; - token.approve(Z_SPENDER, TOKENID_1, _caller); + token.as(OWNER).approve(Z_SPENDER, TOKENID_1); - _caller = SPENDER; expect(() => { - token.approve(Z_OTHER, TOKENID_1, _caller); + token.as(SPENDER).approve(Z_OTHER, TOKENID_1); }).toThrow('NonFungibleToken: Invalid Approver'); }); it('should approve same address multiple times', () => { - _caller = OWNER; - token.approve(Z_SPENDER, TOKENID_1, _caller); - token.approve(Z_SPENDER, TOKENID_1, _caller); + token.as(OWNER).approve(Z_SPENDER, TOKENID_1); + token.as(OWNER).approve(Z_SPENDER, TOKENID_1); expect(token.getApproved(TOKENID_1)).toEqual(Z_SPENDER); }); it('should approve after token transfer', () => { - _caller = OWNER; token._transfer(Z_OWNER, Z_SPENDER, TOKENID_1); - _caller = SPENDER; - token.approve(Z_OTHER, TOKENID_1, _caller); + token.as(SPENDER).approve(Z_OTHER, TOKENID_1); expect(token.getApproved(TOKENID_1)).toEqual(Z_OTHER); }); it('should approve after token burn and remint', () => { - _caller = OWNER; token._burn(TOKENID_1); token._mint(Z_OWNER, TOKENID_1); - token.approve(Z_SPENDER, TOKENID_1, _caller); + token.as(OWNER).approve(Z_SPENDER, TOKENID_1); expect(token.getApproved(TOKENID_1)).toEqual(Z_SPENDER); }); it('should approve with very long token ID', () => { - _caller = OWNER; const longTokenId = BigInt('18446744073709551615'); token._mint(Z_OWNER, longTokenId); - token.approve(Z_SPENDER, longTokenId, _caller); + token.as(OWNER).approve(Z_SPENDER, longTokenId); expect(token.getApproved(longTokenId)).toEqual(Z_SPENDER); }); }); @@ -305,8 +288,7 @@ describe('NonFungibleToken', () => { }); it('should get current approved spender', () => { - _caller = OWNER; - token.approve(Z_OWNER, TOKENID_1, _caller); + token.as(OWNER).approve(Z_OWNER, TOKENID_1); expect(token.getApproved(TOKENID_1)).toEqual(Z_OWNER); }); @@ -317,18 +299,16 @@ describe('NonFungibleToken', () => { describe('setApprovalForAll', () => { it('should not approve zero address', () => { - _caller = OWNER; token._mint(Z_OWNER, TOKENID_1); expect(() => { - token.setApprovalForAll(ZERO_KEY, true, _caller); + token.as(OWNER).setApprovalForAll(ZERO_KEY, true); }).toThrow('NonFungibleToken: Invalid Operator'); }); it('should set operator', () => { - _caller = OWNER; token._mint(Z_OWNER, TOKENID_1); - token.setApprovalForAll(Z_SPENDER, true, OWNER); + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); }); @@ -336,67 +316,58 @@ describe('NonFungibleToken', () => { token._mint(Z_OWNER, TOKENID_1); token._mint(Z_OWNER, TOKENID_2); token._mint(Z_OWNER, TOKENID_3); - _caller = OWNER; - token.setApprovalForAll(Z_SPENDER, true, _caller); + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); - _caller = SPENDER; - token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); + token.as(SPENDER).transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1); expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); - token.approve(Z_OTHER, TOKENID_2, _caller); + token.approve(Z_OTHER, TOKENID_2); expect(token.getApproved(TOKENID_2)).toEqual(Z_OTHER); - token.approve(Z_SPENDER, TOKENID_3, _caller); + token.approve(Z_SPENDER, TOKENID_3); expect(token.getApproved(TOKENID_3)).toEqual(Z_SPENDER); }); it('should revoke approval for all', () => { - _caller = OWNER; token._mint(Z_OWNER, TOKENID_1); - token.setApprovalForAll(Z_SPENDER, true, _caller); + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); - token.setApprovalForAll(Z_SPENDER, false, _caller); + token.as(OWNER).setApprovalForAll(Z_SPENDER, false); expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(false); - _caller = SPENDER; expect(() => { - token.approve(Z_SPENDER, TOKENID_1, _caller); + token.as(SPENDER).approve(Z_SPENDER, TOKENID_1); }).toThrow('NonFungibleToken: Invalid Approver'); }); it('should set approval for all to same address multiple times', () => { - _caller = OWNER; token._mint(Z_OWNER, TOKENID_1); - token.setApprovalForAll(Z_SPENDER, true, _caller); - token.setApprovalForAll(Z_SPENDER, true, _caller); + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); }); it('should set approval for all after token transfer', () => { - _caller = OWNER; token._mint(Z_OWNER, TOKENID_1); token._transfer(Z_OWNER, Z_SPENDER, TOKENID_1); - _caller = SPENDER; - token.setApprovalForAll(Z_OTHER, true, _caller); + token.as(SPENDER).setApprovalForAll(Z_OTHER, true); expect(token.isApprovedForAll(Z_SPENDER, Z_OTHER)).toBe(true); }); it('should set approval for all with multiple operators', () => { - _caller = OWNER; token._mint(Z_OWNER, TOKENID_1); - token.setApprovalForAll(Z_SPENDER, true, _caller); - token.setApprovalForAll(Z_OTHER, true, _caller); + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); + token.as(OWNER).setApprovalForAll(Z_OTHER, true); expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); expect(token.isApprovedForAll(Z_OWNER, Z_OTHER)).toBe(true); }); it('should set approval for all with very long token IDs', () => { - _caller = OWNER; const longTokenId = BigInt('18446744073709551615'); token._mint(Z_OWNER, longTokenId); - token.setApprovalForAll(Z_SPENDER, true, _caller); + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); }); }); @@ -407,9 +378,8 @@ describe('NonFungibleToken', () => { }); it('should return true if approval set', () => { - _caller = OWNER; token._mint(Z_OWNER, TOKENID_1); - token.setApprovalForAll(Z_SPENDER, true, OWNER); + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); }); }); @@ -438,50 +408,42 @@ describe('NonFungibleToken', () => { }); it('should not transfer from unauthorized', () => { - _caller = UNAUTHORIZED; expect(() => { - token.transferFrom(Z_OWNER, Z_UNAUTHORIZED, TOKENID_1, _caller); + token.as(UNAUTHORIZED).transferFrom(Z_OWNER, Z_UNAUTHORIZED, TOKENID_1); }).toThrow('NonFungibleToken: Insufficient Approval'); }); it('should not transfer token that has not been minted', () => { - _caller = OWNER; expect(() => { - token.transferFrom(Z_OWNER, Z_SPENDER, NON_EXISTENT_TOKEN, _caller); + token.as(OWNER).transferFrom(Z_OWNER, Z_SPENDER, NON_EXISTENT_TOKEN); }).toThrow('NonFungibleToken: Nonexistent Token'); }); it('should transfer token without approvers or operators', () => { - _caller = OWNER; - token.transferFrom(Z_OWNER, Z_RECIPIENT, TOKENID_1, _caller); + token.as(OWNER).transferFrom(Z_OWNER, Z_RECIPIENT, TOKENID_1); expect(token.ownerOf(TOKENID_1)).toEqual(Z_RECIPIENT); }); it('should transfer token via approved operator', () => { - _caller = OWNER; - token.approve(Z_SPENDER, TOKENID_1, OWNER); + token.as(OWNER).approve(Z_SPENDER, TOKENID_1); - _caller = SPENDER; - token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); + token.as(SPENDER).transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1); expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); }); it('should transfer token via approvedForAll operator', () => { - _caller = OWNER; - token.setApprovalForAll(Z_SPENDER, true, OWNER); + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); - _caller = SPENDER; - token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); + token.as(SPENDER).transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1); expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); }); it('should allow transfer to same address', () => { - _caller = OWNER; token._approve(Z_SPENDER, TOKENID_1, Z_OWNER); token._setApprovalForAll(Z_OWNER, Z_SPENDER, true); expect(() => { - token.transferFrom(Z_OWNER, Z_OWNER, TOKENID_1, _caller); + token.as(OWNER).transferFrom(Z_OWNER, Z_OWNER, TOKENID_1); }).not.toThrow(); expect(token.ownerOf(TOKENID_1)).toEqual(Z_OWNER); expect(token.balanceOf(Z_OWNER)).toEqual(1n); @@ -490,40 +452,35 @@ describe('NonFungibleToken', () => { }); it('should not transfer after approval revocation', () => { - _caller = OWNER; - token.approve(Z_SPENDER, TOKENID_1, _caller); - token.approve(ZERO_KEY, TOKENID_1, _caller); + token.as(OWNER).approve(Z_SPENDER, TOKENID_1); + token.as(OWNER).approve(ZERO_KEY, TOKENID_1); - _caller = SPENDER; expect(() => { - token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); + token.as(SPENDER).transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1); }).toThrow('NonFungibleToken: Insufficient Approval'); }); it('should not transfer after approval for all revocation', () => { - _caller = OWNER; - token.setApprovalForAll(Z_SPENDER, true, _caller); - token.setApprovalForAll(Z_SPENDER, false, _caller); + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); + token.as(OWNER).setApprovalForAll(Z_SPENDER, false); - _caller = SPENDER; expect(() => { - token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); + token.as(SPENDER).transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1); }).toThrow('NonFungibleToken: Insufficient Approval'); }); it('should transfer multiple tokens in sequence', () => { - _caller = OWNER; token._mint(Z_OWNER, TOKENID_2); token._mint(Z_OWNER, TOKENID_3); - token.approve(Z_SPENDER, TOKENID_1, _caller); - token.approve(Z_SPENDER, TOKENID_2, _caller); - token.approve(Z_SPENDER, TOKENID_3, _caller); + token.as(OWNER).approve(Z_SPENDER, TOKENID_1); + token.as(OWNER).approve(Z_SPENDER, TOKENID_2); + token.as(OWNER).approve(Z_SPENDER, TOKENID_3); - _caller = SPENDER; - token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); - token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_2, _caller); - token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_3, _caller); + token.setPersistentCaller(SPENDER); + token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_1); + token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_2); + token.transferFrom(Z_OWNER, Z_SPENDER, TOKENID_3); expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); expect(token.ownerOf(TOKENID_2)).toEqual(Z_SPENDER); @@ -531,31 +488,27 @@ describe('NonFungibleToken', () => { }); it('should transfer with very long token IDs', () => { - _caller = OWNER; const longTokenId = BigInt('18446744073709551615'); token._mint(Z_OWNER, longTokenId); - token.approve(Z_SPENDER, longTokenId, _caller); + token.as(OWNER).approve(Z_SPENDER, longTokenId); - _caller = SPENDER; - token.transferFrom(Z_OWNER, Z_SPENDER, longTokenId, _caller); + token.as(SPENDER).transferFrom(Z_OWNER, Z_SPENDER, longTokenId); expect(token.ownerOf(longTokenId)).toEqual(Z_SPENDER); }); it('should revoke approval after transferFrom', () => { - _caller = OWNER; - token.approve(Z_SPENDER, TOKENID_1, _caller); + token.as(OWNER).approve(Z_SPENDER, TOKENID_1); token._setApprovalForAll(Z_OWNER, Z_SPENDER, true); - token.transferFrom(Z_OWNER, Z_OTHER, TOKENID_1, _caller); + token.as(OWNER).transferFrom(Z_OWNER, Z_OTHER, TOKENID_1); expect(token.getApproved(TOKENID_1)).toEqual(ZERO_KEY); expect(token._isAuthorized(Z_OTHER, Z_SPENDER, TOKENID_1)).toBe(false); - _caller = SPENDER; expect(() => { - token.approve(Z_UNAUTHORIZED, TOKENID_1, _caller); + token.as(SPENDER).approve(Z_UNAUTHORIZED, TOKENID_1); }).toThrow('NonFungibleToken: Invalid Approver'); expect(() => { - token.transferFrom(Z_OTHER, Z_UNAUTHORIZED, TOKENID_1, _caller); + token.as(SPENDER).transferFrom(Z_OTHER, Z_UNAUTHORIZED, TOKENID_1); }).toThrow('NonFungibleToken: Insufficient Approval'); }); }); @@ -600,9 +553,8 @@ describe('NonFungibleToken', () => { }); it('should approve if auth is approved for all', () => { - _caller = OWNER; token._mint(Z_OWNER, TOKENID_1); - token.setApprovalForAll(Z_SPENDER, true, _caller); + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); token._approve(Z_SPENDER, TOKENID_1, Z_SPENDER); expect(token.getApproved(TOKENID_1)).toEqual(Z_SPENDER); }); @@ -637,15 +589,13 @@ describe('NonFungibleToken', () => { it('should not throw if approved', () => { token._mint(Z_OWNER, TOKENID_1); - _caller = OWNER; - token.approve(Z_SPENDER, TOKENID_1, _caller); + token.as(OWNER).approve(Z_SPENDER, TOKENID_1); token._checkAuthorized(Z_OWNER, Z_SPENDER, TOKENID_1); }); it('should not throw if approvedForAll', () => { token._mint(Z_OWNER, TOKENID_1); - _caller = OWNER; - token.setApprovalForAll(Z_SPENDER, true, _caller); + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); token._checkAuthorized(Z_OWNER, Z_SPENDER, TOKENID_1); }); }); @@ -656,14 +606,12 @@ describe('NonFungibleToken', () => { }); it('should return true if spender is authorized', () => { - _caller = OWNER; - token.approve(Z_SPENDER, TOKENID_1, _caller); + token.as(OWNER).approve(Z_SPENDER, TOKENID_1); expect(token._isAuthorized(Z_OWNER, Z_SPENDER, TOKENID_1)).toBe(true); }); it('should return true if spender is authorized for all', () => { - _caller = OWNER; - token.setApprovalForAll(Z_SPENDER, true, _caller); + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); expect(token._isAuthorized(Z_OWNER, Z_SPENDER, TOKENID_1)).toBe(true); }); @@ -692,8 +640,7 @@ describe('NonFungibleToken', () => { }); it('should return approved address', () => { - _caller = OWNER; - token.approve(Z_SPENDER, TOKENID_1, _caller); + token.as(OWNER).approve(Z_SPENDER, TOKENID_1); expect(token._getApproved(TOKENID_1)).toEqual(Z_SPENDER); }); @@ -710,9 +657,8 @@ describe('NonFungibleToken', () => { }); it('should revoke operator approval', () => { - _caller = OWNER; token._mint(Z_OWNER, TOKENID_1); - token.setApprovalForAll(Z_SPENDER, true, _caller); + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); expect(token.isApprovedForAll(Z_OWNER, Z_SPENDER)).toBe(true); token._setApprovalForAll(Z_OWNER, Z_SPENDER, false); @@ -803,8 +749,7 @@ describe('NonFungibleToken', () => { }); it('should clear approval when token is burned', () => { - _caller = OWNER; - token.approve(Z_SPENDER, TOKENID_1, _caller); + token.as(OWNER).approve(Z_SPENDER, TOKENID_1); expect(token.getApproved(TOKENID_1)).toEqual(Z_SPENDER); token._burn(TOKENID_1); @@ -835,8 +780,7 @@ describe('NonFungibleToken', () => { }); it('should burn after approval', () => { - _caller = OWNER; - token.approve(Z_SPENDER, TOKENID_1, _caller); + token.as(OWNER).approve(Z_SPENDER, TOKENID_1); token._burn(TOKENID_1); expect(token._ownerOf(TOKENID_1)).toEqual(ZERO_KEY); expect(token._getApproved(TOKENID_1)).toEqual(ZERO_KEY); @@ -883,9 +827,8 @@ describe('NonFungibleToken', () => { }); it('should revoke approval after _transfer', () => { - _caller = OWNER; token._mint(Z_OWNER, TOKENID_1); - token.approve(Z_SPENDER, TOKENID_1, _caller); + token.as(OWNER).approve(Z_SPENDER, TOKENID_1); token._transfer(Z_OWNER, Z_OTHER, TOKENID_1); expect(token.getApproved(TOKENID_1)).toEqual(ZERO_KEY); }); @@ -985,8 +928,7 @@ describe('NonFungibleToken', () => { }); it('should revoke approval after _unsafeTransfer', () => { - _caller = OWNER; - token.approve(Z_SPENDER, TOKENID_1, _caller); + token.as(OWNER).approve(Z_SPENDER, TOKENID_1); token._unsafeTransfer(Z_OWNER, Z_OTHER, TOKENID_1); expect(token.getApproved(TOKENID_1)).toEqual(ZERO_KEY); }); @@ -1024,64 +966,52 @@ describe('NonFungibleToken', () => { }); it('unapproved operator should not transfer', () => { - _caller = SPENDER; expect(() => { - token._unsafeTransferFrom(Z_OWNER, Z_UNAUTHORIZED, TOKENID_1, _caller); + token + .as(SPENDER) + ._unsafeTransferFrom(Z_OWNER, Z_UNAUTHORIZED, TOKENID_1); }).toThrow('NonFungibleToken: Insufficient Approval'); }); it('should not transfer token that has not been minted', () => { - _caller = OWNER; expect(() => { - token._unsafeTransferFrom( - Z_OWNER, - Z_SPENDER, - NON_EXISTENT_TOKEN, - _caller, - ); + token + .as(OWNER) + ._unsafeTransferFrom(Z_OWNER, Z_SPENDER, NON_EXISTENT_TOKEN); }).toThrow('NonFungibleToken: Nonexistent Token'); }); it('should transfer token to spender via approved operator', () => { - _caller = OWNER; - token.approve(Z_SPENDER, TOKENID_1, OWNER); + token.as(OWNER).approve(Z_SPENDER, TOKENID_1); - _caller = SPENDER; - token._unsafeTransferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); + token.as(SPENDER)._unsafeTransferFrom(Z_OWNER, Z_SPENDER, TOKENID_1); expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); }); it('should transfer token to ContractAddress via approved operator', () => { - _caller = OWNER; - token.approve(Z_SPENDER, TOKENID_1, OWNER); + token.as(OWNER).approve(Z_SPENDER, TOKENID_1); - _caller = SPENDER; - token._unsafeTransferFrom(Z_OWNER, SOME_CONTRACT, TOKENID_1, _caller); + token.as(SPENDER)._unsafeTransferFrom(Z_OWNER, SOME_CONTRACT, TOKENID_1); expect(token.ownerOf(TOKENID_1)).toEqual(SOME_CONTRACT); }); it('should transfer token to spender via approvedForAll operator', () => { - _caller = OWNER; - token.setApprovalForAll(Z_SPENDER, true, OWNER); + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); - _caller = SPENDER; - token._unsafeTransferFrom(Z_OWNER, Z_SPENDER, TOKENID_1, _caller); + token.as(SPENDER)._unsafeTransferFrom(Z_OWNER, Z_SPENDER, TOKENID_1); expect(token.ownerOf(TOKENID_1)).toEqual(Z_SPENDER); }); it('should transfer token to ContractAddress via approvedForAll operator', () => { - _caller = OWNER; - token.setApprovalForAll(Z_SPENDER, true, OWNER); + token.as(OWNER).setApprovalForAll(Z_SPENDER, true); - _caller = SPENDER; - token._unsafeTransferFrom(Z_OWNER, SOME_CONTRACT, TOKENID_1, _caller); + token.as(SPENDER)._unsafeTransferFrom(Z_OWNER, SOME_CONTRACT, TOKENID_1); expect(token.ownerOf(TOKENID_1)).toEqual(SOME_CONTRACT); }); it('should revoke approval after _unsafeTransferFrom', () => { - _caller = OWNER; - token.approve(Z_SPENDER, TOKENID_1, _caller); - token._unsafeTransferFrom(Z_OWNER, Z_OTHER, TOKENID_1, _caller); + token.as(OWNER).approve(Z_SPENDER, TOKENID_1); + token.as(OWNER)._unsafeTransferFrom(Z_OWNER, Z_OTHER, TOKENID_1); expect(token.getApproved(TOKENID_1)).toEqual(ZERO_KEY); }); }); diff --git a/contracts/src/token/test/simulators/FungibleTokenSimulator.ts b/contracts/src/token/test/simulators/FungibleTokenSimulator.ts index 992199b0..54dda0e0 100644 --- a/contracts/src/token/test/simulators/FungibleTokenSimulator.ts +++ b/contracts/src/token/test/simulators/FungibleTokenSimulator.ts @@ -1,103 +1,71 @@ import { - type CircuitContext, - type CoinPublicKey, - type ContractState, - constructorContext, - emptyZswapLocalState, - QueryContext, -} from '@midnight-ntwrk/compact-runtime'; -import { sampleContractAddress } from '@midnight-ntwrk/zswap'; + type BaseSimulatorOptions, + createSimulator, +} from '@openzeppelin-compact/contracts-simulator'; import { type ContractAddress, type Either, - type Ledger, ledger, Contract as MockFungibleToken, type ZswapCoinPublicKey, -} from '../../../../artifacts/MockFungibleToken/contract/index.cjs'; // Combined imports +} from '../../../../artifacts/MockFungibleToken/contract/index.js'; import { - type FungibleTokenPrivateState, + FungibleTokenPrivateState, FungibleTokenWitnesses, } from '../../witnesses/FungibleTokenWitnesses.js'; -import type { IContractSimulator } from '../types/test.js'; /** - * @description A simulator implementation of a FungibleToken contract for testing purposes. - * @template P - The private state type, fixed to FungibleTokenPrivateState. - * @template L - The ledger type, fixed to Contract.Ledger. + * Type constructor args */ -export class FungibleTokenSimulator - implements IContractSimulator -{ - /** @description The underlying contract instance managing contract logic. */ - readonly contract: MockFungibleToken; +type FungibleTokenArgs = readonly [ + name: string, + symbol: string, + decimals: bigint, + init: boolean, +]; - /** @description The deployed address of the contract. */ - readonly contractAddress: string; +const FungibleTokenSimulatorBase = createSimulator< + FungibleTokenPrivateState, + ReturnType, + ReturnType, + MockFungibleToken, + FungibleTokenArgs +>({ + contractFactory: (witnesses) => + new MockFungibleToken(witnesses), + defaultPrivateState: () => FungibleTokenPrivateState, + contractArgs: (name, symbol, decimals, init) => [ + name, + symbol, + decimals, + init, + ], + ledgerExtractor: (state) => ledger(state), + witnessesFactory: () => FungibleTokenWitnesses(), +}); - /** @description The current circuit context, updated by contract operations. */ - circuitContext: CircuitContext; - - /** - * @description Initializes the mock contract. - */ - constructor(name: string, symbol: string, decimals: bigint, init: boolean) { - this.contract = new MockFungibleToken( - FungibleTokenWitnesses, - ); - const { - currentPrivateState, - currentContractState, - currentZswapLocalState, - } = this.contract.initialState( - constructorContext({}, '0'.repeat(64)), - name, - symbol, - decimals, - init, - ); - this.circuitContext = { - currentPrivateState, - currentZswapLocalState, - originalState: currentContractState, - transactionContext: new QueryContext( - currentContractState.data, - sampleContractAddress(), - ), - }; - this.contractAddress = this.circuitContext.transactionContext.address; - } - - /** - * @description Retrieves the current public ledger state of the contract. - * @returns The ledger state as defined by the contract. - */ - public getCurrentPublicState(): Ledger { - return ledger(this.circuitContext.transactionContext.state); - } - - /** - * @description Retrieves the current private state of the contract. - * @returns The private state of type FungibleTokenPrivateState. - */ - public getCurrentPrivateState(): FungibleTokenPrivateState { - return this.circuitContext.currentPrivateState; - } - - /** - * @description Retrieves the current contract state. - * @returns The contract state object. - */ - public getCurrentContractState(): ContractState { - return this.circuitContext.originalState; +/** + * FungibleToken Simulator + */ +export class FungibleTokenSimulator extends FungibleTokenSimulatorBase { + constructor( + name: string, + symbol: string, + decimals: bigint, + init: boolean, + options: BaseSimulatorOptions< + FungibleTokenPrivateState, + ReturnType + > = {}, + ) { + super([name, symbol, decimals, init], options); } - /** * @description Returns the token name. * @returns The token name. */ public name(): string { - return this.contract.impureCircuits.name(this.circuitContext).result; + return this.circuits.impure.name(); } /** @@ -105,7 +73,7 @@ export class FungibleTokenSimulator * @returns The token name. */ public symbol(): string { - return this.contract.impureCircuits.symbol(this.circuitContext).result; + return this.circuits.impure.symbol(); } /** @@ -113,7 +81,7 @@ export class FungibleTokenSimulator * @returns The account's token balance. */ public decimals(): bigint { - return this.contract.impureCircuits.decimals(this.circuitContext).result; + return this.circuits.impure.decimals(); } /** @@ -121,7 +89,7 @@ export class FungibleTokenSimulator * @returns The total supply of tokens. */ public totalSupply(): bigint { - return this.contract.impureCircuits.totalSupply(this.circuitContext).result; + return this.circuits.impure.totalSupply(); } /** @@ -132,8 +100,7 @@ export class FungibleTokenSimulator public balanceOf( account: Either, ): bigint { - return this.contract.impureCircuits.balanceOf(this.circuitContext, account) - .result; + return this.circuits.impure.balanceOf(account); } /** @@ -147,153 +114,77 @@ export class FungibleTokenSimulator owner: Either, spender: Either, ): bigint { - return this.contract.impureCircuits.allowance( - this.circuitContext, - owner, - spender, - ).result; + return this.circuits.impure.allowance(owner, spender); } /** * @description Moves a `value` amount of tokens from the caller's account to `to`. * @param to The recipient of the transfer, either a user or a contract. * @param value The amount to transfer. - * @param sender The simulated caller. * @returns As per the IERC20 spec, this MUST return true. */ public transfer( to: Either, value: bigint, - sender?: CoinPublicKey, ): boolean { - const res = this.contract.impureCircuits.transfer( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - to, - value, - ); - - this.circuitContext = res.context; - return res.result; + return this.circuits.impure.transfer(to, value); } /** * @description Unsafe variant of `transfer` which allows transfers to contract addresses. * @param to The recipient of the transfer, either a user or a contract. * @param value The amount to transfer. - * @param sender The simulated caller. * @returns As per the IERC20 spec, this MUST return true. */ public _unsafeTransfer( to: Either, value: bigint, - sender?: CoinPublicKey, ): boolean { - const res = this.contract.impureCircuits._unsafeTransfer( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - to, - value, - ); - - this.circuitContext = res.context; - return res.result; + return this.circuits.impure._unsafeTransfer(to, value); } /** * @description Moves `value` tokens from `from` to `to` using the allowance mechanism. * `value` is the deducted from the caller's allowance. - * @param from The current owner of the tokens for the transfer, either a user or a contract. + * @param fromAddress The current owner of the tokens for the transfer, either a user or a contract. * @param to The recipient of the transfer, either a user or a contract. * @param value The amount to transfer. - * @param sender The simulated caller. * @returns As per the IERC20 spec, this MUST return true. */ public transferFrom( - from: Either, + fromAddress: Either, to: Either, value: bigint, - sender?: CoinPublicKey, ): boolean { - const res = this.contract.impureCircuits.transferFrom( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - from, - to, - value, - ); - - this.circuitContext = res.context; - return res.result; + return this.circuits.impure.transferFrom(fromAddress, to, value); } /** * @description Unsafe variant of `transferFrom` which allows transfers to contract addresses. - * @param from The current owner of the tokens for the transfer, either a user or a contract. + * @param fromAddress The current owner of the tokens for the transfer, either a user or a contract. * @param to The recipient of the transfer, either a user or a contract. * @param value The amount to transfer. - * @param sender The simulated caller. * @returns As per the IERC20 spec, this MUST return true. */ public _unsafeTransferFrom( - from: Either, + fromAddress: Either, to: Either, value: bigint, - sender?: CoinPublicKey, ): boolean { - const res = this.contract.impureCircuits._unsafeTransferFrom( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - from, - to, - value, - ); - - this.circuitContext = res.context; - return res.result; + return this.circuits.impure._unsafeTransferFrom(fromAddress, to, value); } /** * @description Sets a `value` amount of tokens as allowance of `spender` over the caller's tokens. * @param spender The Zswap key or ContractAddress that may spend on behalf of the caller. * @param value The amount of tokens the `spender` may spend. - * @param sender The simulated caller. * @returns Returns a boolean value indicating whether the operation succeeded. */ public approve( spender: Either, value: bigint, - sender?: CoinPublicKey, ): boolean { - const res = this.contract.impureCircuits.approve( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - spender, - value, - ); - - this.circuitContext = res.context; - return res.result; + return this.circuits.impure.approve(spender, value); } /// @@ -304,40 +195,30 @@ export class FungibleTokenSimulator * @description Moves a `value` amount of tokens from `from` to `to`. * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. - * @param from The owner of the tokens to transfer. + * @param fromAddress The owner of the tokens to transfer. * @param to The receipient of the transferred tokens. * @param value The amount of tokens to transfer. */ public _transfer( - from: Either, + fromAddress: Either, to: Either, value: bigint, ) { - this.circuitContext = this.contract.impureCircuits._transfer( - this.circuitContext, - from, - to, - value, - ).context; + this.circuits.impure._transfer(fromAddress, to, value); } /** * @description Unsafe variant of `_transfer` which allows transfers to contract addresses. - * @param from The owner of the tokens to transfer. + * @param fromAddress The owner of the tokens to transfer. * @param to The receipient of the transferred tokens. * @param value The amount of tokens to transfer. */ public _unsafeUncheckedTransfer( - from: Either, + fromAddress: Either, to: Either, value: bigint, ) { - this.circuitContext = this.contract.impureCircuits._unsafeUncheckedTransfer( - this.circuitContext, - from, - to, - value, - ).context; + this.circuits.impure._unsafeUncheckedTransfer(fromAddress, to, value); } /** @@ -350,11 +231,7 @@ export class FungibleTokenSimulator account: Either, value: bigint, ) { - this.circuitContext = this.contract.impureCircuits._mint( - this.circuitContext, - account, - value, - ).context; + this.circuits.impure._mint(account, value); } /** @@ -366,11 +243,7 @@ export class FungibleTokenSimulator account: Either, value: bigint, ) { - this.circuitContext = this.contract.impureCircuits._unsafeMint( - this.circuitContext, - account, - value, - ).context; + this.circuits.impure._unsafeMint(account, value); } /** @@ -383,11 +256,7 @@ export class FungibleTokenSimulator account: Either, value: bigint, ) { - this.circuitContext = this.contract.impureCircuits._burn( - this.circuitContext, - account, - value, - ).context; + this.circuits.impure._burn(account, value); } /** @@ -403,12 +272,7 @@ export class FungibleTokenSimulator spender: Either, value: bigint, ) { - this.circuitContext = this.contract.impureCircuits._approve( - this.circuitContext, - owner, - spender, - value, - ).context; + this.circuits.impure._approve(owner, spender, value); } /** @@ -423,11 +287,6 @@ export class FungibleTokenSimulator spender: Either, value: bigint, ) { - this.circuitContext = this.contract.impureCircuits._spendAllowance( - this.circuitContext, - owner, - spender, - value, - ).context; + this.circuits.impure._spendAllowance(owner, spender, value); } } diff --git a/contracts/src/token/test/simulators/MultiTokenSimulator.ts b/contracts/src/token/test/simulators/MultiTokenSimulator.ts index 34b559ee..324a797b 100644 --- a/contracts/src/token/test/simulators/MultiTokenSimulator.ts +++ b/contracts/src/token/test/simulators/MultiTokenSimulator.ts @@ -1,91 +1,52 @@ import { - type CircuitContext, - type CoinPublicKey, - type ContractState, - constructorContext, - emptyZswapLocalState, - QueryContext, -} from '@midnight-ntwrk/compact-runtime'; -import { sampleContractAddress } from '@midnight-ntwrk/zswap'; + type BaseSimulatorOptions, + createSimulator, +} from '@openzeppelin-compact/contracts-simulator'; import { type ContractAddress, type Either, - type Ledger, ledger, type Maybe, Contract as MockMultiToken, type ZswapCoinPublicKey, -} from '../../../../artifacts/MockMultiToken/contract/index.cjs'; // Combined imports +} from '../../../../artifacts/MockMultiToken/contract/index.js'; import { - type MultiTokenPrivateState, + MultiTokenPrivateState, MultiTokenWitnesses, } from '../../witnesses/MultiTokenWitnesses.js'; -import type { IContractSimulator } from '../types/test.js'; /** - * @description A simulator implementation of a MultiToken contract for testing purposes. - * @template P - The private state type, fixed to MultiTokenPrivateState. - * @template L - The ledger type, fixed to Contract.Ledger. + * Type constructor args */ -export class MultiTokenSimulator - implements IContractSimulator -{ - /** @description The underlying contract instance managing contract logic. */ - readonly contract: MockMultiToken; +type MultiTokenArgs = readonly [_uri: Maybe]; + +const MultiTokenSimulatorBase = createSimulator< + MultiTokenPrivateState, + ReturnType, + ReturnType, + MockMultiToken, + MultiTokenArgs +>({ + contractFactory: (witnesses) => + new MockMultiToken(witnesses), + defaultPrivateState: () => MultiTokenPrivateState, + contractArgs: (_uri) => [_uri], + ledgerExtractor: (state) => ledger(state), + witnessesFactory: () => MultiTokenWitnesses(), +}); - /** @description The deployed address of the contract. */ - readonly contractAddress: string; - - /** @description The current circuit context, updated by contract operations. */ - circuitContext: CircuitContext; - - /** - * @description Initializes the mock contract if `uri` is provided. - * If `uri` is none, the contract will not initialize (for testing). - */ - constructor(uri: Maybe) { - this.contract = new MockMultiToken( - MultiTokenWitnesses, - ); - const { - currentPrivateState, - currentContractState, - currentZswapLocalState, - } = this.contract.initialState(constructorContext({}, '0'.repeat(64)), uri); - this.circuitContext = { - currentPrivateState, - currentZswapLocalState, - originalState: currentContractState, - transactionContext: new QueryContext( - currentContractState.data, - sampleContractAddress(), - ), - }; - this.contractAddress = this.circuitContext.transactionContext.address; - } - - /** - * @description Retrieves the current public ledger state of the contract. - * @returns The ledger state as defined by the contract. - */ - public getCurrentPublicState(): Ledger { - return ledger(this.circuitContext.transactionContext.state); - } - - /** - * @description Retrieves the current private state of the contract. - * @returns The private state of type MultiTokenPrivateState. - */ - public getCurrentPrivateState(): MultiTokenPrivateState { - return this.circuitContext.currentPrivateState; - } - - /** - * @description Retrieves the current contract state. - * @returns The contract state object. - */ - public getCurrentContractState(): ContractState { - return this.circuitContext.originalState; +/** + * MultiToken Simulator + */ +export class MultiTokenSimulator extends MultiTokenSimulatorBase { + constructor( + _uri: Maybe, + options: BaseSimulatorOptions< + MultiTokenPrivateState, + ReturnType + > = {}, + ) { + super([_uri], options); } /** @@ -94,10 +55,7 @@ export class MultiTokenSimulator * @param uri The base URI for all token URIs. */ public initialize(uri: string) { - this.circuitContext = this.contract.impureCircuits.initialize( - this.circuitContext, - uri, - ).context; + this.circuits.impure.initialize(uri); } /** @@ -106,7 +64,7 @@ export class MultiTokenSimulator * @returns The token URI. */ public uri(id: bigint): string { - return this.contract.impureCircuits.uri(this.circuitContext, id).result; + return this.circuits.impure.uri(id); } /** @@ -119,11 +77,7 @@ export class MultiTokenSimulator account: Either, id: bigint, ): bigint { - return this.contract.impureCircuits.balanceOf( - this.circuitContext, - account, - id, - ).result; + return this.circuits.impure.balanceOf(account, id); } /** @@ -131,23 +85,12 @@ export class MultiTokenSimulator * @param operator The ZswapCoinPublicKey or ContractAddress whose approval is set for the caller's assets. * @param approved The boolean value determining if the operator may or may not handle the * caller's assets. - * @param sender - Optional. Sets the caller context if provided. */ public setApprovalForAll( operator: Either, approved: boolean, - sender?: CoinPublicKey, ) { - this.circuitContext = this.contract.impureCircuits.setApprovalForAll( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - operator, - approved, - ).context; + this.circuits.impure.setApprovalForAll(operator, approved); } /** @@ -160,133 +103,77 @@ export class MultiTokenSimulator account: Either, operator: Either, ): boolean { - return this.contract.impureCircuits.isApprovedForAll( - this.circuitContext, - account, - operator, - ).result; + return this.circuits.impure.isApprovedForAll(account, operator); } /** - * @description Transfers ownership of `value` amount of `id` tokens from `from` to `to`. - * The caller must be `from` or approved to transfer on their behalf. - * @param from The owner from which the transfer originates. + * @description Transfers ownership of `value` amount of `id` tokens from `fromAddress` to `to`. + * The caller must be `fromAddress` or approved to transfer on their behalf. + * @param fromAddress The owner from which the transfer originates. * @param to The recipient of the transferred assets. * @param id The unique identifier of the asset type. * @param value The quantity of `id` tokens to transfer. - * @param sender - Optional. Sets the caller context if provided. */ public transferFrom( - from: Either, + fromAddress: Either, to: Either, id: bigint, value: bigint, - sender?: CoinPublicKey, ) { - this.circuitContext = this.contract.impureCircuits.transferFrom( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - from, - to, - id, - value, - ).context; + this.circuits.impure.transferFrom(fromAddress, to, id, value); } /** * @description Unsafe variant of `transferFrom` which allows transfers to contract addresses. - * The caller must be `from` or approved to transfer on their behalf. - * @param from The owner from which the transfer originates. + * The caller must be `fromAddress` or approved to transfer on their behalf. + * @param fromAddress The owner from which the transfer originates. * @param to The recipient of the transferred assets. * @param id The unique identifier of the asset type. * @param value The quantity of `id` tokens to transfer. - * @param sender - Optional. Sets the caller context if provided. */ public _unsafeTransferFrom( - from: Either, + fromAddress: Either, to: Either, id: bigint, value: bigint, - sender?: CoinPublicKey, ) { - this.circuitContext = this.contract.impureCircuits._unsafeTransferFrom( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - from, - to, - id, - value, - ).context; + this.circuits.impure._unsafeTransferFrom(fromAddress, to, id, value); } /** - * @description Transfers ownership of `value` amount of `id` tokens from `from` to `to`. + * @description Transfers ownership of `value` amount of `id` tokens from `fromAddress` to `to`. * Does not impose restrictions on the caller, making it suitable for composition * in higher-level contract logic. - * @param from The owner from which the transfer originates. + * @param fromAddress The owner from which the transfer originates. * @param to The recipient of the transferred assets. * @param id The unique identifier of the asset type. * @param value The quantity of `id` tokens to transfer. - * @param sender - Optional. Sets the caller context if provided. */ public _transfer( - from: Either, + fromAddress: Either, to: Either, id: bigint, value: bigint, - sender?: CoinPublicKey, ) { - this.circuitContext = this.contract.impureCircuits._transfer( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - from, - to, - id, - value, - ).context; + this.circuits.impure._transfer(fromAddress, to, id, value); } /** * @description Unsafe variant of `_transfer` which allows transfers to contract addresses. * Does not impose restrictions on the caller, making it suitable as a low-level * building block for advanced contract logic. - * @param from The owner from which the transfer originates. + * @param fromAddress The owner from which the transfer originates. * @param to The recipient of the transferred assets. * @param id The unique identifier of the asset type. * @param value The quantity of `id` tokens to transfer. - * @param sender - Optional. Sets the caller context if provided. */ public _unsafeTransfer( - from: Either, + fromAddress: Either, to: Either, id: bigint, value: bigint, - sender?: CoinPublicKey, ) { - this.circuitContext = this.contract.impureCircuits._unsafeTransfer( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - from, - to, - id, - value, - ).context; + this.circuits.impure._unsafeTransfer(fromAddress, to, id, value); } /** @@ -294,10 +181,7 @@ export class MultiTokenSimulator * @param newURI The new base URI for all tokens. */ public _setURI(newURI: string) { - this.circuitContext = this.contract.impureCircuits._setURI( - this.circuitContext, - newURI, - ).context; + this.circuits.impure._setURI(newURI); } /** @@ -311,12 +195,7 @@ export class MultiTokenSimulator id: bigint, value: bigint, ) { - this.circuitContext = this.contract.impureCircuits._mint( - this.circuitContext, - to, - id, - value, - ).context; + this.circuits.impure._mint(to, id, value); } /** @@ -330,31 +209,21 @@ export class MultiTokenSimulator id: bigint, value: bigint, ) { - this.circuitContext = this.contract.impureCircuits._unsafeMint( - this.circuitContext, - to, - id, - value, - ).context; + this.circuits.impure._unsafeMint(to, id, value); } /** - * @description Destroys a `value` amount of tokens of type `token_id` from `from`. - * @param from The owner whose tokens will be destroyed. + * @description Destroys a `value` amount of tokens of type `token_id` from `fromAddress`. + * @param fromAddress The owner whose tokens will be destroyed. * @param id The unique identifier of the token type. - * @param value The quantity of `id` tokens that will be destroyed from `from`. + * @param value The quantity of `id` tokens that will be destroyed from `fromAddress` */ public _burn( - from: Either, + fromAddress: Either, id: bigint, value: bigint, ) { - this.circuitContext = this.contract.impureCircuits._burn( - this.circuitContext, - from, - id, - value, - ).context; + this.circuits.impure._burn(fromAddress, id, value); } /** @@ -364,24 +233,12 @@ export class MultiTokenSimulator * `owner`'s assets. * @param approved The boolean value determining if the operator may or may not handle the * `owner`'s assets. - * @param sender - Optional. Sets the caller context if provided. */ public _setApprovalForAll( owner: Either, operator: Either, approved: boolean, - sender?: CoinPublicKey, ) { - this.circuitContext = this.contract.impureCircuits._setApprovalForAll( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - owner, - operator, - approved, - ).context; + this.circuits.impure._setApprovalForAll(owner, operator, approved); } } diff --git a/contracts/src/token/test/simulators/NonFungibleTokenSimulator.ts b/contracts/src/token/test/simulators/NonFungibleTokenSimulator.ts index ae2627cb..ef311599 100644 --- a/contracts/src/token/test/simulators/NonFungibleTokenSimulator.ts +++ b/contracts/src/token/test/simulators/NonFungibleTokenSimulator.ts @@ -1,94 +1,57 @@ import { - type CircuitContext, - type CoinPublicKey, - type ContractState, - constructorContext, - emptyZswapLocalState, - QueryContext, -} from '@midnight-ntwrk/compact-runtime'; -import { sampleContractAddress } from '@midnight-ntwrk/zswap'; + type BaseSimulatorOptions, + createSimulator, +} from '@openzeppelin-compact/contracts-simulator'; import { type ContractAddress, type Either, - type Ledger, ledger, Contract as MockNonFungibleToken, type ZswapCoinPublicKey, -} from '../../../../artifacts/MockNonFungibleToken/contract/index.cjs'; // Combined imports +} from '../../../../artifacts/MockNonFungibleToken/contract/index.js'; import { - type NonFungibleTokenPrivateState, + NonFungibleTokenPrivateState, NonFungibleTokenWitnesses, } from '../../witnesses/NonFungibleTokenWitnesses.js'; -import type { IContractSimulator } from '../types/test.js'; /** - * @description A simulator implementation of an nonFungibleToken contract for testing purposes. - * @template P - The private state type, fixed to NonFungibleTokenPrivateState. - * @template L - The ledger type, fixed to Contract.Ledger. + * Type constructor args */ -export class NonFungibleTokenSimulator - implements IContractSimulator -{ - /** @description The underlying contract instance managing contract logic. */ - readonly contract: MockNonFungibleToken; +type NonFungibleTokenArgs = readonly [ + name: string, + symbol: string, + init: boolean, +]; + +const NonFungibleTokenSimulatorBase = createSimulator< + NonFungibleTokenPrivateState, + ReturnType, + ReturnType, + MockNonFungibleToken, + NonFungibleTokenArgs +>({ + contractFactory: (witnesses) => + new MockNonFungibleToken(witnesses), + defaultPrivateState: () => NonFungibleTokenPrivateState, + contractArgs: (name, symbol, init) => [name, symbol, init], + ledgerExtractor: (state) => ledger(state), + witnessesFactory: () => NonFungibleTokenWitnesses(), +}); - /** @description The deployed address of the contract. */ - readonly contractAddress: string; - - /** @description The current circuit context, updated by contract operations. */ - circuitContext: CircuitContext; - - /** - * @description Initializes the mock contract. - */ - constructor(name: string, symbol: string, init: boolean) { - this.contract = new MockNonFungibleToken( - NonFungibleTokenWitnesses, - ); - const { - currentPrivateState, - currentContractState, - currentZswapLocalState, - } = this.contract.initialState( - constructorContext({}, '0'.repeat(64)), - name, - symbol, - init, - ); - this.circuitContext = { - currentPrivateState, - currentZswapLocalState, - originalState: currentContractState, - transactionContext: new QueryContext( - currentContractState.data, - sampleContractAddress(), - ), - }; - this.contractAddress = this.circuitContext.transactionContext.address; - } - - /** - * @description Retrieves the current public ledger state of the contract. - * @returns The ledger state as defined by the contract. - */ - public getCurrentPublicState(): Ledger { - return ledger(this.circuitContext.transactionContext.state); - } - - /** - * @description Retrieves the current private state of the contract. - * @returns The private state of type NonFungibleTokenPrivateState. - */ - public getCurrentPrivateState(): NonFungibleTokenPrivateState { - return this.circuitContext.currentPrivateState; - } - - /** - * @description Retrieves the current contract state. - * @returns The contract state object. - */ - public getCurrentContractState(): ContractState { - return this.circuitContext.originalState; +/** + * NonFungibleToken Simulator + */ +export class NonFungibleTokenSimulator extends NonFungibleTokenSimulatorBase { + constructor( + name: string, + symbol: string, + init: boolean, + options: BaseSimulatorOptions< + NonFungibleTokenPrivateState, + ReturnType + > = {}, + ) { + super([name, symbol, init], options); } /** @@ -96,15 +59,15 @@ export class NonFungibleTokenSimulator * @returns The token name. */ public name(): string { - return this.contract.impureCircuits.name(this.circuitContext).result; + return this.circuits.impure.name(); } /** * @description Returns the symbol of the token. - * @returns The token name. + * @returns The token symbol. */ public symbol(): string { - return this.contract.impureCircuits.symbol(this.circuitContext).result; + return this.circuits.impure.symbol(); } /** @@ -115,8 +78,7 @@ export class NonFungibleTokenSimulator public balanceOf( account: Either, ): bigint { - return this.contract.impureCircuits.balanceOf(this.circuitContext, account) - .result; + return this.circuits.impure.balanceOf(account); } /** @@ -125,8 +87,7 @@ export class NonFungibleTokenSimulator * @return The public key that owns the token. */ public ownerOf(tokenId: bigint): Either { - return this.contract.impureCircuits.ownerOf(this.circuitContext, tokenId) - .result; + return this.circuits.impure.ownerOf(tokenId); } /** @@ -140,8 +101,7 @@ export class NonFungibleTokenSimulator * @returns The token id's URI. */ public tokenURI(tokenId: bigint): string { - return this.contract.impureCircuits.tokenURI(this.circuitContext, tokenId) - .result; + return this.circuits.impure.tokenURI(tokenId); } /** @@ -161,20 +121,8 @@ export class NonFungibleTokenSimulator public approve( to: Either, tokenId: bigint, - sender?: CoinPublicKey, ) { - const res = this.contract.impureCircuits.approve( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - to, - tokenId, - ); - - this.circuitContext = res.context; + this.circuits.impure.approve(to, tokenId); } /** @@ -185,10 +133,7 @@ export class NonFungibleTokenSimulator public getApproved( tokenId: bigint, ): Either { - return this.contract.impureCircuits.getApproved( - this.circuitContext, - tokenId, - ).result; + return this.circuits.impure.getApproved(tokenId); } /** @@ -205,20 +150,8 @@ export class NonFungibleTokenSimulator public setApprovalForAll( operator: Either, approved: boolean, - sender?: CoinPublicKey, ) { - const res = this.contract.impureCircuits.setApprovalForAll( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - operator, - approved, - ); - - this.circuitContext = res.context; + this.circuits.impure.setApprovalForAll(operator, approved); } /** @@ -232,46 +165,29 @@ export class NonFungibleTokenSimulator owner: Either, operator: Either, ): boolean { - return this.contract.impureCircuits.isApprovedForAll( - this.circuitContext, - owner, - operator, - ).result; + return this.circuits.impure.isApprovedForAll(owner, operator); } /** - * @description Transfers `tokenId` token from `from` to `to`. + * @description Transfers `tokenId` token from `fromAddress` to `to`. * * Requirements: * - * - `from` cannot be the zero address. + * - `fromAddress` cannot be the zero address. * - `to` cannot be the zero address. - * - `tokenId` token must be owned by `from`. - * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - `tokenId` token must be owned by `fromAddress`. + * - If the caller is not `fromAddress`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - * @param {Either} from - The source account from which the token is being transfered + * @param {Either} fromAddress - The source account from which the token is being transfered * @param {Either} to - The target account to transfer token to * @param {TokenId} tokenId - The token being transfered */ public transferFrom( - from: Either, + fromAddress: Either, to: Either, tokenId: bigint, - sender?: CoinPublicKey, ) { - const res = this.contract.impureCircuits.transferFrom( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - from, - to, - tokenId, - ); - - this.circuitContext = res.context; + this.circuits.impure.transferFrom(fromAddress, to, tokenId); } /** @@ -286,10 +202,7 @@ export class NonFungibleTokenSimulator public _requireOwned( tokenId: bigint, ): Either { - return this.contract.impureCircuits._requireOwned( - this.circuitContext, - tokenId, - ).result; + return this.circuits.impure._requireOwned(tokenId); } /** @@ -301,8 +214,7 @@ export class NonFungibleTokenSimulator public _ownerOf( tokenId: bigint, ): Either { - return this.contract.impureCircuits._ownerOf(this.circuitContext, tokenId) - .result; + return this.circuits.impure._ownerOf(tokenId); } /** @@ -320,12 +232,7 @@ export class NonFungibleTokenSimulator tokenId: bigint, auth: Either, ) { - this.circuitContext = this.contract.impureCircuits._approve( - this.circuitContext, - to, - tokenId, - auth, - ).context; + this.circuits.impure._approve(to, tokenId, auth); } /** @@ -346,12 +253,7 @@ export class NonFungibleTokenSimulator spender: Either, tokenId: bigint, ) { - this.circuitContext = this.contract.impureCircuits._checkAuthorized( - this.circuitContext, - owner, - spender, - tokenId, - ).context; + return this.circuits.impure._checkAuthorized(owner, spender, tokenId); } /** @@ -371,12 +273,7 @@ export class NonFungibleTokenSimulator spender: Either, tokenId: bigint, ): boolean { - return this.contract.impureCircuits._isAuthorized( - this.circuitContext, - owner, - spender, - tokenId, - ).result; + return this.circuits.impure._isAuthorized(owner, spender, tokenId); } /** @@ -388,10 +285,7 @@ export class NonFungibleTokenSimulator public _getApproved( tokenId: bigint, ): Either { - return this.contract.impureCircuits._getApproved( - this.circuitContext, - tokenId, - ).result; + return this.circuits.impure._getApproved(tokenId); } /** @@ -410,12 +304,7 @@ export class NonFungibleTokenSimulator operator: Either, approved: boolean, ) { - this.circuitContext = this.contract.impureCircuits._setApprovalForAll( - this.circuitContext, - owner, - operator, - approved, - ).context; + this.circuits.impure._setApprovalForAll(owner, operator, approved); } /** @@ -433,11 +322,7 @@ export class NonFungibleTokenSimulator to: Either, tokenId: bigint, ) { - this.circuitContext = this.contract.impureCircuits._mint( - this.circuitContext, - to, - tokenId, - ).context; + this.circuits.impure._mint(to, tokenId); } /** @@ -452,36 +337,28 @@ export class NonFungibleTokenSimulator * @param tokenId The token to burn */ public _burn(tokenId: bigint) { - this.circuitContext = this.contract.impureCircuits._burn( - this.circuitContext, - tokenId, - ).context; + this.circuits.impure._burn(tokenId); } /** - * @description Transfers `tokenId` from `from` to `to`. + * @description Transfers `tokenId` from `fromAddress` to `to`. * As opposed to {transferFrom}, this imposes no restrictions on ownPublicKey(). * * Requirements: * * - `to` cannot be the zero address. - * - `tokenId` token must be owned by `from`. + * - `tokenId` token must be owned by `fromAddress`. * - * @param from The source account of the token transfer + * @param fromAddress The source account of the token transfer * @param to The target account of the token transfer * @param tokenId The token to transfer */ public _transfer( - from: Either, + fromAddress: Either, to: Either, tokenId: bigint, ) { - this.circuitContext = this.contract.impureCircuits._transfer( - this.circuitContext, - from, - to, - tokenId, - ).context; + this.circuits.impure._transfer(fromAddress, to, tokenId); } /** @@ -494,15 +371,11 @@ export class NonFungibleTokenSimulator * @param tokenURI The URI of `tokenId`. */ public _setTokenURI(tokenId: bigint, tokenURI: string) { - this.circuitContext = this.contract.impureCircuits._setTokenURI( - this.circuitContext, - tokenId, - tokenURI, - ).context; + this.circuits.impure._setTokenURI(tokenId, tokenURI); } /** - * @description Transfers `tokenId` token from `from` to `to`. It does NOT check if the recipient is a ContractAddress. + * @description Transfers `tokenId` token from `fromAddress` to `to`. It does NOT check if the recipient is a ContractAddress. * * @notice External smart contracts cannot call the token contract at this time, so any transfers to external contracts * may result in a permanent loss of the token. All transfers to external contracts will be permanently "stuck" at the @@ -510,38 +383,25 @@ export class NonFungibleTokenSimulator * * Requirements: * - * - `from` cannot be the zero address. + * - `fromAddress` cannot be the zero address. * - `to` cannot be the zero address. - * - `tokenId` token must be owned by `from`. - * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}. + * - `tokenId` token must be owned by `fromAddress`. + * - If the caller is not `fromAddress`, it must be approved to move this token by either {approve} or {setApprovalForAll}. * - * @param {Either} from - The source account from which the token is being transfered + * @param {Either} fromAddress - The source account from which the token is being transfered * @param {Either} to - The target account to transfer token to * @param {TokenId} tokenId - The token being transfered */ public _unsafeTransferFrom( - from: Either, + fromAddress: Either, to: Either, tokenId: bigint, - sender?: CoinPublicKey, ) { - const res = this.contract.impureCircuits._unsafeTransferFrom( - { - ...this.circuitContext, - currentZswapLocalState: sender - ? emptyZswapLocalState(sender) - : this.circuitContext.currentZswapLocalState, - }, - from, - to, - tokenId, - ); - - this.circuitContext = res.context; + this.circuits.impure._unsafeTransferFrom(fromAddress, to, tokenId); } /** - * @description Transfers `tokenId` from `from` to `to`. + * @description Transfers `tokenId` from `fromAddress` to `to`. * As opposed to {_unsafeTransferFrom}, this imposes no restrictions on ownPublicKey(). * It does NOT check if the recipient is a ContractAddress. * @@ -552,23 +412,18 @@ export class NonFungibleTokenSimulator * Requirements: * * - `to` cannot be the zero address. - * - `tokenId` token must be owned by `from`. + * - `tokenId` token must be owned by `fromAddress`. * - * @param {Either} from - The source account of the token transfer + * @param {Either} fromAddress - The source account of the token transfer * @param {Either} to - The target account of the token transfer * @param {TokenId} tokenId - The token to transfer */ public _unsafeTransfer( - from: Either, + fromAddress: Either, to: Either, tokenId: bigint, ) { - this.circuitContext = this.contract.impureCircuits._unsafeTransfer( - this.circuitContext, - from, - to, - tokenId, - ).context; + this.circuits.impure._unsafeTransfer(fromAddress, to, tokenId); } /** @@ -590,10 +445,6 @@ export class NonFungibleTokenSimulator to: Either, tokenId: bigint, ) { - this.circuitContext = this.contract.impureCircuits._unsafeMint( - this.circuitContext, - to, - tokenId, - ).context; + this.circuits.impure._unsafeMint(to, tokenId); } } diff --git a/contracts/src/token/test/types/test.ts b/contracts/src/token/test/types/test.ts deleted file mode 100644 index 7a909543..00000000 --- a/contracts/src/token/test/types/test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { - CircuitContext, - ContractState, -} from '@midnight-ntwrk/compact-runtime'; - -/** - * Generic interface for mock contract implementations. - * @template P - The type of the contract's private state. - * @template L - The type of the contract's ledger (public state). - */ -export interface IContractSimulator { - /** The contract's deployed address. */ - readonly contractAddress: string; - - /** The current circuit context. */ - circuitContext: CircuitContext

; - - /** Retrieves the current ledger state. */ - getCurrentPublicState(): L; - - /** Retrieves the current private state. */ - getCurrentPrivateState(): P; - - /** Retrieves the current contract state. */ - getCurrentContractState(): ContractState; -} diff --git a/contracts/src/token/test/utils/address.ts b/contracts/src/token/test/utils/address.ts deleted file mode 100644 index a2bcd69c..00000000 --- a/contracts/src/token/test/utils/address.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { - convertFieldToBytes, - encodeCoinPublicKey, -} from '@midnight-ntwrk/compact-runtime'; -import { encodeContractAddress } from '@midnight-ntwrk/ledger'; -import type * as Compact from '../../../../artifacts/MockFungibleToken/contract/index.cjs'; - -const PREFIX_ADDRESS = '0200'; - -/** - * @description Converts an ASCII string to its hexadecimal representation, - * left-padded with zeros to a specified length. Useful for generating - * fixed-size hex strings for encoding. - * @param str ASCII string to convert. - * @param len Total desired length of the resulting hex string. Defaults to 64. - * @returns Hexadecimal string representation of `str`, padded to `length` characters. - */ -export const toHexPadded = (str: string, len = 64) => - Buffer.from(str, 'ascii').toString('hex').padStart(len, '0'); - -/** - * @description Generates ZswapCoinPublicKey from `str` for testing purposes. - * @param str String to hexify and encode. - * @returns Encoded `ZswapCoinPublicKey`. - */ -export const encodeToPK = (str: string): Compact.ZswapCoinPublicKey => ({ - bytes: encodeCoinPublicKey(toHexPadded(str)), -}); - -/** - * @description Generates ContractAddress from `str` for testing purposes. - * Prepends 32-byte hex with PREFIX_ADDRESS before encoding. - * @param str String to hexify and encode. - * @returns Encoded `ZswapCoinPublicKey`. - */ -export const encodeToAddress = (str: string): Compact.ContractAddress => ({ - bytes: encodeContractAddress(PREFIX_ADDRESS + toHexPadded(str)), -}); - -/** - * @description Generates an Either object for ZswapCoinPublicKey for testing. - * For use when an Either argument is expected. - * @param str String to hexify and encode. - * @returns Defined Either object for ZswapCoinPublicKey. - */ -export const createEitherTestUser = (str: string) => ({ - is_left: true, - left: encodeToPK(str), - right: encodeToAddress(''), -}); - -/** - * @description Generates an Either object for ContractAddress for testing. - * For use when an Either argument is expected. - * @param str String to hexify and encode. - * @returns Defined Either object for ContractAddress. - */ -export const createEitherTestContractAddress = (str: string) => ({ - is_left: false, - left: encodeToPK(''), - right: encodeToAddress(str), -}); - -export const zeroUint8Array = (length = 32) => - convertFieldToBytes(length, 0n, ''); - -export const ZERO_KEY = { - is_left: true, - left: { bytes: zeroUint8Array() }, - right: encodeToAddress(''), -}; - -export const ZERO_ADDRESS = { - is_left: false, - left: encodeToPK(''), - right: { bytes: zeroUint8Array() }, -}; diff --git a/contracts/src/token/witnesses/FungibleTokenWitnesses.ts b/contracts/src/token/witnesses/FungibleTokenWitnesses.ts index 86607738..613bf98a 100644 --- a/contracts/src/token/witnesses/FungibleTokenWitnesses.ts +++ b/contracts/src/token/witnesses/FungibleTokenWitnesses.ts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Compact Contracts v0.0.1-alpha.1 (token/witnesses/FungibleTokenWitnesses.ts) -// This is how we type an empty object. export type FungibleTokenPrivateState = Record; -export const FungibleTokenWitnesses = {}; +export const FungibleTokenPrivateState: FungibleTokenPrivateState = {}; +export const FungibleTokenWitnesses = () => ({}); diff --git a/contracts/src/token/witnesses/MultiTokenWitnesses.ts b/contracts/src/token/witnesses/MultiTokenWitnesses.ts index 1ba0331c..20bfddbc 100644 --- a/contracts/src/token/witnesses/MultiTokenWitnesses.ts +++ b/contracts/src/token/witnesses/MultiTokenWitnesses.ts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Compact Contracts v0.0.1-alpha.1 (token/witnesses/MultiTokenWitnesses.ts) -// This is how we type an empty object. export type MultiTokenPrivateState = Record; -export const MultiTokenWitnesses = {}; +export const MultiTokenPrivateState: MultiTokenPrivateState = {}; +export const MultiTokenWitnesses = () => ({}); diff --git a/contracts/src/token/witnesses/NonFungibleTokenWitnesses.ts b/contracts/src/token/witnesses/NonFungibleTokenWitnesses.ts index 5fec649e..9e229c03 100644 --- a/contracts/src/token/witnesses/NonFungibleTokenWitnesses.ts +++ b/contracts/src/token/witnesses/NonFungibleTokenWitnesses.ts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Compact Contracts v0.0.1-alpha.1 (token/witnesses/NonFungibleToken.ts) -// This is how we type an empty object. export type NonFungibleTokenPrivateState = Record; -export const NonFungibleTokenWitnesses = {}; +export const NonFungibleTokenPrivateState: NonFungibleTokenPrivateState = {}; +export const NonFungibleTokenWitnesses = () => ({}); diff --git a/contracts/src/utils/Utils.compact b/contracts/src/utils/Utils.compact index 42980f39..8e4342e3 100644 --- a/contracts/src/utils/Utils.compact +++ b/contracts/src/utils/Utils.compact @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Compact Contracts v0.0.1-alpha.1 (utils/Utils.compact) -pragma language_version >= 0.18.0; +pragma language_version >= 0.21.0; /** * @module Utils. @@ -19,10 +19,12 @@ module Utils { * @param {Either} keyOrAddress - The target value to check, either a ZswapCoinPublicKey or a ContractAddress. * @return {Boolean} - Returns true if `keyOrAddress` is zero. */ - export pure circuit isKeyOrAddressZero(keyOrAddress: Either): Boolean { + export pure circuit isKeyOrAddressZero( + keyOrAddress: Either + ): Boolean { return isContractAddress(keyOrAddress) - ? default == keyOrAddress.right - : default == keyOrAddress.left; + ? default == keyOrAddress.right + : default == keyOrAddress.left; } /** @@ -45,9 +47,9 @@ module Utils { * @return {Boolean} - Returns true if `keyOrAddress` is is equal to `other`. */ export pure circuit isKeyOrAddressEqual( - keyOrAddress: Either, - other: Either - ): Boolean { + keyOrAddress: Either, + other: Either + ): Boolean { if (keyOrAddress.is_left && other.is_left) { return keyOrAddress.left == other.left; } else if (!keyOrAddress.is_left && !other.is_left) { @@ -63,7 +65,9 @@ module Utils { * @param {Either} keyOrAddress - The target value to check, either a ZswapCoinPublicKey or a ContractAddress. * @return {Boolean} - Returns true if `keyOrAddress` is a ContractAddress. */ - export pure circuit isContractAddress(keyOrAddress: Either): Boolean { + export pure circuit isContractAddress( + keyOrAddress: Either + ): Boolean { return !keyOrAddress.is_left; } diff --git a/contracts/src/utils/test/mocks/MockUtils.compact b/contracts/src/utils/test/mocks/MockUtils.compact index 3f28649b..3f13ffac 100644 --- a/contracts/src/utils/test/mocks/MockUtils.compact +++ b/contracts/src/utils/test/mocks/MockUtils.compact @@ -1,4 +1,4 @@ -pragma language_version >= 0.18.0; +pragma language_version >= 0.21.0; import CompactStandardLibrary; diff --git a/contracts/src/utils/test/simulators/UtilsSimulator.ts b/contracts/src/utils/test/simulators/UtilsSimulator.ts index 715569f8..9a26cebc 100644 --- a/contracts/src/utils/test/simulators/UtilsSimulator.ts +++ b/contracts/src/utils/test/simulators/UtilsSimulator.ts @@ -1,85 +1,49 @@ import { - type CircuitContext, - type ContractState, - constructorContext, - QueryContext, -} from '@midnight-ntwrk/compact-runtime'; -import { sampleContractAddress } from '@midnight-ntwrk/zswap'; + type BaseSimulatorOptions, + createSimulator, +} from '@openzeppelin-compact/contracts-simulator'; import { type ContractAddress, type Either, - type Ledger, ledger, Contract as MockUtils, type ZswapCoinPublicKey, -} from '../../../../artifacts/MockUtils/contract/index.cjs'; // Combined imports +} from '../../../../artifacts/MockUtils/contract/index.js'; import { - type UtilsPrivateState, + UtilsPrivateState, UtilsWitnesses, } from '../../witnesses/UtilsWitnesses.js'; -import type { IContractSimulator } from '../types/test.js'; /** - * @description A simulator implementation of an utils contract for testing purposes. - * @template P - The private state type, fixed to UtilsPrivateState. - * @template L - The ledger type, fixed to Contract.Ledger. + * Type constructor args */ -export class UtilsSimulator - implements IContractSimulator -{ - /** @description The underlying contract instance managing contract logic. */ - readonly contract: MockUtils; +type UtilsArgs = readonly []; - /** @description The deployed address of the contract. */ - readonly contractAddress: string; +const UtilsSimulatorBase = createSimulator< + UtilsPrivateState, + ReturnType, + ReturnType, + MockUtils, + UtilsArgs +>({ + contractFactory: (witnesses) => new MockUtils(witnesses), + defaultPrivateState: () => UtilsPrivateState, + contractArgs: () => [], + ledgerExtractor: (state) => ledger(state), + witnessesFactory: () => UtilsWitnesses(), +}); - /** @description The current circuit context, updated by contract operations. */ - circuitContext: CircuitContext; - - /** - * @description Initializes the mock contract. - */ - constructor() { - this.contract = new MockUtils(UtilsWitnesses); - const { - currentPrivateState, - currentContractState, - currentZswapLocalState, - } = this.contract.initialState(constructorContext({}, '0'.repeat(64))); - this.circuitContext = { - currentPrivateState, - currentZswapLocalState, - originalState: currentContractState, - transactionContext: new QueryContext( - currentContractState.data, - sampleContractAddress(), - ), - }; - this.contractAddress = this.circuitContext.transactionContext.address; - } - - /** - * @description Retrieves the current public ledger state of the contract. - * @returns The ledger state as defined by the contract. - */ - public getCurrentPublicState(): Ledger { - return ledger(this.circuitContext.transactionContext.state); - } - - /** - * @description Retrieves the current private state of the contract. - * @returns The private state of type UtilsPrivateState. - */ - public getCurrentPrivateState(): UtilsPrivateState { - return this.circuitContext.currentPrivateState; - } - - /** - * @description Retrieves the current contract state. - * @returns The contract state object. - */ - public getCurrentContractState(): ContractState { - return this.circuitContext.originalState; +/** + * Utils Simulator + */ +export class UtilsSimulator extends UtilsSimulatorBase { + constructor( + options: BaseSimulatorOptions< + UtilsPrivateState, + ReturnType + > = {}, + ) { + super([], options); } /** @@ -90,10 +54,7 @@ export class UtilsSimulator public isKeyOrAddressZero( keyOrAddress: Either, ): boolean { - return this.contract.circuits.isKeyOrAddressZero( - this.circuitContext, - keyOrAddress, - ).result; + return this.circuits.pure.isKeyOrAddressZero(keyOrAddress); } /** @@ -109,11 +70,7 @@ export class UtilsSimulator keyOrAddress: Either, other: Either, ): boolean { - return this.contract.circuits.isKeyOrAddressEqual( - this.circuitContext, - keyOrAddress, - other, - ).result; + return this.circuits.pure.isKeyOrAddressEqual(keyOrAddress, other); } /** @@ -122,7 +79,7 @@ export class UtilsSimulator * @returns Returns true if `key` is zero. */ public isKeyZero(key: ZswapCoinPublicKey): boolean { - return this.contract.circuits.isKeyZero(this.circuitContext, key).result; + return this.circuits.pure.isKeyZero(key); } /** @@ -133,10 +90,7 @@ export class UtilsSimulator public isContractAddress( keyOrAddress: Either, ): boolean { - return this.contract.circuits.isContractAddress( - this.circuitContext, - keyOrAddress, - ).result; + return this.circuits.pure.isContractAddress(keyOrAddress); } /** @@ -144,6 +98,6 @@ export class UtilsSimulator * @returns The empty string: "" */ public emptyString(): string { - return this.contract.circuits.emptyString(this.circuitContext).result; + return this.circuits.pure.emptyString(); } } diff --git a/contracts/src/utils/test/types/test.ts b/contracts/src/utils/test/types/test.ts deleted file mode 100644 index 7a909543..00000000 --- a/contracts/src/utils/test/types/test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import type { - CircuitContext, - ContractState, -} from '@midnight-ntwrk/compact-runtime'; - -/** - * Generic interface for mock contract implementations. - * @template P - The type of the contract's private state. - * @template L - The type of the contract's ledger (public state). - */ -export interface IContractSimulator { - /** The contract's deployed address. */ - readonly contractAddress: string; - - /** The current circuit context. */ - circuitContext: CircuitContext

; - - /** Retrieves the current ledger state. */ - getCurrentPublicState(): L; - - /** Retrieves the current private state. */ - getCurrentPrivateState(): P; - - /** Retrieves the current contract state. */ - getCurrentContractState(): ContractState; -} diff --git a/contracts/src/utils/test/utils.test.ts b/contracts/src/utils/test/utils.test.ts index 0d768441..163c7d1a 100644 --- a/contracts/src/utils/test/utils.test.ts +++ b/contracts/src/utils/test/utils.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; +import * as contractUtils from '#test-utils/address.js'; import { UtilsSimulator } from './simulators/UtilsSimulator.js'; -import * as contractUtils from './utils/address.js'; const Z_SOME_KEY = contractUtils.createEitherTestUser('SOME_KEY'); const Z_OTHER_KEY = contractUtils.createEitherTestUser('OTHER_KEY'); diff --git a/contracts/src/utils/test/utils/address.ts b/contracts/src/utils/test/utils/address.ts deleted file mode 100644 index ae55f943..00000000 --- a/contracts/src/utils/test/utils/address.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { - convertFieldToBytes, - encodeCoinPublicKey, -} from '@midnight-ntwrk/compact-runtime'; -import { encodeContractAddress } from '@midnight-ntwrk/ledger'; -import type * as Compact from '../../../../artifacts/MockUtils/contract/index.cjs'; - -const PREFIX_ADDRESS = '0200'; - -/** - * @description Converts an ASCII string to its hexadecimal representation, - * left-padded with zeros to a specified length. Useful for generating - * fixed-size hex strings for encoding. - * @param str ASCII string to convert. - * @param len Total desired length of the resulting hex string. Defaults to 64. - * @returns Hexadecimal string representation of `str`, padded to `length` characters. - */ -export const toHexPadded = (str: string, len = 64) => - Buffer.from(str, 'ascii').toString('hex').padStart(len, '0'); - -/** - * @description Generates ZswapCoinPublicKey from `str` for testing purposes. - * @param str String to hexify and encode. - * @returns Encoded `ZswapCoinPublicKey`. - */ -export const encodeToPK = (str: string): Compact.ZswapCoinPublicKey => { - const toHex = Buffer.from(str, 'ascii').toString('hex'); - return { bytes: encodeCoinPublicKey(String(toHex).padStart(64, '0')) }; -}; - -/** - * @description Generates ContractAddress from `str` for testing purposes. - * Prepends 32-byte hex with PREFIX_ADDRESS before encoding. - * @param str String to hexify and encode. - * @returns Encoded `ZswapCoinPublicKey`. - */ -export const encodeToAddress = (str: string): Compact.ContractAddress => { - const toHex = Buffer.from(str, 'ascii').toString('hex'); - const fullAddress = PREFIX_ADDRESS + String(toHex).padStart(64, '0'); - return { bytes: encodeContractAddress(fullAddress) }; -}; - -/** - * @description Generates an Either object for ZswapCoinPublicKey for testing. - * For use when an Either argument is expected. - * @param str String to hexify and encode. - * @returns Defined Either object for ZswapCoinPublicKey. - */ -export const createEitherTestUser = (str: string) => { - return { - is_left: true, - left: encodeToPK(str), - right: encodeToAddress(''), - }; -}; - -/** - * @description Generates an Either object for ContractAddress for testing. - * For use when an Either argument is expected. - * @param str String to hexify and encode. - * @returns Defined Either object for ContractAddress. - */ -export const createEitherTestContractAddress = (str: string) => { - return { - is_left: false, - left: encodeToPK(''), - right: encodeToAddress(str), - }; -}; - -export const ZERO_KEY = { - is_left: true, - left: { bytes: convertFieldToBytes(32, 0n, '') }, - right: encodeToAddress(''), -}; - -export const ZERO_ADDRESS = { - is_left: false, - left: encodeToPK(''), - right: { bytes: convertFieldToBytes(32, 0n, '') }, -}; diff --git a/contracts/src/utils/test/utils/test.ts b/contracts/src/utils/test/utils/test.ts deleted file mode 100644 index 2fd5a504..00000000 --- a/contracts/src/utils/test/utils/test.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { - type CircuitContext, - type CoinPublicKey, - type ContractAddress, - type ContractState, - emptyZswapLocalState, - QueryContext, -} from '@midnight-ntwrk/compact-runtime'; -import type { IContractSimulator } from '../types/test.js'; - -/** - * Constructs a `CircuitContext` from the given state and sender information. - * - * This is typically used at runtime to provide the necessary context - * for executing circuits, including contract state, private state, - * sender identity, and transaction data. - * - * @template P - The type of the contract's private state. - * @param privateState - The current private state of the contract. - * @param contractState - The full contract state, including public and private data. - * @param sender - The public key of the sender (used in the circuit). - * @param contractAddress - The address of the deployed contract. - * @returns A fully populated `CircuitContext` for circuit execution. - * @todo TODO: Move this utility to a generic package for broader reuse across contracts. - */ -export function useCircuitContext

( - privateState: P, - contractState: ContractState, - sender: CoinPublicKey, - contractAddress: ContractAddress, -): CircuitContext

{ - return { - originalState: contractState, - currentPrivateState: privateState, - transactionContext: new QueryContext(contractState.data, contractAddress), - currentZswapLocalState: emptyZswapLocalState(sender), - }; -} - -/** - * Prepares a new `CircuitContext` using the given sender and contract. - * - * Useful for mocking or updating the circuit context with a custom sender. - * - * @template P - The type of the contract's private state. - * @template L - The type of the contract's ledger (public state). - * @template C - The specific type of the contract implementing `MockContract`. - * @param contract - The contract instance implementing `MockContract`. - * @param sender - The public key to set as the sender in the new circuit context. - * @returns A new `CircuitContext` with the sender and updated context values. - * @todo TODO: Move this utility to a generic package for broader reuse across contracts. - */ -export function useCircuitContextSender< - P, - L, - C extends IContractSimulator, ->(contract: C, sender: CoinPublicKey): CircuitContext

{ - const currentPrivateState = contract.getCurrentPrivateState(); - const originalState = contract.getCurrentContractState(); - const contractAddress = contract.contractAddress; - - return { - originalState, - currentPrivateState, - transactionContext: new QueryContext(originalState.data, contractAddress), - currentZswapLocalState: emptyZswapLocalState(sender), - }; -} diff --git a/contracts/src/utils/witnesses/UtilsWitnesses.ts b/contracts/src/utils/witnesses/UtilsWitnesses.ts index e8b27877..5c5bfa11 100644 --- a/contracts/src/utils/witnesses/UtilsWitnesses.ts +++ b/contracts/src/utils/witnesses/UtilsWitnesses.ts @@ -1,6 +1,6 @@ // SPDX-License-Identifier: MIT // OpenZeppelin Compact Contracts v0.0.1-alpha.1 (utils/witnesses/UtilsWitnesses.ts) -// This is how we type an empty object. export type UtilsPrivateState = Record; -export const UtilsWitnesses = {}; +export const UtilsPrivateState: UtilsPrivateState = {}; +export const UtilsWitnesses = () => ({}); diff --git a/contracts/src/access/test/utils/address.ts b/contracts/test-utils/address.ts similarity index 68% rename from contracts/src/access/test/utils/address.ts rename to contracts/test-utils/address.ts index 3c9f2a52..38dae723 100644 --- a/contracts/src/access/test/utils/address.ts +++ b/contracts/test-utils/address.ts @@ -1,11 +1,16 @@ import { convertFieldToBytes, + type EncodedContractAddress, encodeCoinPublicKey, + isContractAddress, } from '@midnight-ntwrk/compact-runtime'; -import { encodeContractAddress } from '@midnight-ntwrk/ledger'; -import type * as Compact from '../../../../artifacts/MockOwnable/contract/index.cjs'; +import { encodeContractAddress } from '@midnight-ntwrk/ledger-v7'; -const PREFIX_ADDRESS = '0200'; +type ZswapCoinPublicKey = { bytes: Uint8Array }; + +type ContractAddress = { bytes: Uint8Array }; + +type Either = { is_left: boolean; left: A; right: B }; /** * @description Converts an ASCII string to its hexadecimal representation, @@ -23,19 +28,27 @@ export const toHexPadded = (str: string, len = 64) => * @param str String to hexify and encode. * @returns Encoded `ZswapCoinPublicKey`. */ -export const encodeToPK = (str: string): Compact.ZswapCoinPublicKey => ({ +export const encodeToPK = (str: string): ZswapCoinPublicKey => ({ bytes: encodeCoinPublicKey(toHexPadded(str)), }); /** - * @description Generates ContractAddress from `str` for testing purposes. - * Prepends 32-byte hex with PREFIX_ADDRESS before encoding. + * @description Generates ContractAddress from 32-byte hex `str` for testing purposes. * @param str String to hexify and encode. - * @returns Encoded `ZswapCoinPublicKey`. + * @throws {Error} Thrown when function fails to generate a valid ContractAddress + * @returns EncodedContractAddress. */ -export const encodeToAddress = (str: string): Compact.ContractAddress => ({ - bytes: encodeContractAddress(PREFIX_ADDRESS + toHexPadded(str)), -}); +export const encodeToAddress = (str: string): EncodedContractAddress => { + const generatedAddress = toHexPadded(str); + if (isContractAddress(generatedAddress)) { + return { + bytes: encodeContractAddress(generatedAddress), + } as EncodedContractAddress; + } + throw new Error( + 'Invalid Input: `generatedAddress` must be a valid `ContractAddress`', + ); +}; /** * @description Generates an Either object for ZswapCoinPublicKey for testing. @@ -66,10 +79,7 @@ const baseGeneratePubKeyPair = ( asEither: boolean, ): [ string, - ( - | Compact.ZswapCoinPublicKey - | Compact.Either - ), + ZswapCoinPublicKey | Either, ] => { const pk = toHexPadded(str); const zpk = asEither ? createEitherTestUser(str) : encodeToPK(str); @@ -77,12 +87,12 @@ const baseGeneratePubKeyPair = ( }; export const generatePubKeyPair = (str: string) => - baseGeneratePubKeyPair(str, false) as [string, Compact.ZswapCoinPublicKey]; + baseGeneratePubKeyPair(str, false) as [string, ZswapCoinPublicKey]; export const generateEitherPubKeyPair = (str: string) => baseGeneratePubKeyPair(str, true) as [ string, - Compact.Either, + Either, ]; export const zeroUint8Array = (length = 32) => diff --git a/contracts/vitest.config.ts b/contracts/vitest.config.ts index ede6d6de..3e71d7a7 100644 --- a/contracts/vitest.config.ts +++ b/contracts/vitest.config.ts @@ -1,10 +1,11 @@ -import { defineConfig } from 'vitest/config'; +import { configDefaults, defineConfig } from 'vitest/config'; export default defineConfig({ test: { globals: true, environment: 'node', include: ['src/**/*.test.ts'], + exclude: [...configDefaults.exclude, 'src/archive/**'], reporters: 'verbose', }, }); diff --git a/package.json b/package.json index e02c98d1..bac17f11 100644 --- a/package.json +++ b/package.json @@ -8,9 +8,9 @@ "packages/*" ], "scripts": { - "compact": "turbo run compact --filter=@openzeppelin-compact/contracts --log-prefix=none", + "compact": "turbo run compact --filter=@openzeppelin/compact-contracts --log-prefix=none", "build": "turbo run build --log-prefix=none", - "test": "turbo run test --filter=@openzeppelin-compact/contracts --log-prefix=none", + "test": "turbo run test --filter=@openzeppelin/compact-contracts --log-prefix=none", "fmt-and-lint": "biome check . --changed", "fmt-and-lint:fix": "biome check . --changed --write", "fmt-and-lint:ci": "biome ci . --changed --no-errors-on-unmatched", @@ -22,11 +22,11 @@ "glob": "~10.5.0" }, "dependencies": { - "@midnight-ntwrk/compact-runtime": "^0.9.0" + "@midnight-ntwrk/compact-runtime": "0.14.0" }, "devDependencies": { "@biomejs/biome": "^2.3.8", - "@midnight-ntwrk/ledger": "^4.0.0", + "@midnight-ntwrk/ledger-v7": "7.0.0", "@midnight-ntwrk/zswap": "^4.0.0", "@types/node": "24.10.0", "ts-node": "^10.9.2", diff --git a/packages/compact/README.md b/packages/compact/README.md new file mode 100644 index 00000000..e0e85cd7 --- /dev/null +++ b/packages/compact/README.md @@ -0,0 +1,200 @@ +# @openzeppelin-compact/compact + +CLI utilities for compiling and building Compact smart contracts. + +## Requirements + +- Node.js >= 20 +- Midnight Compact toolchain installed and available in `PATH` + +Verify your Compact installation: + +```bash +$ compact compile --version +Compactc version: 0.29.0 +``` + +## Binaries + +This package provides two CLI binaries: + +| Binary | Script | Description | +|--------|--------|-------------| +| `compact-compiler` | `dist/runCompiler.js` | Compile `.compact` files to artifacts | +| `compact-builder` | `dist/runBuilder.js` | Compile + build TypeScript + copy artifacts | + +## Compiler CLI + +### Usage + +```bash +compact-compiler [options] +``` + +### Options + +| Option | Description | Default | +|--------|-------------|---------| +| `--dir ` | Compile specific subdirectory within src | (all) | +| `--skip-zk` | Skip zero-knowledge proof generation | `false` | +| `+` | Use specific toolchain version (e.g., `+0.29.0`) | (default) | + +### Environment Variables + +| Variable | Description | +|----------|-------------| +| `SKIP_ZK=true` | Equivalent to `--skip-zk` flag | + +### Artifact Output Structure + +**Default (flattened):** All contract artifacts go directly under the output directory. + +``` +src/ + access/ + AccessControl.compact + token/ + Token.compact + +artifacts/ # Flattened output + AccessControl/ + Token/ +``` + +### Examples + +```bash +# Compile all contracts (flattened output) +compact-compiler + +# Compile specific directory only +compact-compiler --dir security + +# Skip ZK proof generation (faster, for development) +compact-compiler --skip-zk + +# Use specific toolchain version +compact-compiler +0.29.0 + +# Combine options +compact-compiler --dir access --skip-zk + +# Use environment variable +SKIP_ZK=true compact-compiler +``` + +## Builder CLI + +The builder runs the compiler as a prerequisite, then executes additional build steps: + +1. Clean `dist/` directory +2. Compile TypeScript (`tsc --project tsconfig.build.json`) +3. Copy .compact files preserving structure (excludes Mock* files and archive/) +4. Copy package.json and README for distribution + +### Usage + +```bash +compact-builder [options] +``` + +Accepts all compiler options except `--skip-zk` (builds always include ZK proofs). + +### Examples + +```bash +# Full build +compact-builder + +# Build specific directory +compact-builder --dir token + +# Build specific directory and skip proving key generation +compact-builder --dir token --skip-zk + +## Programmatic API + +The compiler can be used programmatically: + +```typescript +import { CompactCompiler } from '@openzeppelin-compact/compact'; + +const compiler = new CompactCompiler( + '--skip-zk', + 'security', + '0.29.0', +); + +await compiler.compile(); + +// Using factory method (parses CLI-style args) +const compiler = CompactCompiler.fromArgs([ + '--dir', 'security', + '--skip-zk', + '+0.29.0' +]); + +await compiler.compile(); +``` + +### Classes and Types + +```typescript +// Main compiler class +class CompactCompiler { + constructor(flags = '', targetDir?: string, version?: string, execFn?: ExecFunction) + static fromArgs(args: string[], env?: NodeJS.ProcessEnv): CompactCompiler; + compile(): Promise; + validateEnvironment(): Promise; +} + +// Builder class +class CompactBuilder { + constructor(compilerFlags = '') + build(): Promise; +} + +### Error Types + +```typescript +import { + CompactCliNotFoundError, // Compact CLI not in PATH + CompilationError, // Compilation failed (includes file path) + DirectoryNotFoundError, // Target directory doesn't exist +} from '@openzeppelin-compact/compact'; +``` + +## Development + +```bash +cd packages/compact + +# Build +yarn build + +# Type-check only +yarn types + +# Run tests +yarn test + +# Clean +yarn clean +``` + +## Output Example + +```bash +ℹ [COMPILE] Compact compiler started +ℹ [COMPILE] Compact developer tools: compact 0.4.0 +ℹ [COMPILE] Compact toolchain: Compactc version: 0.29.0 +ℹ [COMPILE] Found 2 .compact file(s) to compile +✔ [COMPILE] [1/2] Compiled AccessControl.compact + Compactc version: 0.29.0 +✔ [COMPILE] [2/2] Compiled Token.compact + Compactc version: 0.29.0 +``` + +## License + +MIT diff --git a/packages/compact/package.json b/packages/compact/package.json index b0c80805..666a2a7b 100644 --- a/packages/compact/package.json +++ b/packages/compact/package.json @@ -1,14 +1,17 @@ { "name": "@openzeppelin-compact/compact", "private": true, + "description": "CLI for building and packaging Compact smart contracts", "version": "0.0.1", "keywords": [ "compact", - "compiler" + "compiler", + "packaging", + "distribution", + "release" ], "author": "", "license": "MIT", - "description": "Compact fetcher", "type": "module", "exports": "./index.js", "engines": { @@ -26,7 +29,7 @@ }, "devDependencies": { "@tsconfig/node24": "^24.0.3", - "@types/node": "24.10.0", + "@types/node": "24.10.1", "typescript": "^5.9.3", "vitest": "^4.0.15" }, diff --git a/packages/compact/src/Builder.ts b/packages/compact/src/Builder.ts index d6150a2c..9ae39797 100755 --- a/packages/compact/src/Builder.ts +++ b/packages/compact/src/Builder.ts @@ -22,7 +22,7 @@ const execAsync = promisify(exec); * * @example * ```typescript - * const builder = new ProjectBuilder('--skip-zk'); // Optional flags for compactc + * const builder = new CompactBuilder('--skip-zk'); // Optional flags for compactc * builder.build().catch(err => console.error(err)); * ``` * @@ -102,7 +102,7 @@ export class CompactBuilder { ]; /** - * Constructs a new ProjectBuilder instance. + * Constructs a new CompactBuilder instance. * @param compilerFlags - Optional space-separated string of `compactc` flags (e.g., "--skip-zk") */ constructor(compilerFlags = '') { diff --git a/packages/compact/src/Compiler.ts b/packages/compact/src/Compiler.ts index 29b91528..cf34881d 100755 --- a/packages/compact/src/Compiler.ts +++ b/packages/compact/src/Compiler.ts @@ -176,7 +176,8 @@ export class FileDiscovery { */ async getCompactFiles(dir: string): Promise { try { - const dirents = await readdir(dir, { withFileTypes: true }); + let dirents = await readdir(dir, { withFileTypes: true }); + dirents = dirents.filter((dirent) => dirent.name !== 'archive'); const filePromises = dirents.map(async (entry) => { const fullPath = join(dir, entry.name); try { diff --git a/packages/compact/src/versions.ts b/packages/compact/src/versions.ts index efb582eb..827db1bd 100644 --- a/packages/compact/src/versions.ts +++ b/packages/compact/src/versions.ts @@ -1,2 +1,2 @@ -export const COMPACT_VERSION = '0.26.0'; -export const LANGUAGE_VERSION = '0.18.0'; +export const COMPACT_VERSION = '0.29.0'; +export const LANGUAGE_VERSION = '0.21.0'; diff --git a/packages/simulator/README.md b/packages/simulator/README.md index 43336b6d..fcfd3ec0 100644 --- a/packages/simulator/README.md +++ b/packages/simulator/README.md @@ -15,7 +15,7 @@ allowing you to simulate contract behavior locally without blockchain deployment ```typescript import { createSimulator } from '@openzeppelin-compact/contracts-simulator'; -import { Contract, ledger } from './artifacts/MyContract/contract/index.cjs'; +import { Contract, ledger } from './artifacts/MyContract/contract/index.js'; // 1. Define your contract arguments type type MyContractArgs = readonly [owner: Uint8Array, value: bigint]; @@ -46,7 +46,7 @@ The base simulator acts as a configuration class that the actual simulator will ```typescript import { createSimulator } from '@openzeppelin-compact/contracts-simulator'; -import { Contract as MyContract, ledger } from './artifacts/MyContract/contract/index.cjs'; +import { Contract as MyContract, ledger } from './artifacts/MyContract/contract/index.js'; import { MyContractWitnesses, MyContractPrivateState } from './MyContractWitnesses.js'; // Define contract constructor arguments as a tuple type diff --git a/packages/simulator/package.json b/packages/simulator/package.json index 0448a429..9bc117a7 100644 --- a/packages/simulator/package.json +++ b/packages/simulator/package.json @@ -29,7 +29,7 @@ "clean": "git clean -fXd" }, "devDependencies": { - "@midnight-ntwrk/ledger": "^4.0.0", + "@midnight-ntwrk/ledger-v7": "7.0.0", "@midnight-ntwrk/zswap": "^4.0.0", "@tsconfig/node24": "^24.0.3", "@types/node": "24.10.0", @@ -38,6 +38,6 @@ "vitest": "^4.0.15" }, "dependencies": { - "@midnight-ntwrk/compact-runtime": "^0.9.0" + "@midnight-ntwrk/compact-runtime": "0.14.0" } } diff --git a/packages/simulator/src/core/AbstractSimulator.ts b/packages/simulator/src/core/AbstractSimulator.ts index 79258299..52be1b58 100644 --- a/packages/simulator/src/core/AbstractSimulator.ts +++ b/packages/simulator/src/core/AbstractSimulator.ts @@ -1,7 +1,7 @@ import type { CircuitContext, CoinPublicKey, - ContractState, + StateValue, } from '@midnight-ntwrk/compact-runtime'; import type { ContextlessCircuits, @@ -79,12 +79,12 @@ export abstract class AbstractSimulator } /** - * Retrieves the original contract state from the circuit context. + * Retrieves the current contract state data. * - * @returns The current contract state from the blockchain + * @returns The current state value containing the ledger data */ - public getContractState(): ContractState { - return this.circuitContext.originalState; + public getContractState(): StateValue { + return this.circuitContext.currentQueryContext.state.state; } /** diff --git a/packages/simulator/src/core/CircuitContextManager.ts b/packages/simulator/src/core/CircuitContextManager.ts index 88f832a3..0928d1a2 100644 --- a/packages/simulator/src/core/CircuitContextManager.ts +++ b/packages/simulator/src/core/CircuitContextManager.ts @@ -4,7 +4,8 @@ import { type ConstructorContext, type ContractAddress, type ContractState, - constructorContext, + CostModel, + createConstructorContext, type EncodedZswapLocalState, QueryContext, } from '@midnight-ntwrk/compact-runtime'; @@ -44,7 +45,7 @@ export class CircuitContextManager

{ contractAddress: ContractAddress, ...contractArgs: any[] ) { - const initCtx = constructorContext(privateState, coinPK); + const initCtx = createConstructorContext(privateState, coinPK); const { currentPrivateState, @@ -52,14 +53,14 @@ export class CircuitContextManager

{ currentZswapLocalState, } = contract.initialState(initCtx, ...contractArgs); + // Extract ChargedState from the compiler-generated ContractState + const chargedState = currentContractState.data; + this.context = { currentPrivateState, currentZswapLocalState, - originalState: currentContractState, - transactionContext: new QueryContext( - currentContractState.data, - contractAddress, - ), + currentQueryContext: new QueryContext(chargedState, contractAddress), + costModel: CostModel.initialCostModel(), }; } diff --git a/packages/simulator/src/core/ContractSimulator.ts b/packages/simulator/src/core/ContractSimulator.ts index 0c360b44..9321626f 100644 --- a/packages/simulator/src/core/ContractSimulator.ts +++ b/packages/simulator/src/core/ContractSimulator.ts @@ -35,12 +35,16 @@ export abstract class ContractSimulator extends AbstractSimulator { */ public getCallerContext(): CircuitContext

{ const activeCaller = this.callerOverride || this.persistentCallerOverride; + const baseCtx = this.circuitContext; return { - ...this.circuitContext, + currentPrivateState: baseCtx.currentPrivateState, + currentQueryContext: baseCtx.currentQueryContext, currentZswapLocalState: activeCaller ? emptyZswapLocalState(activeCaller) - : this.circuitContext.currentZswapLocalState, + : baseCtx.currentZswapLocalState, + costModel: baseCtx.costModel, + gasLimit: baseCtx.gasLimit, }; } diff --git a/packages/simulator/src/factory/SimulatorConfig.ts b/packages/simulator/src/factory/SimulatorConfig.ts index 64e852d8..bd11aaa5 100644 --- a/packages/simulator/src/factory/SimulatorConfig.ts +++ b/packages/simulator/src/factory/SimulatorConfig.ts @@ -1,19 +1,22 @@ import type { StateValue } from '@midnight-ntwrk/compact-runtime'; +import type { IMinimalContract } from '../types/Contract.js'; /** * Configuration interface for the simulator factory. * @template P - Private state type * @template L - Ledger state type * @template W - Witnesses type + * @template TContract - The contract type that extends IMinimalContract * @template TArgs - Tuple type of contract-specific arguments passed to CircuitContextManager */ export interface SimulatorConfig< P, L, W, + TContract extends IMinimalContract, TArgs extends readonly any[] = readonly any[], > { /** Factory function to create the contract instance */ - contractFactory: (witnesses: W) => any; + contractFactory: (witnesses: W) => TContract; /** Function to generate default private state */ defaultPrivateState: () => P; /** diff --git a/packages/simulator/src/factory/createSimulator.ts b/packages/simulator/src/factory/createSimulator.ts index 9f1dd249..98c83f09 100644 --- a/packages/simulator/src/factory/createSimulator.ts +++ b/packages/simulator/src/factory/createSimulator.ts @@ -1,8 +1,13 @@ import type { WitnessContext } from '@midnight-ntwrk/compact-runtime'; -import { sampleContractAddress } from '@midnight-ntwrk/zswap'; +import { dummyContractAddress } from '@midnight-ntwrk/compact-runtime'; import { CircuitContextManager } from '../core/CircuitContextManager.js'; import { ContractSimulator } from '../core/ContractSimulator.js'; import type { IMinimalContract } from '../types/Contract.js'; +import type { + ContextlessCircuits, + ExtractImpureCircuits, + ExtractPureCircuits, +} from '../types/index.js'; import type { BaseSimulatorOptions } from '../types/Options.js'; import type { SimulatorConfig } from './SimulatorConfig.js'; @@ -19,11 +24,15 @@ import type { SimulatorConfig } from './SimulatorConfig.js'; * @param config - Configuration object defining how to create and manage the simulator * @returns A class constructor that can be extended to create specific simulators */ -export function createSimulator( - config: SimulatorConfig, -) { +export function createSimulator< + P, + L, + W, + TContract extends IMinimalContract, + TArgs extends readonly any[] = readonly any[], +>(config: SimulatorConfig) { return class GeneratedSimulator extends ContractSimulator { - contract: IMinimalContract; + contract: TContract; readonly contractAddress: string; public _witnesses: W; @@ -40,7 +49,7 @@ export function createSimulator( privateState = config.defaultPrivateState(), witnesses = config.witnessesFactory(), coinPK = '0'.repeat(64), - contractAddress = sampleContractAddress(), + contractAddress = dummyContractAddress(), } = options; this._witnesses = witnesses; @@ -56,21 +65,30 @@ export function createSimulator( ...processedArgs, ); - this.contractAddress = this.circuitContext.transactionContext.address; + this.contractAddress = this.circuitContext.currentQueryContext.address; } - public _pureCircuitProxy?: any; - public _impureCircuitProxy?: any; + public _pureCircuitProxy?: ContextlessCircuits< + ExtractPureCircuits, + P + >; + public _impureCircuitProxy?: ContextlessCircuits< + ExtractImpureCircuits, + P + >; /** * Gets the pure circuit proxy, creating it lazily if it doesn't exist. * * @returns The pure circuit proxy for executing read-only contract methods */ - public get pureCircuit() { + public get pureCircuit(): ContextlessCircuits< + ExtractPureCircuits, + P + > { if (!this._pureCircuitProxy) { this._pureCircuitProxy = this.createPureCircuitProxy( - this.contract.circuits, + this.contract.circuits as ExtractPureCircuits, () => this.circuitContext, ); } @@ -82,10 +100,13 @@ export function createSimulator( * * @returns The impure circuit proxy for executing state-modifying contract methods */ - public get impureCircuit() { + public get impureCircuit(): ContextlessCircuits< + ExtractImpureCircuits, + P + > { if (!this._impureCircuitProxy) { this._impureCircuitProxy = this.createImpureCircuitProxy( - this.contract.impureCircuits, + this.contract.impureCircuits as ExtractImpureCircuits, () => this.getCallerContext(), (ctx) => { this.circuitContext = ctx; @@ -122,7 +143,7 @@ export function createSimulator( */ getPublicState(): L { return config.ledgerExtractor( - this.circuitContext.transactionContext.state, + this.circuitContext.currentQueryContext.state.state, ); } @@ -170,7 +191,7 @@ export function createSimulator( return { ledger: this.getPublicState(), privateState: circuitCtx.currentPrivateState, - contractAddress: circuitCtx.transactionContext.address, + contractAddress: circuitCtx.currentQueryContext.address, }; } }; diff --git a/packages/simulator/src/types/Simulator.ts b/packages/simulator/src/types/Simulator.ts index 5058dd51..9ed0ee61 100644 --- a/packages/simulator/src/types/Simulator.ts +++ b/packages/simulator/src/types/Simulator.ts @@ -1,6 +1,6 @@ import type { CircuitContext, - ContractState, + StateValue, } from '@midnight-ntwrk/compact-runtime'; /** @@ -31,7 +31,7 @@ export interface IContractSimulator { getPrivateState(): P; /** - * Returns the original contract state. + * Returns the current contract state. */ - getContractState(): ContractState; + getContractState(): StateValue; } diff --git a/packages/simulator/src/utils/CircuitContextUtils.ts b/packages/simulator/src/utils/CircuitContextUtils.ts index a121d823..420ac759 100644 --- a/packages/simulator/src/utils/CircuitContextUtils.ts +++ b/packages/simulator/src/utils/CircuitContextUtils.ts @@ -1,8 +1,9 @@ import { + type ChargedState, type CircuitContext, type CoinPublicKey, type ContractAddress, - type ContractState, + CostModel, emptyZswapLocalState, QueryContext, } from '@midnight-ntwrk/compact-runtime'; @@ -15,22 +16,22 @@ import type { IContractSimulator } from '../types/index.js'; * for executing circuits, including contract state, private state, * sender identity, and transaction data. * @param privateState - The private state data specific to the contract - * @param contractState - The current contract state from the blockchain + * @param chargedState - The charged state (wraps StateValue with cost tracking) * @param sender - The public key of the transaction sender * @param contractAddress - The address of the contract being executed * @returns A complete CircuitContext ready for circuit execution */ export function useCircuitContext

( privateState: P, - contractState: ContractState, + chargedState: ChargedState, sender: CoinPublicKey, contractAddress: ContractAddress, ): CircuitContext

{ return { - originalState: contractState, currentPrivateState: privateState, - transactionContext: new QueryContext(contractState.data, contractAddress), + currentQueryContext: new QueryContext(chargedState, contractAddress), currentZswapLocalState: emptyZswapLocalState(sender), + costModel: CostModel.initialCostModel(), }; } @@ -47,14 +48,19 @@ export function useCircuitContextSender< L, C extends IContractSimulator, >(contract: C, sender: CoinPublicKey): CircuitContext

{ + const currentCircuitContext = contract.circuitContext; const currentPrivateState = contract.getPrivateState(); - const originalState = contract.getContractState(); + const existingChargedState = currentCircuitContext.currentQueryContext.state; const contractAddress = contract.contractAddress; return { - originalState, currentPrivateState, - transactionContext: new QueryContext(originalState.data, contractAddress), + currentQueryContext: new QueryContext( + existingChargedState, + contractAddress, + ), currentZswapLocalState: emptyZswapLocalState(sender), + costModel: currentCircuitContext.costModel, + gasLimit: currentCircuitContext.gasLimit, }; } diff --git a/packages/simulator/test/fixtures/sample-contracts/SampleZOwnable.compact b/packages/simulator/test/fixtures/sample-contracts/SampleZOwnable.compact index 554774bc..6137167f 100644 --- a/packages/simulator/test/fixtures/sample-contracts/SampleZOwnable.compact +++ b/packages/simulator/test/fixtures/sample-contracts/SampleZOwnable.compact @@ -1,9 +1,16 @@ // Sample contract for testing // DO NOT USE IN PRODUCTION!!! -pragma language_version >= 0.18.0; +pragma language_version >= 0.21.0; -import CompactStandardLibrary; +import { + Either, + Counter, + ZswapCoinPublicKey, + ContractAddress, + persistentHash, + ownPublicKey, +} from CompactStandardLibrary; export { ZswapCoinPublicKey, ContractAddress, Either }; export ledger _ownerCommitment: Bytes<32>; diff --git a/packages/simulator/test/fixtures/sample-contracts/Simple.compact b/packages/simulator/test/fixtures/sample-contracts/Simple.compact index 3ce08c73..769fc0a9 100644 --- a/packages/simulator/test/fixtures/sample-contracts/Simple.compact +++ b/packages/simulator/test/fixtures/sample-contracts/Simple.compact @@ -1,6 +1,9 @@ -pragma language_version >= 0.18.0; +// Sample contract for testing +// DO NOT USE IN PRODUCTION!!! -import CompactStandardLibrary; +pragma language_version >= 0.21.0; + +import { ZswapCoinPublicKey, ContractAddress, Either, Maybe } from CompactStandardLibrary; export { ZswapCoinPublicKey, ContractAddress, Either, Maybe }; export ledger _val: Field; diff --git a/packages/simulator/test/fixtures/sample-contracts/Witness.compact b/packages/simulator/test/fixtures/sample-contracts/Witness.compact index 211edcb6..fea28bab 100644 --- a/packages/simulator/test/fixtures/sample-contracts/Witness.compact +++ b/packages/simulator/test/fixtures/sample-contracts/Witness.compact @@ -1,6 +1,9 @@ -pragma language_version >= 0.18.0; +// Sample contract for testing +// DO NOT USE IN PRODUCTION!!! -import CompactStandardLibrary; +pragma language_version >= 0.21.0; + +import { ZswapCoinPublicKey, ContractAddress, Either, Maybe } from CompactStandardLibrary; export { ZswapCoinPublicKey, ContractAddress, Either, Maybe }; export ledger _valBytes: Bytes<32>; diff --git a/packages/simulator/test/fixtures/sample-contracts/witnesses/SampleZOwnableWitnesses.ts b/packages/simulator/test/fixtures/sample-contracts/witnesses/SampleZOwnableWitnesses.ts index 996e9cbe..464007f1 100644 --- a/packages/simulator/test/fixtures/sample-contracts/witnesses/SampleZOwnableWitnesses.ts +++ b/packages/simulator/test/fixtures/sample-contracts/witnesses/SampleZOwnableWitnesses.ts @@ -1,6 +1,6 @@ import { getRandomValues } from 'node:crypto'; import type { WitnessContext } from '@midnight-ntwrk/compact-runtime'; -import type { Ledger } from '../../test-artifacts/SampleZOwnable/contract/index.cjs'; +import type { Ledger } from '../../artifacts/SampleZOwnable/contract/index.js'; /** * @description Interface defining the witness methods for SampleZOwnable operations. diff --git a/packages/simulator/test/fixtures/sample-contracts/witnesses/WitnessWitnesses.ts b/packages/simulator/test/fixtures/sample-contracts/witnesses/WitnessWitnesses.ts index 32f12424..7795cdfc 100644 --- a/packages/simulator/test/fixtures/sample-contracts/witnesses/WitnessWitnesses.ts +++ b/packages/simulator/test/fixtures/sample-contracts/witnesses/WitnessWitnesses.ts @@ -1,6 +1,6 @@ import { getRandomValues } from 'node:crypto'; import type { WitnessContext } from '@midnight-ntwrk/compact-runtime'; -import type { Ledger } from '../../test-artifacts/Witness/contract/index.cjs'; +import type { Ledger } from '../../artifacts/Witness/contract/index.js'; const randomBigInt = (bits: number): bigint => { const bytes = Math.ceil(bits / 8); diff --git a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/compiler/contract-info.json b/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/compiler/contract-info.json deleted file mode 100644 index 15dffd51..00000000 --- a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/compiler/contract-info.json +++ /dev/null @@ -1,155 +0,0 @@ -{ - "circuits": [ - { - "name": "owner", - "pure": false, - "arguments": [ - ], - "result-type": { - "type-name": "Bytes", - "length": 32 - } - }, - { - "name": "transferOwnership", - "pure": false, - "arguments": [ - { - "name": "newOwnerId", - "type": { - "type-name": "Bytes", - "length": 32 - } - } - ], - "result-type": { - "type-name": "Tuple", - "types": [ - ] - } - }, - { - "name": "renounceOwnership", - "pure": false, - "arguments": [ - ], - "result-type": { - "type-name": "Tuple", - "types": [ - ] - } - }, - { - "name": "assertOnlyOwner", - "pure": false, - "arguments": [ - ], - "result-type": { - "type-name": "Tuple", - "types": [ - ] - } - }, - { - "name": "_computeOwnerCommitment", - "pure": false, - "arguments": [ - { - "name": "id", - "type": { - "type-name": "Bytes", - "length": 32 - } - }, - { - "name": "counter", - "type": { - "type-name": "Uint", - "maxval": 18446744073709551615 - } - } - ], - "result-type": { - "type-name": "Bytes", - "length": 32 - } - }, - { - "name": "_computeOwnerId", - "pure": true, - "arguments": [ - { - "name": "pk", - "type": { - "type-name": "Struct", - "name": "Either", - "elements": [ - { - "name": "is_left", - "type": { - "type-name": "Boolean" - } - }, - { - "name": "left", - "type": { - "type-name": "Struct", - "name": "ZswapCoinPublicKey", - "elements": [ - { - "name": "bytes", - "type": { - "type-name": "Bytes", - "length": 32 - } - } - ] - } - }, - { - "name": "right", - "type": { - "type-name": "Struct", - "name": "ContractAddress", - "elements": [ - { - "name": "bytes", - "type": { - "type-name": "Bytes", - "length": 32 - } - } - ] - } - } - ] - } - }, - { - "name": "nonce", - "type": { - "type-name": "Bytes", - "length": 32 - } - } - ], - "result-type": { - "type-name": "Bytes", - "length": 32 - } - } - ], - "witnesses": [ - { - "name": "secretNonce", - "arguments": [ - ], - "result type": { - "type-name": "Bytes", - "length": 32 - } - } - ], - "contracts": [ - ] -} diff --git a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/contract/index.cjs b/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/contract/index.cjs deleted file mode 100644 index b0606b61..00000000 --- a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/contract/index.cjs +++ /dev/null @@ -1,670 +0,0 @@ -'use strict'; -const __compactRuntime = require('@midnight-ntwrk/compact-runtime'); -const expectedRuntimeVersionString = '0.9.0'; -const expectedRuntimeVersion = expectedRuntimeVersionString.split('-')[0].split('.').map(Number); -const actualRuntimeVersion = __compactRuntime.versionString.split('-')[0].split('.').map(Number); -if (expectedRuntimeVersion[0] != actualRuntimeVersion[0] - || (actualRuntimeVersion[0] == 0 && expectedRuntimeVersion[1] != actualRuntimeVersion[1]) - || expectedRuntimeVersion[1] > actualRuntimeVersion[1] - || (expectedRuntimeVersion[1] == actualRuntimeVersion[1] && expectedRuntimeVersion[2] > actualRuntimeVersion[2])) - throw new __compactRuntime.CompactError(`Version mismatch: compiled code expects ${expectedRuntimeVersionString}, runtime is ${__compactRuntime.versionString}`); -{ const MAX_FIELD = 52435875175126190479447740508185965837690552500527637822603658699938581184512n; - if (__compactRuntime.MAX_FIELD !== MAX_FIELD) - throw new __compactRuntime.CompactError(`compiler thinks maximum field value is ${MAX_FIELD}; run time thinks it is ${__compactRuntime.MAX_FIELD}`) -} - -const _descriptor_0 = new __compactRuntime.CompactTypeBoolean(); - -const _descriptor_1 = new __compactRuntime.CompactTypeBytes(32); - -class _ZswapCoinPublicKey_0 { - alignment() { - return _descriptor_1.alignment(); - } - fromValue(value_0) { - return { - bytes: _descriptor_1.fromValue(value_0) - } - } - toValue(value_0) { - return _descriptor_1.toValue(value_0.bytes); - } -} - -const _descriptor_2 = new _ZswapCoinPublicKey_0(); - -class _ContractAddress_0 { - alignment() { - return _descriptor_1.alignment(); - } - fromValue(value_0) { - return { - bytes: _descriptor_1.fromValue(value_0) - } - } - toValue(value_0) { - return _descriptor_1.toValue(value_0.bytes); - } -} - -const _descriptor_3 = new _ContractAddress_0(); - -class _Either_0 { - alignment() { - return _descriptor_0.alignment().concat(_descriptor_2.alignment().concat(_descriptor_3.alignment())); - } - fromValue(value_0) { - return { - is_left: _descriptor_0.fromValue(value_0), - left: _descriptor_2.fromValue(value_0), - right: _descriptor_3.fromValue(value_0) - } - } - toValue(value_0) { - return _descriptor_0.toValue(value_0.is_left).concat(_descriptor_2.toValue(value_0.left).concat(_descriptor_3.toValue(value_0.right))); - } -} - -const _descriptor_4 = new _Either_0(); - -const _descriptor_5 = new __compactRuntime.CompactTypeUnsignedInteger(65535n, 2); - -const _descriptor_6 = new __compactRuntime.CompactTypeUnsignedInteger(18446744073709551615n, 8); - -const _descriptor_7 = new __compactRuntime.CompactTypeVector(2, _descriptor_1); - -const _descriptor_8 = new __compactRuntime.CompactTypeVector(4, _descriptor_1); - -const _descriptor_9 = new __compactRuntime.CompactTypeUnsignedInteger(255n, 1); - -const _descriptor_10 = new __compactRuntime.CompactTypeUnsignedInteger(340282366920938463463374607431768211455n, 16); - -class Contract { - witnesses; - constructor(...args_0) { - if (args_0.length !== 1) { - throw new __compactRuntime.CompactError(`Contract constructor: expected 1 argument, received ${args_0.length}`); - } - const witnesses_0 = args_0[0]; - if (typeof(witnesses_0) !== 'object') { - throw new __compactRuntime.CompactError('first (witnesses) argument to Contract constructor is not an object'); - } - if (typeof(witnesses_0.secretNonce) !== 'function') { - throw new __compactRuntime.CompactError('first (witnesses) argument to Contract constructor does not contain a function-valued field named secretNonce'); - } - this.witnesses = witnesses_0; - this.circuits = { - owner: (...args_1) => { - if (args_1.length !== 1) { - throw new __compactRuntime.CompactError(`owner: expected 1 argument (as invoked from Typescript), received ${args_1.length}`); - } - const contextOrig_0 = args_1[0]; - if (!(typeof(contextOrig_0) === 'object' && contextOrig_0.originalState != undefined && contextOrig_0.transactionContext != undefined)) { - __compactRuntime.type_error('owner', - 'argument 1 (as invoked from Typescript)', - 'SampleZOwnable.compact line 21 char 1', - 'CircuitContext', - contextOrig_0) - } - const context = { ...contextOrig_0 }; - const partialProofData = { - input: { value: [], alignment: [] }, - output: undefined, - publicTranscript: [], - privateTranscriptOutputs: [] - }; - const result_0 = this._owner_0(context, partialProofData); - partialProofData.output = { value: _descriptor_1.toValue(result_0), alignment: _descriptor_1.alignment() }; - return { result: result_0, context: context, proofData: partialProofData }; - }, - transferOwnership: (...args_1) => { - if (args_1.length !== 2) { - throw new __compactRuntime.CompactError(`transferOwnership: expected 2 arguments (as invoked from Typescript), received ${args_1.length}`); - } - const contextOrig_0 = args_1[0]; - const newOwnerId_0 = args_1[1]; - if (!(typeof(contextOrig_0) === 'object' && contextOrig_0.originalState != undefined && contextOrig_0.transactionContext != undefined)) { - __compactRuntime.type_error('transferOwnership', - 'argument 1 (as invoked from Typescript)', - 'SampleZOwnable.compact line 25 char 1', - 'CircuitContext', - contextOrig_0) - } - if (!(newOwnerId_0.buffer instanceof ArrayBuffer && newOwnerId_0.BYTES_PER_ELEMENT === 1 && newOwnerId_0.length === 32)) { - __compactRuntime.type_error('transferOwnership', - 'argument 1 (argument 2 as invoked from Typescript)', - 'SampleZOwnable.compact line 25 char 1', - 'Bytes<32>', - newOwnerId_0) - } - const context = { ...contextOrig_0 }; - const partialProofData = { - input: { - value: _descriptor_1.toValue(newOwnerId_0), - alignment: _descriptor_1.alignment() - }, - output: undefined, - publicTranscript: [], - privateTranscriptOutputs: [] - }; - const result_0 = this._transferOwnership_0(context, - partialProofData, - newOwnerId_0); - partialProofData.output = { value: [], alignment: [] }; - return { result: result_0, context: context, proofData: partialProofData }; - }, - renounceOwnership: (...args_1) => { - if (args_1.length !== 1) { - throw new __compactRuntime.CompactError(`renounceOwnership: expected 1 argument (as invoked from Typescript), received ${args_1.length}`); - } - const contextOrig_0 = args_1[0]; - if (!(typeof(contextOrig_0) === 'object' && contextOrig_0.originalState != undefined && contextOrig_0.transactionContext != undefined)) { - __compactRuntime.type_error('renounceOwnership', - 'argument 1 (as invoked from Typescript)', - 'SampleZOwnable.compact line 31 char 1', - 'CircuitContext', - contextOrig_0) - } - const context = { ...contextOrig_0 }; - const partialProofData = { - input: { value: [], alignment: [] }, - output: undefined, - publicTranscript: [], - privateTranscriptOutputs: [] - }; - const result_0 = this._renounceOwnership_0(context, partialProofData); - partialProofData.output = { value: [], alignment: [] }; - return { result: result_0, context: context, proofData: partialProofData }; - }, - assertOnlyOwner: (...args_1) => { - if (args_1.length !== 1) { - throw new __compactRuntime.CompactError(`assertOnlyOwner: expected 1 argument (as invoked from Typescript), received ${args_1.length}`); - } - const contextOrig_0 = args_1[0]; - if (!(typeof(contextOrig_0) === 'object' && contextOrig_0.originalState != undefined && contextOrig_0.transactionContext != undefined)) { - __compactRuntime.type_error('assertOnlyOwner', - 'argument 1 (as invoked from Typescript)', - 'SampleZOwnable.compact line 36 char 1', - 'CircuitContext', - contextOrig_0) - } - const context = { ...contextOrig_0 }; - const partialProofData = { - input: { value: [], alignment: [] }, - output: undefined, - publicTranscript: [], - privateTranscriptOutputs: [] - }; - const result_0 = this._assertOnlyOwner_0(context, partialProofData); - partialProofData.output = { value: [], alignment: [] }; - return { result: result_0, context: context, proofData: partialProofData }; - }, - _computeOwnerCommitment: (...args_1) => { - if (args_1.length !== 3) { - throw new __compactRuntime.CompactError(`_computeOwnerCommitment: expected 3 arguments (as invoked from Typescript), received ${args_1.length}`); - } - const contextOrig_0 = args_1[0]; - const id_0 = args_1[1]; - const counter_0 = args_1[2]; - if (!(typeof(contextOrig_0) === 'object' && contextOrig_0.originalState != undefined && contextOrig_0.transactionContext != undefined)) { - __compactRuntime.type_error('_computeOwnerCommitment', - 'argument 1 (as invoked from Typescript)', - 'SampleZOwnable.compact line 47 char 1', - 'CircuitContext', - contextOrig_0) - } - if (!(id_0.buffer instanceof ArrayBuffer && id_0.BYTES_PER_ELEMENT === 1 && id_0.length === 32)) { - __compactRuntime.type_error('_computeOwnerCommitment', - 'argument 1 (argument 2 as invoked from Typescript)', - 'SampleZOwnable.compact line 47 char 1', - 'Bytes<32>', - id_0) - } - if (!(typeof(counter_0) === 'bigint' && counter_0 >= 0n && counter_0 <= 18446744073709551615n)) { - __compactRuntime.type_error('_computeOwnerCommitment', - 'argument 2 (argument 3 as invoked from Typescript)', - 'SampleZOwnable.compact line 47 char 1', - 'Uint<0..18446744073709551615>', - counter_0) - } - const context = { ...contextOrig_0 }; - const partialProofData = { - input: { - value: _descriptor_1.toValue(id_0).concat(_descriptor_6.toValue(counter_0)), - alignment: _descriptor_1.alignment().concat(_descriptor_6.alignment()) - }, - output: undefined, - publicTranscript: [], - privateTranscriptOutputs: [] - }; - const result_0 = this.__computeOwnerCommitment_0(context, - partialProofData, - id_0, - counter_0); - partialProofData.output = { value: _descriptor_1.toValue(result_0), alignment: _descriptor_1.alignment() }; - return { result: result_0, context: context, proofData: partialProofData }; - }, - _computeOwnerId(context, ...args_1) { - return { result: pureCircuits._computeOwnerId(...args_1), context }; - } - }; - this.impureCircuits = { - owner: this.circuits.owner, - transferOwnership: this.circuits.transferOwnership, - renounceOwnership: this.circuits.renounceOwnership, - assertOnlyOwner: this.circuits.assertOnlyOwner, - _computeOwnerCommitment: this.circuits._computeOwnerCommitment - }; - } - initialState(...args_0) { - if (args_0.length !== 3) { - throw new __compactRuntime.CompactError(`Contract state constructor: expected 3 arguments (as invoked from Typescript), received ${args_0.length}`); - } - const constructorContext_0 = args_0[0]; - const ownerId_0 = args_0[1]; - const instanceSalt_0 = args_0[2]; - if (typeof(constructorContext_0) !== 'object') { - throw new __compactRuntime.CompactError(`Contract state constructor: expected 'constructorContext' in argument 1 (as invoked from Typescript) to be an object`); - } - if (!('initialPrivateState' in constructorContext_0)) { - throw new __compactRuntime.CompactError(`Contract state constructor: expected 'initialPrivateState' in argument 1 (as invoked from Typescript)`); - } - if (!('initialZswapLocalState' in constructorContext_0)) { - throw new __compactRuntime.CompactError(`Contract state constructor: expected 'initialZswapLocalState' in argument 1 (as invoked from Typescript)`); - } - if (typeof(constructorContext_0.initialZswapLocalState) !== 'object') { - throw new __compactRuntime.CompactError(`Contract state constructor: expected 'initialZswapLocalState' in argument 1 (as invoked from Typescript) to be an object`); - } - if (!(ownerId_0.buffer instanceof ArrayBuffer && ownerId_0.BYTES_PER_ELEMENT === 1 && ownerId_0.length === 32)) { - __compactRuntime.type_error('Contract state constructor', - 'argument 1 (argument 2 as invoked from Typescript)', - 'SampleZOwnable.compact line 15 char 1', - 'Bytes<32>', - ownerId_0) - } - if (!(instanceSalt_0.buffer instanceof ArrayBuffer && instanceSalt_0.BYTES_PER_ELEMENT === 1 && instanceSalt_0.length === 32)) { - __compactRuntime.type_error('Contract state constructor', - 'argument 2 (argument 3 as invoked from Typescript)', - 'SampleZOwnable.compact line 15 char 1', - 'Bytes<32>', - instanceSalt_0) - } - const state_0 = new __compactRuntime.ContractState(); - let stateValue_0 = __compactRuntime.StateValue.newArray(); - stateValue_0 = stateValue_0.arrayPush(__compactRuntime.StateValue.newNull()); - stateValue_0 = stateValue_0.arrayPush(__compactRuntime.StateValue.newNull()); - stateValue_0 = stateValue_0.arrayPush(__compactRuntime.StateValue.newNull()); - state_0.data = stateValue_0; - state_0.setOperation('owner', new __compactRuntime.ContractOperation()); - state_0.setOperation('transferOwnership', new __compactRuntime.ContractOperation()); - state_0.setOperation('renounceOwnership', new __compactRuntime.ContractOperation()); - state_0.setOperation('assertOnlyOwner', new __compactRuntime.ContractOperation()); - state_0.setOperation('_computeOwnerCommitment', new __compactRuntime.ContractOperation()); - const context = { - originalState: state_0, - currentPrivateState: constructorContext_0.initialPrivateState, - currentZswapLocalState: constructorContext_0.initialZswapLocalState, - transactionContext: new __compactRuntime.QueryContext(state_0.data, __compactRuntime.dummyContractAddress()) - }; - const partialProofData = { - input: { value: [], alignment: [] }, - output: undefined, - publicTranscript: [], - privateTranscriptOutputs: [] - }; - Contract._query(context, - partialProofData, - [ - { push: { storage: false, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_9.toValue(0n), - alignment: _descriptor_9.alignment() }).encode() } }, - { push: { storage: true, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_1.toValue(new Uint8Array(32)), - alignment: _descriptor_1.alignment() }).encode() } }, - { ins: { cached: false, n: 1 } }]); - Contract._query(context, - partialProofData, - [ - { push: { storage: false, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_9.toValue(1n), - alignment: _descriptor_9.alignment() }).encode() } }, - { push: { storage: true, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_6.toValue(0n), - alignment: _descriptor_6.alignment() }).encode() } }, - { ins: { cached: false, n: 1 } }]); - Contract._query(context, - partialProofData, - [ - { push: { storage: false, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_9.toValue(2n), - alignment: _descriptor_9.alignment() }).encode() } }, - { push: { storage: true, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_1.toValue(new Uint8Array(32)), - alignment: _descriptor_1.alignment() }).encode() } }, - { ins: { cached: false, n: 1 } }]); - __compactRuntime.assert(!this._equal_0(ownerId_0, new Uint8Array(32)), - 'SampleZOwnable: invalid id'); - Contract._query(context, - partialProofData, - [ - { push: { storage: false, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_9.toValue(2n), - alignment: _descriptor_9.alignment() }).encode() } }, - { push: { storage: true, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_1.toValue(instanceSalt_0), - alignment: _descriptor_1.alignment() }).encode() } }, - { ins: { cached: false, n: 1 } }]); - this.__transferOwnership_0(context, partialProofData, ownerId_0); - state_0.data = context.transactionContext.state; - return { - currentContractState: state_0, - currentPrivateState: context.currentPrivateState, - currentZswapLocalState: context.currentZswapLocalState - } - } - _persistentHash_0(value_0) { - const result_0 = __compactRuntime.persistentHash(_descriptor_8, value_0); - return result_0; - } - _persistentHash_1(value_0) { - const result_0 = __compactRuntime.persistentHash(_descriptor_7, value_0); - return result_0; - } - _ownPublicKey_0(context, partialProofData) { - const result_0 = __compactRuntime.ownPublicKey(context); - partialProofData.privateTranscriptOutputs.push({ - value: _descriptor_2.toValue(result_0), - alignment: _descriptor_2.alignment() - }); - return result_0; - } - _secretNonce_0(context, partialProofData) { - const witnessContext_0 = __compactRuntime.witnessContext(ledger(context.transactionContext.state), context.currentPrivateState, context.transactionContext.address); - const [nextPrivateState_0, result_0] = this.witnesses.secretNonce(witnessContext_0); - context.currentPrivateState = nextPrivateState_0; - if (!(result_0.buffer instanceof ArrayBuffer && result_0.BYTES_PER_ELEMENT === 1 && result_0.length === 32)) { - __compactRuntime.type_error('secretNonce', - 'return value', - 'SampleZOwnable.compact line 13 char 1', - 'Bytes<32>', - result_0) - } - partialProofData.privateTranscriptOutputs.push({ - value: _descriptor_1.toValue(result_0), - alignment: _descriptor_1.alignment() - }); - return result_0; - } - _owner_0(context, partialProofData) { - return _descriptor_1.fromValue(Contract._query(context, - partialProofData, - [ - { dup: { n: 0 } }, - { idx: { cached: false, - pushPath: false, - path: [ - { tag: 'value', - value: { value: _descriptor_9.toValue(0n), - alignment: _descriptor_9.alignment() } }] } }, - { popeq: { cached: false, - result: undefined } }]).value); - } - _transferOwnership_0(context, partialProofData, newOwnerId_0) { - this._assertOnlyOwner_0(context, partialProofData); - __compactRuntime.assert(!this._equal_1(newOwnerId_0, new Uint8Array(32)), - 'SampleZOwnable: invalid id'); - this.__transferOwnership_0(context, partialProofData, newOwnerId_0); - return []; - } - _renounceOwnership_0(context, partialProofData) { - this._assertOnlyOwner_0(context, partialProofData); - Contract._query(context, - partialProofData, - [ - { push: { storage: false, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_9.toValue(0n), - alignment: _descriptor_9.alignment() }).encode() } }, - { push: { storage: true, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_1.toValue(new Uint8Array(32)), - alignment: _descriptor_1.alignment() }).encode() } }, - { ins: { cached: false, n: 1 } }]); - return []; - } - _assertOnlyOwner_0(context, partialProofData) { - const nonce_0 = this._secretNonce_0(context, partialProofData); - const callerAsEither_0 = { is_left: true, - left: - this._ownPublicKey_0(context, partialProofData), - right: - { bytes: - new Uint8Array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) } }; - const id_0 = this.__computeOwnerId_0(callerAsEither_0, nonce_0); - __compactRuntime.assert(this._equal_2(_descriptor_1.fromValue(Contract._query(context, - partialProofData, - [ - { dup: { n: 0 } }, - { idx: { cached: false, - pushPath: false, - path: [ - { tag: 'value', - value: { value: _descriptor_9.toValue(0n), - alignment: _descriptor_9.alignment() } }] } }, - { popeq: { cached: false, - result: undefined } }]).value), - this.__computeOwnerCommitment_0(context, - partialProofData, - id_0, - _descriptor_6.fromValue(Contract._query(context, - partialProofData, - [ - { dup: { n: 0 } }, - { idx: { cached: false, - pushPath: false, - path: [ - { tag: 'value', - value: { value: _descriptor_9.toValue(1n), - alignment: _descriptor_9.alignment() } }] } }, - { popeq: { cached: true, - result: undefined } }]).value))), - 'SampleZOwnable: caller is not the owner'); - return []; - } - __computeOwnerCommitment_0(context, partialProofData, id_0, counter_0) { - const value_0 = _descriptor_1.fromValue(Contract._query(context, - partialProofData, - [ - { dup: { n: 0 } }, - { idx: { cached: false, - pushPath: false, - path: [ - { tag: 'value', - value: { value: _descriptor_9.toValue(2n), - alignment: _descriptor_9.alignment() } }] } }, - { popeq: { cached: false, - result: undefined } }]).value); - return this._persistentHash_0([id_0, - value_0, - __compactRuntime.convertFieldToBytes(32, - counter_0, - 'SampleZOwnable.compact line 56 char 7'), - new Uint8Array([83, 97, 109, 112, 108, 101, 90, 79, 119, 110, 97, 98, 108, 101, 58, 115, 104, 105, 101, 108, 100, 58, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0])]); - } - __computeOwnerId_0(pk_0, nonce_0) { - __compactRuntime.assert(pk_0.is_left, - 'SampleZOwnable: contract address owners are not yet supported'); - return this._persistentHash_1([pk_0.left.bytes, nonce_0]); - } - __transferOwnership_0(context, partialProofData, newOwnerId_0) { - const tmp_0 = 1n; - Contract._query(context, - partialProofData, - [ - { idx: { cached: false, - pushPath: true, - path: [ - { tag: 'value', - value: { value: _descriptor_9.toValue(1n), - alignment: _descriptor_9.alignment() } }] } }, - { addi: { immediate: parseInt(__compactRuntime.valueToBigInt( - { value: _descriptor_5.toValue(tmp_0), - alignment: _descriptor_5.alignment() } - .value - )) } }, - { ins: { cached: true, n: 1 } }]); - const tmp_1 = this.__computeOwnerCommitment_0(context, - partialProofData, - newOwnerId_0, - _descriptor_6.fromValue(Contract._query(context, - partialProofData, - [ - { dup: { n: 0 } }, - { idx: { cached: false, - pushPath: false, - path: [ - { tag: 'value', - value: { value: _descriptor_9.toValue(1n), - alignment: _descriptor_9.alignment() } }] } }, - { popeq: { cached: true, - result: undefined } }]).value)); - Contract._query(context, - partialProofData, - [ - { push: { storage: false, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_9.toValue(0n), - alignment: _descriptor_9.alignment() }).encode() } }, - { push: { storage: true, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_1.toValue(tmp_1), - alignment: _descriptor_1.alignment() }).encode() } }, - { ins: { cached: false, n: 1 } }]); - return []; - } - _equal_0(x0, y0) { - if (!x0.every((x, i) => y0[i] === x)) { return false; } - return true; - } - _equal_1(x0, y0) { - if (!x0.every((x, i) => y0[i] === x)) { return false; } - return true; - } - _equal_2(x0, y0) { - if (!x0.every((x, i) => y0[i] === x)) { return false; } - return true; - } - static _query(context, partialProofData, prog) { - var res; - try { - res = context.transactionContext.query(prog, __compactRuntime.CostModel.dummyCostModel()); - } catch (err) { - throw new __compactRuntime.CompactError(err.toString()); - } - context.transactionContext = res.context; - var reads = res.events.filter((e) => e.tag === 'read'); - var i = 0; - partialProofData.publicTranscript = partialProofData.publicTranscript.concat(prog.map((op) => { - if(typeof(op) === 'object' && 'popeq' in op) { - return { popeq: { - ...op.popeq, - result: reads[i++].content, - } }; - } else { - return op; - } - })); - if(res.events.length == 1 && res.events[0].tag === 'read') { - return res.events[0].content; - } else { - return res.events; - } - } -} -function ledger(state) { - const context = { - originalState: state, - transactionContext: new __compactRuntime.QueryContext(state, __compactRuntime.dummyContractAddress()) - }; - const partialProofData = { - input: { value: [], alignment: [] }, - output: undefined, - publicTranscript: [], - privateTranscriptOutputs: [] - }; - return { - get _ownerCommitment() { - return _descriptor_1.fromValue(Contract._query(context, - partialProofData, - [ - { dup: { n: 0 } }, - { idx: { cached: false, - pushPath: false, - path: [ - { tag: 'value', - value: { value: _descriptor_9.toValue(0n), - alignment: _descriptor_9.alignment() } }] } }, - { popeq: { cached: false, - result: undefined } }]).value); - }, - get _counter() { - return _descriptor_6.fromValue(Contract._query(context, - partialProofData, - [ - { dup: { n: 0 } }, - { idx: { cached: false, - pushPath: false, - path: [ - { tag: 'value', - value: { value: _descriptor_9.toValue(1n), - alignment: _descriptor_9.alignment() } }] } }, - { popeq: { cached: true, - result: undefined } }]).value); - }, - get _instanceSalt() { - return _descriptor_1.fromValue(Contract._query(context, - partialProofData, - [ - { dup: { n: 0 } }, - { idx: { cached: false, - pushPath: false, - path: [ - { tag: 'value', - value: { value: _descriptor_9.toValue(2n), - alignment: _descriptor_9.alignment() } }] } }, - { popeq: { cached: false, - result: undefined } }]).value); - } - }; -} -const _emptyContext = { - originalState: new __compactRuntime.ContractState(), - transactionContext: new __compactRuntime.QueryContext(new __compactRuntime.ContractState().data, __compactRuntime.dummyContractAddress()) -}; -const _dummyContract = new Contract({ secretNonce: (...args) => undefined }); -const pureCircuits = { - _computeOwnerId: (...args_0) => { - if (args_0.length !== 2) { - throw new __compactRuntime.CompactError(`_computeOwnerId: expected 2 arguments (as invoked from Typescript), received ${args_0.length}`); - } - const pk_0 = args_0[0]; - const nonce_0 = args_0[1]; - if (!(typeof(pk_0) === 'object' && typeof(pk_0.is_left) === 'boolean' && typeof(pk_0.left) === 'object' && pk_0.left.bytes.buffer instanceof ArrayBuffer && pk_0.left.bytes.BYTES_PER_ELEMENT === 1 && pk_0.left.bytes.length === 32 && typeof(pk_0.right) === 'object' && pk_0.right.bytes.buffer instanceof ArrayBuffer && pk_0.right.bytes.BYTES_PER_ELEMENT === 1 && pk_0.right.bytes.length === 32)) { - __compactRuntime.type_error('_computeOwnerId', - 'argument 1', - 'SampleZOwnable.compact line 62 char 1', - 'struct Either>, right: struct ContractAddress>>', - pk_0) - } - if (!(nonce_0.buffer instanceof ArrayBuffer && nonce_0.BYTES_PER_ELEMENT === 1 && nonce_0.length === 32)) { - __compactRuntime.type_error('_computeOwnerId', - 'argument 2', - 'SampleZOwnable.compact line 62 char 1', - 'Bytes<32>', - nonce_0) - } - return _dummyContract.__computeOwnerId_0(pk_0, nonce_0); - } -}; -const contractReferenceLocations = { tag: 'publicLedgerArray', indices: { } }; -exports.Contract = Contract; -exports.ledger = ledger; -exports.pureCircuits = pureCircuits; -exports.contractReferenceLocations = contractReferenceLocations; -//# sourceMappingURL=index.cjs.map diff --git a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/contract/index.cjs.map b/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/contract/index.cjs.map deleted file mode 100644 index ac13053d..00000000 --- a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/contract/index.cjs.map +++ /dev/null @@ -1,8 +0,0 @@ -{ - "version": 3, - "file": "index.cjs", - "sourceRoot": "../../../../../", - "sources": ["test/fixtures/sample-contracts/SampleZOwnable.compact", "compiler/standard-library.compact"], - "names": [], - "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAcA;;;;;;;;;;;;;MAMA,AAAA,KAEC;;;;;;;;;;;;;;;;;;;;;;OAAA;MAED,AAAA,iBAIC;;;;;cAJgC,YAAqB;;;;;;;;;;;;;;;;;;yCAArB,YAAqB;;;;;;;;;mDAArB,YAAqB;;;OAIrD;MAED,AAAA,iBAGC;;;;;;;;;;;;;;;;;;;;;;OAAA;MAED,AAAA,eASC;;;;;;;;;;;;;;;;;;;;;;OAAA;MAED,AAAA,uBAaC;;;;;cAZC,IAAa;cACb,SAAiB;;;;;;;;;;;;;;;;;;;;;;;;;yCADjB,IAAa,+BACb,SAAiB;;;;;;;;;yDADjB,IAAa;yDACb,SAAiB;;;OAWlB;MAED,AAAA,eAMC;;OAAA;;;;;;;;;GAjDA;EAJD;;;;;UAAY,SAAkB;UAAE,cAAuB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IANvD;;;;;;;;;uDAA0C;IAC1C;;;;;;;;;uDAAgC;IAChC;;;;;;;;;uDAA8C;2CAKrC,SAAO;;IACd;;;;;;;yGAAyB,cAAY;;uDAAxB;0DACM,SAAO;;;;;;;GAC3B;EC8BD,AAAA,kBAAiC;oEAAA;;;EAAjC,AAAA,kBAAiC;oEAAA;;;EAwFjC,AAAA;;;;;;;;ED5HA,AAAA,cAAiC;;0DAAjC,WAAiC;;;;;;;;;;;;;;GAAA;EAQjC,AAAA,QAEC;mCADQ;;;;;;;;;;;sFAAgB;GACxB;EAED,AAAA,oBAIC,4BAJgC,YAAqB;;2CAE7C,YAAU;;0DACE,YAAU;;GAC9B;EAED,AAAA,oBAGC;;IADC;;;;;;;;;uDAAgB;;GACjB;EAED,AAAA,kBASC;UARO,OAAqB;UACrB,gBAIL;;;;;;UACK,IAA2C,2BAAtB,gBAAc,EAAE,OAAK;kEACzC;;;;;;;;;;;qHAAgB;;;0EAA4B,IAAE;kGAAE;;;;;;;;;;;qJAAQ;;;GAChE;EAED,AAAA,0BAaC,4BAZC,IAAa,EACb,SAAiB;UAEX,OAAqB,2BAAb;;;;;;;;;;;+FAAa;mCAGvB,IAAE;mCACF,OAAK;;wEACL,SAAO;;;GAIZ;EAED,AAAA,kBAMC,CALC,IAA+C,EAC/C,OAAgB;4BAET,IAAE;;mCACoC,IAAE,aAAa,OAAK;GAClE;EAED,AAAA,qBAGC,4BAH0B,YAAqB;UAC9C,KAAQ;IAAR;;;;;;;;;;2EAAA,KAAQ;;;;sDAAA;UACR,KAAgB;;kDAAoC,YAAU;0EAAG;;;;;;;;;;;6HAAQ;IAAzE;;;;;;;yGAAA,KAAgB;;uDAAA;;GACjB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAhED;qCAAA;;;;;;;;;;;wFAA0C;KAAA;IAC1C;qCAAA;;;;;;;;;;;wFAAgC;KAAA;IAChC;qCAAA;;;;;;;;;;;wFAA8C;KAAA;;;;;;;;;EAmD9C,AAAA,eAMC;;;;UALC,IAA+C;UAC/C,OAAgB;;;;;;;;;;;;;;;6CADhB,IAA+C,EAC/C,OAAgB;GAIjB;;;;;;;" -} diff --git a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/contract/index.d.cts b/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/contract/index.d.cts deleted file mode 100644 index 5404b06f..00000000 --- a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/contract/index.d.cts +++ /dev/null @@ -1,64 +0,0 @@ -import type * as __compactRuntime from '@midnight-ntwrk/compact-runtime'; - -export type ZswapCoinPublicKey = { bytes: Uint8Array }; - -export type ContractAddress = { bytes: Uint8Array }; - -export type Either = { is_left: boolean; left: A; right: B }; - -export type Witnesses = { - secretNonce(context: __compactRuntime.WitnessContext): [T, Uint8Array]; -} - -export type ImpureCircuits = { - owner(context: __compactRuntime.CircuitContext): __compactRuntime.CircuitResults; - transferOwnership(context: __compactRuntime.CircuitContext, - newOwnerId_0: Uint8Array): __compactRuntime.CircuitResults; - renounceOwnership(context: __compactRuntime.CircuitContext): __compactRuntime.CircuitResults; - assertOnlyOwner(context: __compactRuntime.CircuitContext): __compactRuntime.CircuitResults; - _computeOwnerCommitment(context: __compactRuntime.CircuitContext, - id_0: Uint8Array, - counter_0: bigint): __compactRuntime.CircuitResults; -} - -export type PureCircuits = { - _computeOwnerId(pk_0: Either, - nonce_0: Uint8Array): Uint8Array; -} - -export type Circuits = { - owner(context: __compactRuntime.CircuitContext): __compactRuntime.CircuitResults; - transferOwnership(context: __compactRuntime.CircuitContext, - newOwnerId_0: Uint8Array): __compactRuntime.CircuitResults; - renounceOwnership(context: __compactRuntime.CircuitContext): __compactRuntime.CircuitResults; - assertOnlyOwner(context: __compactRuntime.CircuitContext): __compactRuntime.CircuitResults; - _computeOwnerCommitment(context: __compactRuntime.CircuitContext, - id_0: Uint8Array, - counter_0: bigint): __compactRuntime.CircuitResults; - _computeOwnerId(context: __compactRuntime.CircuitContext, - pk_0: Either, - nonce_0: Uint8Array): __compactRuntime.CircuitResults; -} - -export type Ledger = { - readonly _ownerCommitment: Uint8Array; - readonly _counter: bigint; - readonly _instanceSalt: Uint8Array; -} - -export type ContractReferenceLocations = any; - -export declare const contractReferenceLocations : ContractReferenceLocations; - -export declare class Contract = Witnesses> { - witnesses: W; - circuits: Circuits; - impureCircuits: ImpureCircuits; - constructor(witnesses: W); - initialState(context: __compactRuntime.ConstructorContext, - ownerId_0: Uint8Array, - instanceSalt_0: Uint8Array): __compactRuntime.ConstructorResult; -} - -export declare function ledger(state: __compactRuntime.StateValue): Ledger; -export declare const pureCircuits: PureCircuits; diff --git a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/_computeOwnerCommitment.prover b/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/_computeOwnerCommitment.prover deleted file mode 100644 index 2c176ba8..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/_computeOwnerCommitment.prover and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/_computeOwnerCommitment.verifier b/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/_computeOwnerCommitment.verifier deleted file mode 100644 index 6ab1053f..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/_computeOwnerCommitment.verifier and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/assertOnlyOwner.prover b/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/assertOnlyOwner.prover deleted file mode 100644 index c9917d3e..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/assertOnlyOwner.prover and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/assertOnlyOwner.verifier b/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/assertOnlyOwner.verifier deleted file mode 100644 index 1c73f1d1..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/assertOnlyOwner.verifier and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/owner.prover b/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/owner.prover deleted file mode 100644 index b82d3265..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/owner.prover and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/owner.verifier b/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/owner.verifier deleted file mode 100644 index 1895d30c..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/owner.verifier and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/renounceOwnership.prover b/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/renounceOwnership.prover deleted file mode 100644 index 8f67fc39..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/renounceOwnership.prover and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/renounceOwnership.verifier b/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/renounceOwnership.verifier deleted file mode 100644 index 3c969b0e..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/renounceOwnership.verifier and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/transferOwnership.prover b/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/transferOwnership.prover deleted file mode 100644 index de4f0fb7..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/transferOwnership.prover and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/transferOwnership.verifier b/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/transferOwnership.verifier deleted file mode 100644 index ad5ab663..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/keys/transferOwnership.verifier and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/_computeOwnerCommitment.bzkir b/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/_computeOwnerCommitment.bzkir deleted file mode 100644 index 9395efaf..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/_computeOwnerCommitment.bzkir and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/_computeOwnerCommitment.zkir b/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/_computeOwnerCommitment.zkir deleted file mode 100644 index af60338a..00000000 --- a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/_computeOwnerCommitment.zkir +++ /dev/null @@ -1,37 +0,0 @@ -{ - "version": { "major": 2, "minor": 0 }, - "do_communications_commitment": true, - "num_inputs": 3, - "instructions": [ - { "op": "constrain_bits", "var": 0, "bits": 8 }, - { "op": "constrain_bits", "var": 1, "bits": 248 }, - { "op": "constrain_bits", "var": 2, "bits": 64 }, - { "op": "load_imm", "imm": "01" }, - { "op": "load_imm", "imm": "30" }, - { "op": "declare_pub_input", "var": 4 }, - { "op": "pi_skip", "guard": 3, "count": 1 }, - { "op": "load_imm", "imm": "50" }, - { "op": "load_imm", "imm": "02" }, - { "op": "declare_pub_input", "var": 5 }, - { "op": "declare_pub_input", "var": 3 }, - { "op": "declare_pub_input", "var": 3 }, - { "op": "declare_pub_input", "var": 6 }, - { "op": "pi_skip", "guard": 3, "count": 4 }, - { "op": "public_input", "guard": null }, - { "op": "public_input", "guard": null }, - { "op": "load_imm", "imm": "20" }, - { "op": "load_imm", "imm": "0C" }, - { "op": "declare_pub_input", "var": 10 }, - { "op": "declare_pub_input", "var": 3 }, - { "op": "declare_pub_input", "var": 9 }, - { "op": "declare_pub_input", "var": 7 }, - { "op": "declare_pub_input", "var": 8 }, - { "op": "pi_skip", "guard": 3, "count": 5 }, - { "op": "div_mod_power_of_two", "var": 2, "bits": 248 }, - { "op": "load_imm", "imm": "00" }, - { "op": "load_imm", "imm": "53616D706C655A4F776E61626C653A736869656C643A" }, - { "op": "persistent_hash", "alignment": [{ "tag": "atom", "value": { "length": 32, "tag": "bytes" } }, { "tag": "atom", "value": { "length": 32, "tag": "bytes" } }, { "tag": "atom", "value": { "length": 32, "tag": "bytes" } }, { "tag": "atom", "value": { "length": 32, "tag": "bytes" } }], "inputs": [0, 1, 7, 8, 11, 12, 13, 14] }, - { "op": "output", "var": 15 }, - { "op": "output", "var": 16 } - ] -} diff --git a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/assertOnlyOwner.bzkir b/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/assertOnlyOwner.bzkir deleted file mode 100644 index 31503d09..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/assertOnlyOwner.bzkir and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/assertOnlyOwner.zkir b/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/assertOnlyOwner.zkir deleted file mode 100644 index 2d5db59e..00000000 --- a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/assertOnlyOwner.zkir +++ /dev/null @@ -1,75 +0,0 @@ -{ - "version": { "major": 2, "minor": 0 }, - "do_communications_commitment": true, - "num_inputs": 0, - "instructions": [ - { "op": "load_imm", "imm": "01" }, - { "op": "private_input", "guard": null }, - { "op": "constrain_bits", "var": 1, "bits": 8 }, - { "op": "private_input", "guard": null }, - { "op": "constrain_bits", "var": 2, "bits": 248 }, - { "op": "private_input", "guard": null }, - { "op": "constrain_bits", "var": 3, "bits": 8 }, - { "op": "private_input", "guard": null }, - { "op": "constrain_bits", "var": 4, "bits": 248 }, - { "op": "persistent_hash", "alignment": [{ "tag": "atom", "value": { "length": 32, "tag": "bytes" } }, { "tag": "atom", "value": { "length": 32, "tag": "bytes" } }], "inputs": [3, 4, 1, 2] }, - { "op": "load_imm", "imm": "30" }, - { "op": "declare_pub_input", "var": 7 }, - { "op": "pi_skip", "guard": 0, "count": 1 }, - { "op": "load_imm", "imm": "50" }, - { "op": "load_imm", "imm": "00" }, - { "op": "declare_pub_input", "var": 8 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 9 }, - { "op": "pi_skip", "guard": 0, "count": 4 }, - { "op": "public_input", "guard": null }, - { "op": "public_input", "guard": null }, - { "op": "load_imm", "imm": "20" }, - { "op": "load_imm", "imm": "0C" }, - { "op": "declare_pub_input", "var": 13 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 12 }, - { "op": "declare_pub_input", "var": 10 }, - { "op": "declare_pub_input", "var": 11 }, - { "op": "pi_skip", "guard": 0, "count": 5 }, - { "op": "declare_pub_input", "var": 7 }, - { "op": "pi_skip", "guard": 0, "count": 1 }, - { "op": "declare_pub_input", "var": 8 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "pi_skip", "guard": 0, "count": 4 }, - { "op": "public_input", "guard": null }, - { "op": "load_imm", "imm": "08" }, - { "op": "load_imm", "imm": "0D" }, - { "op": "declare_pub_input", "var": 16 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 15 }, - { "op": "declare_pub_input", "var": 14 }, - { "op": "pi_skip", "guard": 0, "count": 4 }, - { "op": "declare_pub_input", "var": 7 }, - { "op": "pi_skip", "guard": 0, "count": 1 }, - { "op": "load_imm", "imm": "02" }, - { "op": "declare_pub_input", "var": 8 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 17 }, - { "op": "pi_skip", "guard": 0, "count": 4 }, - { "op": "public_input", "guard": null }, - { "op": "public_input", "guard": null }, - { "op": "declare_pub_input", "var": 13 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 12 }, - { "op": "declare_pub_input", "var": 18 }, - { "op": "declare_pub_input", "var": 19 }, - { "op": "pi_skip", "guard": 0, "count": 5 }, - { "op": "div_mod_power_of_two", "var": 14, "bits": 248 }, - { "op": "load_imm", "imm": "53616D706C655A4F776E61626C653A736869656C643A" }, - { "op": "persistent_hash", "alignment": [{ "tag": "atom", "value": { "length": 32, "tag": "bytes" } }, { "tag": "atom", "value": { "length": 32, "tag": "bytes" } }, { "tag": "atom", "value": { "length": 32, "tag": "bytes" } }, { "tag": "atom", "value": { "length": 32, "tag": "bytes" } }], "inputs": [5, 6, 18, 19, 20, 21, 9, 22] }, - { "op": "test_eq", "a": 10, "b": 23 }, - { "op": "test_eq", "a": 11, "b": 24 }, - { "op": "cond_select", "bit": 25, "a": 26, "b": 9 }, - { "op": "assert", "cond": 27 } - ] -} diff --git a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/owner.bzkir b/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/owner.bzkir deleted file mode 100644 index 38b14bfd..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/owner.bzkir and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/owner.zkir b/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/owner.zkir deleted file mode 100644 index 50ebbfc5..00000000 --- a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/owner.zkir +++ /dev/null @@ -1,30 +0,0 @@ -{ - "version": { "major": 2, "minor": 0 }, - "do_communications_commitment": true, - "num_inputs": 0, - "instructions": [ - { "op": "load_imm", "imm": "01" }, - { "op": "load_imm", "imm": "30" }, - { "op": "declare_pub_input", "var": 1 }, - { "op": "pi_skip", "guard": 0, "count": 1 }, - { "op": "load_imm", "imm": "50" }, - { "op": "load_imm", "imm": "00" }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 3 }, - { "op": "pi_skip", "guard": 0, "count": 4 }, - { "op": "public_input", "guard": null }, - { "op": "public_input", "guard": null }, - { "op": "load_imm", "imm": "20" }, - { "op": "load_imm", "imm": "0C" }, - { "op": "declare_pub_input", "var": 7 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 6 }, - { "op": "declare_pub_input", "var": 4 }, - { "op": "declare_pub_input", "var": 5 }, - { "op": "pi_skip", "guard": 0, "count": 5 }, - { "op": "output", "var": 4 }, - { "op": "output", "var": 5 } - ] -} diff --git a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/renounceOwnership.bzkir b/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/renounceOwnership.bzkir deleted file mode 100644 index 0eb1da1e..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/renounceOwnership.bzkir and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/renounceOwnership.zkir b/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/renounceOwnership.zkir deleted file mode 100644 index ce621b6a..00000000 --- a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/renounceOwnership.zkir +++ /dev/null @@ -1,93 +0,0 @@ -{ - "version": { "major": 2, "minor": 0 }, - "do_communications_commitment": true, - "num_inputs": 0, - "instructions": [ - { "op": "load_imm", "imm": "01" }, - { "op": "private_input", "guard": null }, - { "op": "constrain_bits", "var": 1, "bits": 8 }, - { "op": "private_input", "guard": null }, - { "op": "constrain_bits", "var": 2, "bits": 248 }, - { "op": "private_input", "guard": null }, - { "op": "constrain_bits", "var": 3, "bits": 8 }, - { "op": "private_input", "guard": null }, - { "op": "constrain_bits", "var": 4, "bits": 248 }, - { "op": "persistent_hash", "alignment": [{ "tag": "atom", "value": { "length": 32, "tag": "bytes" } }, { "tag": "atom", "value": { "length": 32, "tag": "bytes" } }], "inputs": [3, 4, 1, 2] }, - { "op": "load_imm", "imm": "30" }, - { "op": "declare_pub_input", "var": 7 }, - { "op": "pi_skip", "guard": 0, "count": 1 }, - { "op": "load_imm", "imm": "50" }, - { "op": "load_imm", "imm": "00" }, - { "op": "declare_pub_input", "var": 8 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 9 }, - { "op": "pi_skip", "guard": 0, "count": 4 }, - { "op": "public_input", "guard": null }, - { "op": "public_input", "guard": null }, - { "op": "load_imm", "imm": "20" }, - { "op": "load_imm", "imm": "0C" }, - { "op": "declare_pub_input", "var": 13 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 12 }, - { "op": "declare_pub_input", "var": 10 }, - { "op": "declare_pub_input", "var": 11 }, - { "op": "pi_skip", "guard": 0, "count": 5 }, - { "op": "declare_pub_input", "var": 7 }, - { "op": "pi_skip", "guard": 0, "count": 1 }, - { "op": "declare_pub_input", "var": 8 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "pi_skip", "guard": 0, "count": 4 }, - { "op": "public_input", "guard": null }, - { "op": "load_imm", "imm": "08" }, - { "op": "load_imm", "imm": "0D" }, - { "op": "declare_pub_input", "var": 16 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 15 }, - { "op": "declare_pub_input", "var": 14 }, - { "op": "pi_skip", "guard": 0, "count": 4 }, - { "op": "declare_pub_input", "var": 7 }, - { "op": "pi_skip", "guard": 0, "count": 1 }, - { "op": "load_imm", "imm": "02" }, - { "op": "declare_pub_input", "var": 8 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 17 }, - { "op": "pi_skip", "guard": 0, "count": 4 }, - { "op": "public_input", "guard": null }, - { "op": "public_input", "guard": null }, - { "op": "declare_pub_input", "var": 13 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 12 }, - { "op": "declare_pub_input", "var": 18 }, - { "op": "declare_pub_input", "var": 19 }, - { "op": "pi_skip", "guard": 0, "count": 5 }, - { "op": "div_mod_power_of_two", "var": 14, "bits": 248 }, - { "op": "load_imm", "imm": "53616D706C655A4F776E61626C653A736869656C643A" }, - { "op": "persistent_hash", "alignment": [{ "tag": "atom", "value": { "length": 32, "tag": "bytes" } }, { "tag": "atom", "value": { "length": 32, "tag": "bytes" } }, { "tag": "atom", "value": { "length": 32, "tag": "bytes" } }, { "tag": "atom", "value": { "length": 32, "tag": "bytes" } }], "inputs": [5, 6, 18, 19, 20, 21, 9, 22] }, - { "op": "test_eq", "a": 10, "b": 23 }, - { "op": "test_eq", "a": 11, "b": 24 }, - { "op": "cond_select", "bit": 25, "a": 26, "b": 9 }, - { "op": "assert", "cond": 27 }, - { "op": "load_imm", "imm": "10" }, - { "op": "declare_pub_input", "var": 28 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 9 }, - { "op": "pi_skip", "guard": 0, "count": 5 }, - { "op": "load_imm", "imm": "11" }, - { "op": "declare_pub_input", "var": 29 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 12 }, - { "op": "declare_pub_input", "var": 9 }, - { "op": "declare_pub_input", "var": 9 }, - { "op": "pi_skip", "guard": 0, "count": 6 }, - { "op": "load_imm", "imm": "91" }, - { "op": "declare_pub_input", "var": 30 }, - { "op": "pi_skip", "guard": 0, "count": 1 } - ] -} diff --git a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/transferOwnership.bzkir b/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/transferOwnership.bzkir deleted file mode 100644 index 173464ee..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/transferOwnership.bzkir and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/transferOwnership.zkir b/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/transferOwnership.zkir deleted file mode 100644 index 4f31458b..00000000 --- a/packages/simulator/test/fixtures/test-artifacts/SampleZOwnable/zkir/transferOwnership.zkir +++ /dev/null @@ -1,144 +0,0 @@ -{ - "version": { "major": 2, "minor": 0 }, - "do_communications_commitment": true, - "num_inputs": 2, - "instructions": [ - { "op": "constrain_bits", "var": 0, "bits": 8 }, - { "op": "constrain_bits", "var": 1, "bits": 248 }, - { "op": "load_imm", "imm": "01" }, - { "op": "private_input", "guard": null }, - { "op": "constrain_bits", "var": 3, "bits": 8 }, - { "op": "private_input", "guard": null }, - { "op": "constrain_bits", "var": 4, "bits": 248 }, - { "op": "private_input", "guard": null }, - { "op": "constrain_bits", "var": 5, "bits": 8 }, - { "op": "private_input", "guard": null }, - { "op": "constrain_bits", "var": 6, "bits": 248 }, - { "op": "persistent_hash", "alignment": [{ "tag": "atom", "value": { "length": 32, "tag": "bytes" } }, { "tag": "atom", "value": { "length": 32, "tag": "bytes" } }], "inputs": [5, 6, 3, 4] }, - { "op": "load_imm", "imm": "30" }, - { "op": "declare_pub_input", "var": 9 }, - { "op": "pi_skip", "guard": 2, "count": 1 }, - { "op": "load_imm", "imm": "50" }, - { "op": "load_imm", "imm": "00" }, - { "op": "declare_pub_input", "var": 10 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 11 }, - { "op": "pi_skip", "guard": 2, "count": 4 }, - { "op": "public_input", "guard": null }, - { "op": "public_input", "guard": null }, - { "op": "load_imm", "imm": "20" }, - { "op": "load_imm", "imm": "0C" }, - { "op": "declare_pub_input", "var": 15 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 14 }, - { "op": "declare_pub_input", "var": 12 }, - { "op": "declare_pub_input", "var": 13 }, - { "op": "pi_skip", "guard": 2, "count": 5 }, - { "op": "declare_pub_input", "var": 9 }, - { "op": "pi_skip", "guard": 2, "count": 1 }, - { "op": "declare_pub_input", "var": 10 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "pi_skip", "guard": 2, "count": 4 }, - { "op": "public_input", "guard": null }, - { "op": "load_imm", "imm": "08" }, - { "op": "load_imm", "imm": "0D" }, - { "op": "declare_pub_input", "var": 18 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 17 }, - { "op": "declare_pub_input", "var": 16 }, - { "op": "pi_skip", "guard": 2, "count": 4 }, - { "op": "declare_pub_input", "var": 9 }, - { "op": "pi_skip", "guard": 2, "count": 1 }, - { "op": "load_imm", "imm": "02" }, - { "op": "declare_pub_input", "var": 10 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 19 }, - { "op": "pi_skip", "guard": 2, "count": 4 }, - { "op": "public_input", "guard": null }, - { "op": "public_input", "guard": null }, - { "op": "declare_pub_input", "var": 15 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 14 }, - { "op": "declare_pub_input", "var": 20 }, - { "op": "declare_pub_input", "var": 21 }, - { "op": "pi_skip", "guard": 2, "count": 5 }, - { "op": "div_mod_power_of_two", "var": 16, "bits": 248 }, - { "op": "load_imm", "imm": "53616D706C655A4F776E61626C653A736869656C643A" }, - { "op": "persistent_hash", "alignment": [{ "tag": "atom", "value": { "length": 32, "tag": "bytes" } }, { "tag": "atom", "value": { "length": 32, "tag": "bytes" } }, { "tag": "atom", "value": { "length": 32, "tag": "bytes" } }, { "tag": "atom", "value": { "length": 32, "tag": "bytes" } }], "inputs": [7, 8, 20, 21, 22, 23, 11, 24] }, - { "op": "test_eq", "a": 12, "b": 25 }, - { "op": "test_eq", "a": 13, "b": 26 }, - { "op": "cond_select", "bit": 27, "a": 28, "b": 11 }, - { "op": "assert", "cond": 29 }, - { "op": "test_eq", "a": 0, "b": 11 }, - { "op": "test_eq", "a": 1, "b": 11 }, - { "op": "cond_select", "bit": 30, "a": 31, "b": 11 }, - { "op": "cond_select", "bit": 32, "a": 11, "b": 2 }, - { "op": "assert", "cond": 33 }, - { "op": "load_imm", "imm": "70" }, - { "op": "declare_pub_input", "var": 34 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "pi_skip", "guard": 2, "count": 4 }, - { "op": "load_imm", "imm": "0E" }, - { "op": "declare_pub_input", "var": 35 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "pi_skip", "guard": 2, "count": 2 }, - { "op": "load_imm", "imm": "A1" }, - { "op": "declare_pub_input", "var": 36 }, - { "op": "pi_skip", "guard": 2, "count": 1 }, - { "op": "declare_pub_input", "var": 9 }, - { "op": "pi_skip", "guard": 2, "count": 1 }, - { "op": "declare_pub_input", "var": 10 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "pi_skip", "guard": 2, "count": 4 }, - { "op": "public_input", "guard": null }, - { "op": "declare_pub_input", "var": 18 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 17 }, - { "op": "declare_pub_input", "var": 37 }, - { "op": "pi_skip", "guard": 2, "count": 4 }, - { "op": "declare_pub_input", "var": 9 }, - { "op": "pi_skip", "guard": 2, "count": 1 }, - { "op": "declare_pub_input", "var": 10 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 19 }, - { "op": "pi_skip", "guard": 2, "count": 4 }, - { "op": "public_input", "guard": null }, - { "op": "public_input", "guard": null }, - { "op": "declare_pub_input", "var": 15 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 14 }, - { "op": "declare_pub_input", "var": 38 }, - { "op": "declare_pub_input", "var": 39 }, - { "op": "pi_skip", "guard": 2, "count": 5 }, - { "op": "div_mod_power_of_two", "var": 37, "bits": 248 }, - { "op": "load_imm", "imm": "53616D706C655A4F776E61626C653A736869656C643A" }, - { "op": "persistent_hash", "alignment": [{ "tag": "atom", "value": { "length": 32, "tag": "bytes" } }, { "tag": "atom", "value": { "length": 32, "tag": "bytes" } }, { "tag": "atom", "value": { "length": 32, "tag": "bytes" } }, { "tag": "atom", "value": { "length": 32, "tag": "bytes" } }], "inputs": [0, 1, 38, 39, 40, 41, 11, 42] }, - { "op": "load_imm", "imm": "10" }, - { "op": "declare_pub_input", "var": 45 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 11 }, - { "op": "pi_skip", "guard": 2, "count": 5 }, - { "op": "load_imm", "imm": "11" }, - { "op": "declare_pub_input", "var": 46 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 14 }, - { "op": "declare_pub_input", "var": 43 }, - { "op": "declare_pub_input", "var": 44 }, - { "op": "pi_skip", "guard": 2, "count": 6 }, - { "op": "load_imm", "imm": "91" }, - { "op": "declare_pub_input", "var": 47 }, - { "op": "pi_skip", "guard": 2, "count": 1 } - ] -} diff --git a/packages/simulator/test/fixtures/test-artifacts/Simple/compiler/contract-info.json b/packages/simulator/test/fixtures/test-artifacts/Simple/compiler/contract-info.json deleted file mode 100644 index 8191238b..00000000 --- a/packages/simulator/test/fixtures/test-artifacts/Simple/compiler/contract-info.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "circuits": [ - { - "name": "setVal", - "pure": false, - "arguments": [ - { - "name": "n", - "type": { - "type-name": "Field" - } - } - ], - "result-type": { - "type-name": "Tuple", - "types": [ - ] - } - }, - { - "name": "getVal", - "pure": false, - "arguments": [ - ], - "result-type": { - "type-name": "Field" - } - } - ], - "witnesses": [ - ], - "contracts": [ - ] -} diff --git a/packages/simulator/test/fixtures/test-artifacts/Simple/contract/index.cjs b/packages/simulator/test/fixtures/test-artifacts/Simple/contract/index.cjs deleted file mode 100644 index c6f82f2c..00000000 --- a/packages/simulator/test/fixtures/test-artifacts/Simple/contract/index.cjs +++ /dev/null @@ -1,261 +0,0 @@ -'use strict'; -const __compactRuntime = require('@midnight-ntwrk/compact-runtime'); -const expectedRuntimeVersionString = '0.9.0'; -const expectedRuntimeVersion = expectedRuntimeVersionString.split('-')[0].split('.').map(Number); -const actualRuntimeVersion = __compactRuntime.versionString.split('-')[0].split('.').map(Number); -if (expectedRuntimeVersion[0] != actualRuntimeVersion[0] - || (actualRuntimeVersion[0] == 0 && expectedRuntimeVersion[1] != actualRuntimeVersion[1]) - || expectedRuntimeVersion[1] > actualRuntimeVersion[1] - || (expectedRuntimeVersion[1] == actualRuntimeVersion[1] && expectedRuntimeVersion[2] > actualRuntimeVersion[2])) - throw new __compactRuntime.CompactError(`Version mismatch: compiled code expects ${expectedRuntimeVersionString}, runtime is ${__compactRuntime.versionString}`); -{ const MAX_FIELD = 52435875175126190479447740508185965837690552500527637822603658699938581184512n; - if (__compactRuntime.MAX_FIELD !== MAX_FIELD) - throw new __compactRuntime.CompactError(`compiler thinks maximum field value is ${MAX_FIELD}; run time thinks it is ${__compactRuntime.MAX_FIELD}`) -} - -const _descriptor_0 = new __compactRuntime.CompactTypeField(); - -const _descriptor_1 = new __compactRuntime.CompactTypeUnsignedInteger(18446744073709551615n, 8); - -const _descriptor_2 = new __compactRuntime.CompactTypeBoolean(); - -const _descriptor_3 = new __compactRuntime.CompactTypeBytes(32); - -class _ContractAddress_0 { - alignment() { - return _descriptor_3.alignment(); - } - fromValue(value_0) { - return { - bytes: _descriptor_3.fromValue(value_0) - } - } - toValue(value_0) { - return _descriptor_3.toValue(value_0.bytes); - } -} - -const _descriptor_4 = new _ContractAddress_0(); - -const _descriptor_5 = new __compactRuntime.CompactTypeUnsignedInteger(255n, 1); - -const _descriptor_6 = new __compactRuntime.CompactTypeUnsignedInteger(340282366920938463463374607431768211455n, 16); - -class Contract { - witnesses; - constructor(...args_0) { - if (args_0.length !== 1) { - throw new __compactRuntime.CompactError(`Contract constructor: expected 1 argument, received ${args_0.length}`); - } - const witnesses_0 = args_0[0]; - if (typeof(witnesses_0) !== 'object') { - throw new __compactRuntime.CompactError('first (witnesses) argument to Contract constructor is not an object'); - } - this.witnesses = witnesses_0; - this.circuits = { - setVal: (...args_1) => { - if (args_1.length !== 2) { - throw new __compactRuntime.CompactError(`setVal: expected 2 arguments (as invoked from Typescript), received ${args_1.length}`); - } - const contextOrig_0 = args_1[0]; - const n_0 = args_1[1]; - if (!(typeof(contextOrig_0) === 'object' && contextOrig_0.originalState != undefined && contextOrig_0.transactionContext != undefined)) { - __compactRuntime.type_error('setVal', - 'argument 1 (as invoked from Typescript)', - 'Simple.compact line 8 char 1', - 'CircuitContext', - contextOrig_0) - } - if (!(typeof(n_0) === 'bigint' && n_0 >= 0 && n_0 <= __compactRuntime.MAX_FIELD)) { - __compactRuntime.type_error('setVal', - 'argument 1 (argument 2 as invoked from Typescript)', - 'Simple.compact line 8 char 1', - 'Field', - n_0) - } - const context = { ...contextOrig_0 }; - const partialProofData = { - input: { - value: _descriptor_0.toValue(n_0), - alignment: _descriptor_0.alignment() - }, - output: undefined, - publicTranscript: [], - privateTranscriptOutputs: [] - }; - const result_0 = this._setVal_0(context, partialProofData, n_0); - partialProofData.output = { value: [], alignment: [] }; - return { result: result_0, context: context, proofData: partialProofData }; - }, - getVal: (...args_1) => { - if (args_1.length !== 1) { - throw new __compactRuntime.CompactError(`getVal: expected 1 argument (as invoked from Typescript), received ${args_1.length}`); - } - const contextOrig_0 = args_1[0]; - if (!(typeof(contextOrig_0) === 'object' && contextOrig_0.originalState != undefined && contextOrig_0.transactionContext != undefined)) { - __compactRuntime.type_error('getVal', - 'argument 1 (as invoked from Typescript)', - 'Simple.compact line 12 char 1', - 'CircuitContext', - contextOrig_0) - } - const context = { ...contextOrig_0 }; - const partialProofData = { - input: { value: [], alignment: [] }, - output: undefined, - publicTranscript: [], - privateTranscriptOutputs: [] - }; - const result_0 = this._getVal_0(context, partialProofData); - partialProofData.output = { value: _descriptor_0.toValue(result_0), alignment: _descriptor_0.alignment() }; - return { result: result_0, context: context, proofData: partialProofData }; - } - }; - this.impureCircuits = { - setVal: this.circuits.setVal, - getVal: this.circuits.getVal - }; - } - initialState(...args_0) { - if (args_0.length !== 1) { - throw new __compactRuntime.CompactError(`Contract state constructor: expected 1 argument (as invoked from Typescript), received ${args_0.length}`); - } - const constructorContext_0 = args_0[0]; - if (typeof(constructorContext_0) !== 'object') { - throw new __compactRuntime.CompactError(`Contract state constructor: expected 'constructorContext' in argument 1 (as invoked from Typescript) to be an object`); - } - if (!('initialZswapLocalState' in constructorContext_0)) { - throw new __compactRuntime.CompactError(`Contract state constructor: expected 'initialZswapLocalState' in argument 1 (as invoked from Typescript)`); - } - if (typeof(constructorContext_0.initialZswapLocalState) !== 'object') { - throw new __compactRuntime.CompactError(`Contract state constructor: expected 'initialZswapLocalState' in argument 1 (as invoked from Typescript) to be an object`); - } - const state_0 = new __compactRuntime.ContractState(); - let stateValue_0 = __compactRuntime.StateValue.newArray(); - stateValue_0 = stateValue_0.arrayPush(__compactRuntime.StateValue.newNull()); - state_0.data = stateValue_0; - state_0.setOperation('setVal', new __compactRuntime.ContractOperation()); - state_0.setOperation('getVal', new __compactRuntime.ContractOperation()); - const context = { - originalState: state_0, - currentPrivateState: constructorContext_0.initialPrivateState, - currentZswapLocalState: constructorContext_0.initialZswapLocalState, - transactionContext: new __compactRuntime.QueryContext(state_0.data, __compactRuntime.dummyContractAddress()) - }; - const partialProofData = { - input: { value: [], alignment: [] }, - output: undefined, - publicTranscript: [], - privateTranscriptOutputs: [] - }; - Contract._query(context, - partialProofData, - [ - { push: { storage: false, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_5.toValue(0n), - alignment: _descriptor_5.alignment() }).encode() } }, - { push: { storage: true, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_0.toValue(0n), - alignment: _descriptor_0.alignment() }).encode() } }, - { ins: { cached: false, n: 1 } }]); - state_0.data = context.transactionContext.state; - return { - currentContractState: state_0, - currentPrivateState: context.currentPrivateState, - currentZswapLocalState: context.currentZswapLocalState - } - } - _setVal_0(context, partialProofData, n_0) { - Contract._query(context, - partialProofData, - [ - { push: { storage: false, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_5.toValue(0n), - alignment: _descriptor_5.alignment() }).encode() } }, - { push: { storage: true, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_0.toValue(n_0), - alignment: _descriptor_0.alignment() }).encode() } }, - { ins: { cached: false, n: 1 } }]); - return []; - } - _getVal_0(context, partialProofData) { - return _descriptor_0.fromValue(Contract._query(context, - partialProofData, - [ - { dup: { n: 0 } }, - { idx: { cached: false, - pushPath: false, - path: [ - { tag: 'value', - value: { value: _descriptor_5.toValue(0n), - alignment: _descriptor_5.alignment() } }] } }, - { popeq: { cached: false, - result: undefined } }]).value); - } - static _query(context, partialProofData, prog) { - var res; - try { - res = context.transactionContext.query(prog, __compactRuntime.CostModel.dummyCostModel()); - } catch (err) { - throw new __compactRuntime.CompactError(err.toString()); - } - context.transactionContext = res.context; - var reads = res.events.filter((e) => e.tag === 'read'); - var i = 0; - partialProofData.publicTranscript = partialProofData.publicTranscript.concat(prog.map((op) => { - if(typeof(op) === 'object' && 'popeq' in op) { - return { popeq: { - ...op.popeq, - result: reads[i++].content, - } }; - } else { - return op; - } - })); - if(res.events.length == 1 && res.events[0].tag === 'read') { - return res.events[0].content; - } else { - return res.events; - } - } -} -function ledger(state) { - const context = { - originalState: state, - transactionContext: new __compactRuntime.QueryContext(state, __compactRuntime.dummyContractAddress()) - }; - const partialProofData = { - input: { value: [], alignment: [] }, - output: undefined, - publicTranscript: [], - privateTranscriptOutputs: [] - }; - return { - get _val() { - return _descriptor_0.fromValue(Contract._query(context, - partialProofData, - [ - { dup: { n: 0 } }, - { idx: { cached: false, - pushPath: false, - path: [ - { tag: 'value', - value: { value: _descriptor_5.toValue(0n), - alignment: _descriptor_5.alignment() } }] } }, - { popeq: { cached: false, - result: undefined } }]).value); - } - }; -} -const _emptyContext = { - originalState: new __compactRuntime.ContractState(), - transactionContext: new __compactRuntime.QueryContext(new __compactRuntime.ContractState().data, __compactRuntime.dummyContractAddress()) -}; -const _dummyContract = new Contract({ }); -const pureCircuits = {}; -const contractReferenceLocations = { tag: 'publicLedgerArray', indices: { } }; -exports.Contract = Contract; -exports.ledger = ledger; -exports.pureCircuits = pureCircuits; -exports.contractReferenceLocations = contractReferenceLocations; -//# sourceMappingURL=index.cjs.map diff --git a/packages/simulator/test/fixtures/test-artifacts/Simple/contract/index.cjs.map b/packages/simulator/test/fixtures/test-artifacts/Simple/contract/index.cjs.map deleted file mode 100644 index 5b3e8d27..00000000 --- a/packages/simulator/test/fixtures/test-artifacts/Simple/contract/index.cjs.map +++ /dev/null @@ -1,8 +0,0 @@ -{ - "version": 3, - "file": "index.cjs", - "sourceRoot": "../../../../../", - "sources": ["test/fixtures/sample-contracts/Simple.compact"], - "names": [], - "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAAA;;;;;;;;;;MAOA,AAAA,MAEC;;;;;cAFqB,GAAQ;;;;;;;;;;;;;;;;;;yCAAR,GAAQ;;;;;;;mEAAR,GAAQ;;;OAE7B;MAED,AAAA,MAEC;;;;;;;;;;;;;;;;;;;;;;OAAA;;;;;;GACA;EAdD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAKA;;;;;;;;;uDAA0B;;;;;;;GASzB;EAPD,AAAA,SAEC,4BAFqB,GAAQ;IAC5B;;;;;;;yGAAgB,GAAC;;uDAAb;;GACL;EAED,AAAA,SAEC;mCADQ;;;;;;;;;;;sFAAI;GACZ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IARD;qCAAA;;;;;;;;;;;wFAA0B;KAAA;;;;;;;;;;;;;;" -} diff --git a/packages/simulator/test/fixtures/test-artifacts/Simple/contract/index.d.cts b/packages/simulator/test/fixtures/test-artifacts/Simple/contract/index.d.cts deleted file mode 100644 index b9e089a9..00000000 --- a/packages/simulator/test/fixtures/test-artifacts/Simple/contract/index.d.cts +++ /dev/null @@ -1,44 +0,0 @@ -import type * as __compactRuntime from '@midnight-ntwrk/compact-runtime'; - -export type ZswapCoinPublicKey = { bytes: Uint8Array }; - -export type ContractAddress = { bytes: Uint8Array }; - -export type Either = { is_left: boolean; left: A; right: B }; - -export type Maybe = { is_some: boolean; value: T }; - -export type Witnesses = { -} - -export type ImpureCircuits = { - setVal(context: __compactRuntime.CircuitContext, n_0: bigint): __compactRuntime.CircuitResults; - getVal(context: __compactRuntime.CircuitContext): __compactRuntime.CircuitResults; -} - -export type PureCircuits = { -} - -export type Circuits = { - setVal(context: __compactRuntime.CircuitContext, n_0: bigint): __compactRuntime.CircuitResults; - getVal(context: __compactRuntime.CircuitContext): __compactRuntime.CircuitResults; -} - -export type Ledger = { - readonly _val: bigint; -} - -export type ContractReferenceLocations = any; - -export declare const contractReferenceLocations : ContractReferenceLocations; - -export declare class Contract = Witnesses> { - witnesses: W; - circuits: Circuits; - impureCircuits: ImpureCircuits; - constructor(witnesses: W); - initialState(context: __compactRuntime.ConstructorContext): __compactRuntime.ConstructorResult; -} - -export declare function ledger(state: __compactRuntime.StateValue): Ledger; -export declare const pureCircuits: PureCircuits; diff --git a/packages/simulator/test/fixtures/test-artifacts/Simple/keys/getVal.prover b/packages/simulator/test/fixtures/test-artifacts/Simple/keys/getVal.prover deleted file mode 100644 index 84ddcc6f..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/Simple/keys/getVal.prover and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/Simple/keys/getVal.verifier b/packages/simulator/test/fixtures/test-artifacts/Simple/keys/getVal.verifier deleted file mode 100644 index 5a60c135..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/Simple/keys/getVal.verifier and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/Simple/keys/setVal.prover b/packages/simulator/test/fixtures/test-artifacts/Simple/keys/setVal.prover deleted file mode 100644 index b0636044..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/Simple/keys/setVal.prover and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/Simple/keys/setVal.verifier b/packages/simulator/test/fixtures/test-artifacts/Simple/keys/setVal.verifier deleted file mode 100644 index e205835e..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/Simple/keys/setVal.verifier and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/Simple/zkir/getVal.bzkir b/packages/simulator/test/fixtures/test-artifacts/Simple/zkir/getVal.bzkir deleted file mode 100644 index 74acd352..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/Simple/zkir/getVal.bzkir and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/Simple/zkir/getVal.zkir b/packages/simulator/test/fixtures/test-artifacts/Simple/zkir/getVal.zkir deleted file mode 100644 index cad66eb4..00000000 --- a/packages/simulator/test/fixtures/test-artifacts/Simple/zkir/getVal.zkir +++ /dev/null @@ -1,27 +0,0 @@ -{ - "version": { "major": 2, "minor": 0 }, - "do_communications_commitment": true, - "num_inputs": 0, - "instructions": [ - { "op": "load_imm", "imm": "01" }, - { "op": "load_imm", "imm": "30" }, - { "op": "declare_pub_input", "var": 1 }, - { "op": "pi_skip", "guard": 0, "count": 1 }, - { "op": "load_imm", "imm": "50" }, - { "op": "load_imm", "imm": "00" }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 3 }, - { "op": "pi_skip", "guard": 0, "count": 4 }, - { "op": "public_input", "guard": null }, - { "op": "load_imm", "imm": "-02" }, - { "op": "load_imm", "imm": "0C" }, - { "op": "declare_pub_input", "var": 6 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 5 }, - { "op": "declare_pub_input", "var": 4 }, - { "op": "pi_skip", "guard": 0, "count": 4 }, - { "op": "output", "var": 4 } - ] -} diff --git a/packages/simulator/test/fixtures/test-artifacts/Simple/zkir/setVal.bzkir b/packages/simulator/test/fixtures/test-artifacts/Simple/zkir/setVal.bzkir deleted file mode 100644 index 8a9d024d..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/Simple/zkir/setVal.bzkir and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/Simple/zkir/setVal.zkir b/packages/simulator/test/fixtures/test-artifacts/Simple/zkir/setVal.zkir deleted file mode 100644 index 2dd05a6e..00000000 --- a/packages/simulator/test/fixtures/test-artifacts/Simple/zkir/setVal.zkir +++ /dev/null @@ -1,27 +0,0 @@ -{ - "version": { "major": 2, "minor": 0 }, - "do_communications_commitment": true, - "num_inputs": 1, - "instructions": [ - { "op": "load_imm", "imm": "01" }, - { "op": "load_imm", "imm": "10" }, - { "op": "load_imm", "imm": "00" }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 1 }, - { "op": "declare_pub_input", "var": 1 }, - { "op": "declare_pub_input", "var": 1 }, - { "op": "declare_pub_input", "var": 3 }, - { "op": "pi_skip", "guard": 1, "count": 5 }, - { "op": "load_imm", "imm": "11" }, - { "op": "load_imm", "imm": "-02" }, - { "op": "declare_pub_input", "var": 4 }, - { "op": "declare_pub_input", "var": 1 }, - { "op": "declare_pub_input", "var": 1 }, - { "op": "declare_pub_input", "var": 5 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "pi_skip", "guard": 1, "count": 5 }, - { "op": "load_imm", "imm": "91" }, - { "op": "declare_pub_input", "var": 6 }, - { "op": "pi_skip", "guard": 1, "count": 1 } - ] -} diff --git a/packages/simulator/test/fixtures/test-artifacts/Witness/compiler/contract-info.json b/packages/simulator/test/fixtures/test-artifacts/Witness/compiler/contract-info.json deleted file mode 100644 index 3bbe4e42..00000000 --- a/packages/simulator/test/fixtures/test-artifacts/Witness/compiler/contract-info.json +++ /dev/null @@ -1,107 +0,0 @@ -{ - "circuits": [ - { - "name": "setBytes", - "pure": false, - "arguments": [ - ], - "result-type": { - "type-name": "Tuple", - "types": [ - ] - } - }, - { - "name": "setField", - "pure": false, - "arguments": [ - { - "name": "arg", - "type": { - "type-name": "Field" - } - } - ], - "result-type": { - "type-name": "Tuple", - "types": [ - ] - } - }, - { - "name": "setUint", - "pure": false, - "arguments": [ - { - "name": "arg1", - "type": { - "type-name": "Uint", - "maxval": 340282366920938463463374607431768211455 - } - }, - { - "name": "arg2", - "type": { - "type-name": "Uint", - "maxval": 340282366920938463463374607431768211455 - } - } - ], - "result-type": { - "type-name": "Tuple", - "types": [ - ] - } - } - ], - "witnesses": [ - { - "name": "wit_secretBytes", - "arguments": [ - ], - "result type": { - "type-name": "Bytes", - "length": 32 - } - }, - { - "name": "wit_secretFieldPlusArg", - "arguments": [ - { - "name": "arg1", - "type": { - "type-name": "Field" - } - } - ], - "result type": { - "type-name": "Field" - } - }, - { - "name": "wit_secretUintPlusArgs", - "arguments": [ - { - "name": "arg1", - "type": { - "type-name": "Uint", - "maxval": 340282366920938463463374607431768211455 - } - }, - { - "name": "arg2", - "type": { - "type-name": "Uint", - "maxval": 340282366920938463463374607431768211455 - } - } - ], - "result type": { - "type-name": "Uint", - "maxval": 340282366920938463463374607431768211455 - } - } - ], - "contracts": [ - ] -} diff --git a/packages/simulator/test/fixtures/test-artifacts/Witness/contract/index.cjs b/packages/simulator/test/fixtures/test-artifacts/Witness/contract/index.cjs deleted file mode 100644 index 776de1fd..00000000 --- a/packages/simulator/test/fixtures/test-artifacts/Witness/contract/index.cjs +++ /dev/null @@ -1,448 +0,0 @@ -'use strict'; -const __compactRuntime = require('@midnight-ntwrk/compact-runtime'); -const expectedRuntimeVersionString = '0.9.0'; -const expectedRuntimeVersion = expectedRuntimeVersionString.split('-')[0].split('.').map(Number); -const actualRuntimeVersion = __compactRuntime.versionString.split('-')[0].split('.').map(Number); -if (expectedRuntimeVersion[0] != actualRuntimeVersion[0] - || (actualRuntimeVersion[0] == 0 && expectedRuntimeVersion[1] != actualRuntimeVersion[1]) - || expectedRuntimeVersion[1] > actualRuntimeVersion[1] - || (expectedRuntimeVersion[1] == actualRuntimeVersion[1] && expectedRuntimeVersion[2] > actualRuntimeVersion[2])) - throw new __compactRuntime.CompactError(`Version mismatch: compiled code expects ${expectedRuntimeVersionString}, runtime is ${__compactRuntime.versionString}`); -{ const MAX_FIELD = 52435875175126190479447740508185965837690552500527637822603658699938581184512n; - if (__compactRuntime.MAX_FIELD !== MAX_FIELD) - throw new __compactRuntime.CompactError(`compiler thinks maximum field value is ${MAX_FIELD}; run time thinks it is ${__compactRuntime.MAX_FIELD}`) -} - -const _descriptor_0 = new __compactRuntime.CompactTypeField(); - -const _descriptor_1 = new __compactRuntime.CompactTypeUnsignedInteger(340282366920938463463374607431768211455n, 16); - -const _descriptor_2 = new __compactRuntime.CompactTypeBytes(32); - -const _descriptor_3 = new __compactRuntime.CompactTypeUnsignedInteger(18446744073709551615n, 8); - -const _descriptor_4 = new __compactRuntime.CompactTypeBoolean(); - -class _ContractAddress_0 { - alignment() { - return _descriptor_2.alignment(); - } - fromValue(value_0) { - return { - bytes: _descriptor_2.fromValue(value_0) - } - } - toValue(value_0) { - return _descriptor_2.toValue(value_0.bytes); - } -} - -const _descriptor_5 = new _ContractAddress_0(); - -const _descriptor_6 = new __compactRuntime.CompactTypeUnsignedInteger(255n, 1); - -class Contract { - witnesses; - constructor(...args_0) { - if (args_0.length !== 1) { - throw new __compactRuntime.CompactError(`Contract constructor: expected 1 argument, received ${args_0.length}`); - } - const witnesses_0 = args_0[0]; - if (typeof(witnesses_0) !== 'object') { - throw new __compactRuntime.CompactError('first (witnesses) argument to Contract constructor is not an object'); - } - if (typeof(witnesses_0.wit_secretBytes) !== 'function') { - throw new __compactRuntime.CompactError('first (witnesses) argument to Contract constructor does not contain a function-valued field named wit_secretBytes'); - } - if (typeof(witnesses_0.wit_secretFieldPlusArg) !== 'function') { - throw new __compactRuntime.CompactError('first (witnesses) argument to Contract constructor does not contain a function-valued field named wit_secretFieldPlusArg'); - } - if (typeof(witnesses_0.wit_secretUintPlusArgs) !== 'function') { - throw new __compactRuntime.CompactError('first (witnesses) argument to Contract constructor does not contain a function-valued field named wit_secretUintPlusArgs'); - } - this.witnesses = witnesses_0; - this.circuits = { - setBytes: (...args_1) => { - if (args_1.length !== 1) { - throw new __compactRuntime.CompactError(`setBytes: expected 1 argument (as invoked from Typescript), received ${args_1.length}`); - } - const contextOrig_0 = args_1[0]; - if (!(typeof(contextOrig_0) === 'object' && contextOrig_0.originalState != undefined && contextOrig_0.transactionContext != undefined)) { - __compactRuntime.type_error('setBytes', - 'argument 1 (as invoked from Typescript)', - 'Witness.compact line 14 char 1', - 'CircuitContext', - contextOrig_0) - } - const context = { ...contextOrig_0 }; - const partialProofData = { - input: { value: [], alignment: [] }, - output: undefined, - publicTranscript: [], - privateTranscriptOutputs: [] - }; - const result_0 = this._setBytes_0(context, partialProofData); - partialProofData.output = { value: [], alignment: [] }; - return { result: result_0, context: context, proofData: partialProofData }; - }, - setField: (...args_1) => { - if (args_1.length !== 2) { - throw new __compactRuntime.CompactError(`setField: expected 2 arguments (as invoked from Typescript), received ${args_1.length}`); - } - const contextOrig_0 = args_1[0]; - const arg_0 = args_1[1]; - if (!(typeof(contextOrig_0) === 'object' && contextOrig_0.originalState != undefined && contextOrig_0.transactionContext != undefined)) { - __compactRuntime.type_error('setField', - 'argument 1 (as invoked from Typescript)', - 'Witness.compact line 19 char 1', - 'CircuitContext', - contextOrig_0) - } - if (!(typeof(arg_0) === 'bigint' && arg_0 >= 0 && arg_0 <= __compactRuntime.MAX_FIELD)) { - __compactRuntime.type_error('setField', - 'argument 1 (argument 2 as invoked from Typescript)', - 'Witness.compact line 19 char 1', - 'Field', - arg_0) - } - const context = { ...contextOrig_0 }; - const partialProofData = { - input: { - value: _descriptor_0.toValue(arg_0), - alignment: _descriptor_0.alignment() - }, - output: undefined, - publicTranscript: [], - privateTranscriptOutputs: [] - }; - const result_0 = this._setField_0(context, partialProofData, arg_0); - partialProofData.output = { value: [], alignment: [] }; - return { result: result_0, context: context, proofData: partialProofData }; - }, - setUint: (...args_1) => { - if (args_1.length !== 3) { - throw new __compactRuntime.CompactError(`setUint: expected 3 arguments (as invoked from Typescript), received ${args_1.length}`); - } - const contextOrig_0 = args_1[0]; - const arg1_0 = args_1[1]; - const arg2_0 = args_1[2]; - if (!(typeof(contextOrig_0) === 'object' && contextOrig_0.originalState != undefined && contextOrig_0.transactionContext != undefined)) { - __compactRuntime.type_error('setUint', - 'argument 1 (as invoked from Typescript)', - 'Witness.compact line 24 char 1', - 'CircuitContext', - contextOrig_0) - } - if (!(typeof(arg1_0) === 'bigint' && arg1_0 >= 0n && arg1_0 <= 340282366920938463463374607431768211455n)) { - __compactRuntime.type_error('setUint', - 'argument 1 (argument 2 as invoked from Typescript)', - 'Witness.compact line 24 char 1', - 'Uint<0..340282366920938463463374607431768211455>', - arg1_0) - } - if (!(typeof(arg2_0) === 'bigint' && arg2_0 >= 0n && arg2_0 <= 340282366920938463463374607431768211455n)) { - __compactRuntime.type_error('setUint', - 'argument 2 (argument 3 as invoked from Typescript)', - 'Witness.compact line 24 char 1', - 'Uint<0..340282366920938463463374607431768211455>', - arg2_0) - } - const context = { ...contextOrig_0 }; - const partialProofData = { - input: { - value: _descriptor_1.toValue(arg1_0).concat(_descriptor_1.toValue(arg2_0)), - alignment: _descriptor_1.alignment().concat(_descriptor_1.alignment()) - }, - output: undefined, - publicTranscript: [], - privateTranscriptOutputs: [] - }; - const result_0 = this._setUint_0(context, - partialProofData, - arg1_0, - arg2_0); - partialProofData.output = { value: [], alignment: [] }; - return { result: result_0, context: context, proofData: partialProofData }; - } - }; - this.impureCircuits = { - setBytes: this.circuits.setBytes, - setField: this.circuits.setField, - setUint: this.circuits.setUint - }; - } - initialState(...args_0) { - if (args_0.length !== 1) { - throw new __compactRuntime.CompactError(`Contract state constructor: expected 1 argument (as invoked from Typescript), received ${args_0.length}`); - } - const constructorContext_0 = args_0[0]; - if (typeof(constructorContext_0) !== 'object') { - throw new __compactRuntime.CompactError(`Contract state constructor: expected 'constructorContext' in argument 1 (as invoked from Typescript) to be an object`); - } - if (!('initialPrivateState' in constructorContext_0)) { - throw new __compactRuntime.CompactError(`Contract state constructor: expected 'initialPrivateState' in argument 1 (as invoked from Typescript)`); - } - if (!('initialZswapLocalState' in constructorContext_0)) { - throw new __compactRuntime.CompactError(`Contract state constructor: expected 'initialZswapLocalState' in argument 1 (as invoked from Typescript)`); - } - if (typeof(constructorContext_0.initialZswapLocalState) !== 'object') { - throw new __compactRuntime.CompactError(`Contract state constructor: expected 'initialZswapLocalState' in argument 1 (as invoked from Typescript) to be an object`); - } - const state_0 = new __compactRuntime.ContractState(); - let stateValue_0 = __compactRuntime.StateValue.newArray(); - stateValue_0 = stateValue_0.arrayPush(__compactRuntime.StateValue.newNull()); - stateValue_0 = stateValue_0.arrayPush(__compactRuntime.StateValue.newNull()); - stateValue_0 = stateValue_0.arrayPush(__compactRuntime.StateValue.newNull()); - state_0.data = stateValue_0; - state_0.setOperation('setBytes', new __compactRuntime.ContractOperation()); - state_0.setOperation('setField', new __compactRuntime.ContractOperation()); - state_0.setOperation('setUint', new __compactRuntime.ContractOperation()); - const context = { - originalState: state_0, - currentPrivateState: constructorContext_0.initialPrivateState, - currentZswapLocalState: constructorContext_0.initialZswapLocalState, - transactionContext: new __compactRuntime.QueryContext(state_0.data, __compactRuntime.dummyContractAddress()) - }; - const partialProofData = { - input: { value: [], alignment: [] }, - output: undefined, - publicTranscript: [], - privateTranscriptOutputs: [] - }; - Contract._query(context, - partialProofData, - [ - { push: { storage: false, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_6.toValue(0n), - alignment: _descriptor_6.alignment() }).encode() } }, - { push: { storage: true, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_2.toValue(new Uint8Array(32)), - alignment: _descriptor_2.alignment() }).encode() } }, - { ins: { cached: false, n: 1 } }]); - Contract._query(context, - partialProofData, - [ - { push: { storage: false, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_6.toValue(1n), - alignment: _descriptor_6.alignment() }).encode() } }, - { push: { storage: true, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_0.toValue(0n), - alignment: _descriptor_0.alignment() }).encode() } }, - { ins: { cached: false, n: 1 } }]); - Contract._query(context, - partialProofData, - [ - { push: { storage: false, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_6.toValue(2n), - alignment: _descriptor_6.alignment() }).encode() } }, - { push: { storage: true, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_1.toValue(0n), - alignment: _descriptor_1.alignment() }).encode() } }, - { ins: { cached: false, n: 1 } }]); - state_0.data = context.transactionContext.state; - return { - currentContractState: state_0, - currentPrivateState: context.currentPrivateState, - currentZswapLocalState: context.currentZswapLocalState - } - } - _wit_secretBytes_0(context, partialProofData) { - const witnessContext_0 = __compactRuntime.witnessContext(ledger(context.transactionContext.state), context.currentPrivateState, context.transactionContext.address); - const [nextPrivateState_0, result_0] = this.witnesses.wit_secretBytes(witnessContext_0); - context.currentPrivateState = nextPrivateState_0; - if (!(result_0.buffer instanceof ArrayBuffer && result_0.BYTES_PER_ELEMENT === 1 && result_0.length === 32)) { - __compactRuntime.type_error('wit_secretBytes', - 'return value', - 'Witness.compact line 10 char 1', - 'Bytes<32>', - result_0) - } - partialProofData.privateTranscriptOutputs.push({ - value: _descriptor_2.toValue(result_0), - alignment: _descriptor_2.alignment() - }); - return result_0; - } - _wit_secretFieldPlusArg_0(context, partialProofData, arg1_0) { - const witnessContext_0 = __compactRuntime.witnessContext(ledger(context.transactionContext.state), context.currentPrivateState, context.transactionContext.address); - const [nextPrivateState_0, result_0] = this.witnesses.wit_secretFieldPlusArg(witnessContext_0, - arg1_0); - context.currentPrivateState = nextPrivateState_0; - if (!(typeof(result_0) === 'bigint' && result_0 >= 0 && result_0 <= __compactRuntime.MAX_FIELD)) { - __compactRuntime.type_error('wit_secretFieldPlusArg', - 'return value', - 'Witness.compact line 11 char 1', - 'Field', - result_0) - } - partialProofData.privateTranscriptOutputs.push({ - value: _descriptor_0.toValue(result_0), - alignment: _descriptor_0.alignment() - }); - return result_0; - } - _wit_secretUintPlusArgs_0(context, partialProofData, arg1_0, arg2_0) { - const witnessContext_0 = __compactRuntime.witnessContext(ledger(context.transactionContext.state), context.currentPrivateState, context.transactionContext.address); - const [nextPrivateState_0, result_0] = this.witnesses.wit_secretUintPlusArgs(witnessContext_0, - arg1_0, - arg2_0); - context.currentPrivateState = nextPrivateState_0; - if (!(typeof(result_0) === 'bigint' && result_0 >= 0n && result_0 <= 340282366920938463463374607431768211455n)) { - __compactRuntime.type_error('wit_secretUintPlusArgs', - 'return value', - 'Witness.compact line 12 char 1', - 'Uint<0..340282366920938463463374607431768211455>', - result_0) - } - partialProofData.privateTranscriptOutputs.push({ - value: _descriptor_1.toValue(result_0), - alignment: _descriptor_1.alignment() - }); - return result_0; - } - _setBytes_0(context, partialProofData) { - const val_0 = this._wit_secretBytes_0(context, partialProofData); - Contract._query(context, - partialProofData, - [ - { push: { storage: false, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_6.toValue(0n), - alignment: _descriptor_6.alignment() }).encode() } }, - { push: { storage: true, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_2.toValue(val_0), - alignment: _descriptor_2.alignment() }).encode() } }, - { ins: { cached: false, n: 1 } }]); - return []; - } - _setField_0(context, partialProofData, arg_0) { - const val_0 = this._wit_secretFieldPlusArg_0(context, - partialProofData, - arg_0); - Contract._query(context, - partialProofData, - [ - { push: { storage: false, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_6.toValue(1n), - alignment: _descriptor_6.alignment() }).encode() } }, - { push: { storage: true, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_0.toValue(val_0), - alignment: _descriptor_0.alignment() }).encode() } }, - { ins: { cached: false, n: 1 } }]); - return []; - } - _setUint_0(context, partialProofData, arg1_0, arg2_0) { - const val_0 = this._wit_secretUintPlusArgs_0(context, - partialProofData, - arg1_0, - arg2_0); - Contract._query(context, - partialProofData, - [ - { push: { storage: false, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_6.toValue(2n), - alignment: _descriptor_6.alignment() }).encode() } }, - { push: { storage: true, - value: __compactRuntime.StateValue.newCell({ value: _descriptor_1.toValue(val_0), - alignment: _descriptor_1.alignment() }).encode() } }, - { ins: { cached: false, n: 1 } }]); - return []; - } - static _query(context, partialProofData, prog) { - var res; - try { - res = context.transactionContext.query(prog, __compactRuntime.CostModel.dummyCostModel()); - } catch (err) { - throw new __compactRuntime.CompactError(err.toString()); - } - context.transactionContext = res.context; - var reads = res.events.filter((e) => e.tag === 'read'); - var i = 0; - partialProofData.publicTranscript = partialProofData.publicTranscript.concat(prog.map((op) => { - if(typeof(op) === 'object' && 'popeq' in op) { - return { popeq: { - ...op.popeq, - result: reads[i++].content, - } }; - } else { - return op; - } - })); - if(res.events.length == 1 && res.events[0].tag === 'read') { - return res.events[0].content; - } else { - return res.events; - } - } -} -function ledger(state) { - const context = { - originalState: state, - transactionContext: new __compactRuntime.QueryContext(state, __compactRuntime.dummyContractAddress()) - }; - const partialProofData = { - input: { value: [], alignment: [] }, - output: undefined, - publicTranscript: [], - privateTranscriptOutputs: [] - }; - return { - get _valBytes() { - return _descriptor_2.fromValue(Contract._query(context, - partialProofData, - [ - { dup: { n: 0 } }, - { idx: { cached: false, - pushPath: false, - path: [ - { tag: 'value', - value: { value: _descriptor_6.toValue(0n), - alignment: _descriptor_6.alignment() } }] } }, - { popeq: { cached: false, - result: undefined } }]).value); - }, - get _valField() { - return _descriptor_0.fromValue(Contract._query(context, - partialProofData, - [ - { dup: { n: 0 } }, - { idx: { cached: false, - pushPath: false, - path: [ - { tag: 'value', - value: { value: _descriptor_6.toValue(1n), - alignment: _descriptor_6.alignment() } }] } }, - { popeq: { cached: false, - result: undefined } }]).value); - }, - get _valUint() { - return _descriptor_1.fromValue(Contract._query(context, - partialProofData, - [ - { dup: { n: 0 } }, - { idx: { cached: false, - pushPath: false, - path: [ - { tag: 'value', - value: { value: _descriptor_6.toValue(2n), - alignment: _descriptor_6.alignment() } }] } }, - { popeq: { cached: false, - result: undefined } }]).value); - } - }; -} -const _emptyContext = { - originalState: new __compactRuntime.ContractState(), - transactionContext: new __compactRuntime.QueryContext(new __compactRuntime.ContractState().data, __compactRuntime.dummyContractAddress()) -}; -const _dummyContract = new Contract({ - wit_secretBytes: (...args) => undefined, - wit_secretFieldPlusArg: (...args) => undefined, - wit_secretUintPlusArgs: (...args) => undefined -}); -const pureCircuits = {}; -const contractReferenceLocations = { tag: 'publicLedgerArray', indices: { } }; -exports.Contract = Contract; -exports.ledger = ledger; -exports.pureCircuits = pureCircuits; -exports.contractReferenceLocations = contractReferenceLocations; -//# sourceMappingURL=index.cjs.map diff --git a/packages/simulator/test/fixtures/test-artifacts/Witness/contract/index.cjs.map b/packages/simulator/test/fixtures/test-artifacts/Witness/contract/index.cjs.map deleted file mode 100644 index dcf28b21..00000000 --- a/packages/simulator/test/fixtures/test-artifacts/Witness/contract/index.cjs.map +++ /dev/null @@ -1,8 +0,0 @@ -{ - "version": 3, - "file": "index.cjs", - "sourceRoot": "../../../../../", - "sources": ["test/fixtures/sample-contracts/Witness.compact"], - "names": [], - "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAAA;;;;;;;;;;;;;;;;;;;MAaA,AAAA,QAGC;;;;;;;;;;;;;;;;;;;;;;OAAA;MAED,AAAA,QAGC;;;;;cAHuB,KAAU;;;;;;;;;;;;;;;;;;yCAAV,KAAU;;;;;;;qEAAV,KAAU;;;OAGjC;MAED,AAAA,OAGC;;;;;cAHsB,MAAe;cAAE,MAAe;;;;;;;;;;;;;;;;;;;;;;;;;yCAAhC,MAAe,+BAAE,MAAe;;;;;;;;;yCAAhC,MAAe;yCAAE,MAAe;;;OAGtD;;;;;;;GACA;EA3BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAKA;;;;;;;;;uDAAmC;IACnC;;;;;;;;;uDAA+B;IAC/B;;;;;;;;;uDAAkC;;;;;;;GAoBjC;EAlBD,AAAA,kBAAqC;;0DAArC,eAAqC;;;;;;;;;;;;;;GAAA;EACrC,AAAA,yBAAmD,4BAApB,MAAW;;0DAA1C,sBAAmD;iFAApB,MAAW;;;;;;;;;;;;;;GAAS;EACnD,AAAA,yBAA4E,4BAA7C,MAAe,EAAE,MAAe;;0DAA/D,sBAA4E;iFAA7C,MAAe;iFAAE,MAAe;;;;;;;;;;;;;;GAAa;EAE5E,AAAA,WAGC;UAFO,KAAuB;IAC7B;;;;;;;yGAAqB,KAAG;;uDAAf;;GACV;EAED,AAAA,WAGC,4BAHuB,KAAU;UAC1B,KAAiC;;iDAAJ,KAAG;IACtC;;;;;;;yGAAqB,KAAG;;uDAAf;;GACV;EAED,AAAA,UAGC,4BAHsB,MAAe,EAAE,MAAe;UAC/C,KAAwC;;iDAAX,MAAI;iDAAE,MAAI;IAC7C;;;;;;;yGAAoB,KAAG;;uDAAf;;GACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IArBD;qCAAA;;;;;;;;;;;wFAAmC;KAAA;IACnC;qCAAA;;;;;;;;;;;wFAA+B;KAAA;IAC/B;qCAAA;;;;;;;;;;;wFAAkC;KAAA;;;;;;;;;;;;;;;;;;" -} diff --git a/packages/simulator/test/fixtures/test-artifacts/Witness/contract/index.d.cts b/packages/simulator/test/fixtures/test-artifacts/Witness/contract/index.d.cts deleted file mode 100644 index ea270f84..00000000 --- a/packages/simulator/test/fixtures/test-artifacts/Witness/contract/index.d.cts +++ /dev/null @@ -1,58 +0,0 @@ -import type * as __compactRuntime from '@midnight-ntwrk/compact-runtime'; - -export type ZswapCoinPublicKey = { bytes: Uint8Array }; - -export type ContractAddress = { bytes: Uint8Array }; - -export type Either = { is_left: boolean; left: A; right: B }; - -export type Maybe = { is_some: boolean; value: T }; - -export type Witnesses = { - wit_secretBytes(context: __compactRuntime.WitnessContext): [T, Uint8Array]; - wit_secretFieldPlusArg(context: __compactRuntime.WitnessContext, - arg1_0: bigint): [T, bigint]; - wit_secretUintPlusArgs(context: __compactRuntime.WitnessContext, - arg1_0: bigint, - arg2_0: bigint): [T, bigint]; -} - -export type ImpureCircuits = { - setBytes(context: __compactRuntime.CircuitContext): __compactRuntime.CircuitResults; - setField(context: __compactRuntime.CircuitContext, arg_0: bigint): __compactRuntime.CircuitResults; - setUint(context: __compactRuntime.CircuitContext, - arg1_0: bigint, - arg2_0: bigint): __compactRuntime.CircuitResults; -} - -export type PureCircuits = { -} - -export type Circuits = { - setBytes(context: __compactRuntime.CircuitContext): __compactRuntime.CircuitResults; - setField(context: __compactRuntime.CircuitContext, arg_0: bigint): __compactRuntime.CircuitResults; - setUint(context: __compactRuntime.CircuitContext, - arg1_0: bigint, - arg2_0: bigint): __compactRuntime.CircuitResults; -} - -export type Ledger = { - readonly _valBytes: Uint8Array; - readonly _valField: bigint; - readonly _valUint: bigint; -} - -export type ContractReferenceLocations = any; - -export declare const contractReferenceLocations : ContractReferenceLocations; - -export declare class Contract = Witnesses> { - witnesses: W; - circuits: Circuits; - impureCircuits: ImpureCircuits; - constructor(witnesses: W); - initialState(context: __compactRuntime.ConstructorContext): __compactRuntime.ConstructorResult; -} - -export declare function ledger(state: __compactRuntime.StateValue): Ledger; -export declare const pureCircuits: PureCircuits; diff --git a/packages/simulator/test/fixtures/test-artifacts/Witness/keys/setBytes.prover b/packages/simulator/test/fixtures/test-artifacts/Witness/keys/setBytes.prover deleted file mode 100644 index 6d0aa34e..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/Witness/keys/setBytes.prover and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/Witness/keys/setBytes.verifier b/packages/simulator/test/fixtures/test-artifacts/Witness/keys/setBytes.verifier deleted file mode 100644 index 1c6c4550..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/Witness/keys/setBytes.verifier and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/Witness/keys/setField.prover b/packages/simulator/test/fixtures/test-artifacts/Witness/keys/setField.prover deleted file mode 100644 index ceeb847d..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/Witness/keys/setField.prover and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/Witness/keys/setField.verifier b/packages/simulator/test/fixtures/test-artifacts/Witness/keys/setField.verifier deleted file mode 100644 index 90ca30e8..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/Witness/keys/setField.verifier and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/Witness/keys/setUint.prover b/packages/simulator/test/fixtures/test-artifacts/Witness/keys/setUint.prover deleted file mode 100644 index c0f1c9a9..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/Witness/keys/setUint.prover and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/Witness/keys/setUint.verifier b/packages/simulator/test/fixtures/test-artifacts/Witness/keys/setUint.verifier deleted file mode 100644 index 91b2ba2d..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/Witness/keys/setUint.verifier and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/Witness/zkir/setBytes.bzkir b/packages/simulator/test/fixtures/test-artifacts/Witness/zkir/setBytes.bzkir deleted file mode 100644 index 2fb735f1..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/Witness/zkir/setBytes.bzkir and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/Witness/zkir/setBytes.zkir b/packages/simulator/test/fixtures/test-artifacts/Witness/zkir/setBytes.zkir deleted file mode 100644 index fcfb7286..00000000 --- a/packages/simulator/test/fixtures/test-artifacts/Witness/zkir/setBytes.zkir +++ /dev/null @@ -1,32 +0,0 @@ -{ - "version": { "major": 2, "minor": 0 }, - "do_communications_commitment": true, - "num_inputs": 0, - "instructions": [ - { "op": "load_imm", "imm": "01" }, - { "op": "private_input", "guard": null }, - { "op": "constrain_bits", "var": 1, "bits": 8 }, - { "op": "private_input", "guard": null }, - { "op": "constrain_bits", "var": 2, "bits": 248 }, - { "op": "load_imm", "imm": "10" }, - { "op": "load_imm", "imm": "00" }, - { "op": "declare_pub_input", "var": 3 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 4 }, - { "op": "pi_skip", "guard": 0, "count": 5 }, - { "op": "load_imm", "imm": "11" }, - { "op": "load_imm", "imm": "20" }, - { "op": "declare_pub_input", "var": 5 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 0 }, - { "op": "declare_pub_input", "var": 6 }, - { "op": "declare_pub_input", "var": 1 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "pi_skip", "guard": 0, "count": 6 }, - { "op": "load_imm", "imm": "91" }, - { "op": "declare_pub_input", "var": 7 }, - { "op": "pi_skip", "guard": 0, "count": 1 } - ] -} diff --git a/packages/simulator/test/fixtures/test-artifacts/Witness/zkir/setField.bzkir b/packages/simulator/test/fixtures/test-artifacts/Witness/zkir/setField.bzkir deleted file mode 100644 index 7acd4c9a..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/Witness/zkir/setField.bzkir and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/Witness/zkir/setField.zkir b/packages/simulator/test/fixtures/test-artifacts/Witness/zkir/setField.zkir deleted file mode 100644 index c01bbe24..00000000 --- a/packages/simulator/test/fixtures/test-artifacts/Witness/zkir/setField.zkir +++ /dev/null @@ -1,27 +0,0 @@ -{ - "version": { "major": 2, "minor": 0 }, - "do_communications_commitment": true, - "num_inputs": 1, - "instructions": [ - { "op": "load_imm", "imm": "01" }, - { "op": "private_input", "guard": null }, - { "op": "load_imm", "imm": "10" }, - { "op": "declare_pub_input", "var": 3 }, - { "op": "declare_pub_input", "var": 1 }, - { "op": "declare_pub_input", "var": 1 }, - { "op": "declare_pub_input", "var": 1 }, - { "op": "declare_pub_input", "var": 1 }, - { "op": "pi_skip", "guard": 1, "count": 5 }, - { "op": "load_imm", "imm": "11" }, - { "op": "load_imm", "imm": "-02" }, - { "op": "declare_pub_input", "var": 4 }, - { "op": "declare_pub_input", "var": 1 }, - { "op": "declare_pub_input", "var": 1 }, - { "op": "declare_pub_input", "var": 5 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "pi_skip", "guard": 1, "count": 5 }, - { "op": "load_imm", "imm": "91" }, - { "op": "declare_pub_input", "var": 6 }, - { "op": "pi_skip", "guard": 1, "count": 1 } - ] -} diff --git a/packages/simulator/test/fixtures/test-artifacts/Witness/zkir/setUint.bzkir b/packages/simulator/test/fixtures/test-artifacts/Witness/zkir/setUint.bzkir deleted file mode 100644 index 848bc6e0..00000000 Binary files a/packages/simulator/test/fixtures/test-artifacts/Witness/zkir/setUint.bzkir and /dev/null differ diff --git a/packages/simulator/test/fixtures/test-artifacts/Witness/zkir/setUint.zkir b/packages/simulator/test/fixtures/test-artifacts/Witness/zkir/setUint.zkir deleted file mode 100644 index d6b52312..00000000 --- a/packages/simulator/test/fixtures/test-artifacts/Witness/zkir/setUint.zkir +++ /dev/null @@ -1,30 +0,0 @@ -{ - "version": { "major": 2, "minor": 0 }, - "do_communications_commitment": true, - "num_inputs": 2, - "instructions": [ - { "op": "constrain_bits", "var": 0, "bits": 128 }, - { "op": "constrain_bits", "var": 1, "bits": 128 }, - { "op": "load_imm", "imm": "01" }, - { "op": "private_input", "guard": null }, - { "op": "constrain_bits", "var": 3, "bits": 128 }, - { "op": "load_imm", "imm": "10" }, - { "op": "load_imm", "imm": "02" }, - { "op": "declare_pub_input", "var": 4 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 5 }, - { "op": "pi_skip", "guard": 2, "count": 5 }, - { "op": "load_imm", "imm": "11" }, - { "op": "declare_pub_input", "var": 6 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 2 }, - { "op": "declare_pub_input", "var": 4 }, - { "op": "declare_pub_input", "var": 3 }, - { "op": "pi_skip", "guard": 2, "count": 5 }, - { "op": "load_imm", "imm": "91" }, - { "op": "declare_pub_input", "var": 7 }, - { "op": "pi_skip", "guard": 2, "count": 1 } - ] -} diff --git a/packages/simulator/test/fixtures/utils/address.ts b/packages/simulator/test/fixtures/utils/address.ts index da7578d6..125be771 100644 --- a/packages/simulator/test/fixtures/utils/address.ts +++ b/packages/simulator/test/fixtures/utils/address.ts @@ -2,8 +2,8 @@ import { convertFieldToBytes, encodeCoinPublicKey, } from '@midnight-ntwrk/compact-runtime'; -import { encodeContractAddress } from '@midnight-ntwrk/ledger'; -import type * as Compact from '../test-artifacts/SampleZOwnable/contract/index.cjs'; +import { encodeContractAddress } from '@midnight-ntwrk/ledger-v7'; +import type * as Compact from '../artifacts/SampleZOwnable/contract/index.js'; const PREFIX_ADDRESS = '0200'; @@ -29,13 +29,19 @@ export const encodeToPK = (str: string): Compact.ZswapCoinPublicKey => ({ /** * @description Generates ContractAddress from `str` for testing purposes. - * Prepends 32-byte hex with PREFIX_ADDRESS before encoding. + * Truncates to 30 bytes before prepending PREFIX_ADDRESS to comply + * with field value constraints (max unsigned integer is 2^248-1). + * The truncation compensates for the bytes added by the prefix. * @param str String to hexify and encode. - * @returns Encoded `ZswapCoinPublicKey`. + * @returns Encoded `Compact.ContractAddress`. */ -export const encodeToAddress = (str: string): Compact.ContractAddress => ({ - bytes: encodeContractAddress(PREFIX_ADDRESS + toHexPadded(str)), -}); +export const encodeToAddress = (str: string): Compact.ContractAddress => { + const hex = toHexPadded(str); + const truncated = hex.slice(0, -4); + return { + bytes: encodeContractAddress(PREFIX_ADDRESS + truncated), + }; +}; /** * @description Generates an Either object for ZswapCoinPublicKey for testing. diff --git a/packages/simulator/test/integration/SampleZOwnable.test.ts b/packages/simulator/test/integration/SampleZOwnable.test.ts index 936ff292..1a21bb90 100644 --- a/packages/simulator/test/integration/SampleZOwnable.test.ts +++ b/packages/simulator/test/integration/SampleZOwnable.test.ts @@ -5,8 +5,8 @@ import { persistentHash, } from '@midnight-ntwrk/compact-runtime'; import { beforeEach, describe, expect, it } from 'vitest'; +import type { ZswapCoinPublicKey } from '../fixtures/artifacts/SampleZOwnable/contract/index.js'; import { SampleZOwnablePrivateState } from '../fixtures/sample-contracts/witnesses/SampleZOwnableWitnesses.js'; -import type { ZswapCoinPublicKey } from '../fixtures/test-artifacts/SampleZOwnable/contract/index.cjs'; import * as utils from '../fixtures/utils/address.js'; import { SampleZOwnableSimulator } from './SampleZOwnableSimulator.js'; diff --git a/packages/simulator/test/integration/SampleZOwnableSimulator.ts b/packages/simulator/test/integration/SampleZOwnableSimulator.ts index 7b22f12c..c288e259 100644 --- a/packages/simulator/test/integration/SampleZOwnableSimulator.ts +++ b/packages/simulator/test/integration/SampleZOwnableSimulator.ts @@ -1,15 +1,15 @@ import { type BaseSimulatorOptions, createSimulator } from '../../src/index'; -import { - SampleZOwnablePrivateState, - SampleZOwnableWitnesses, -} from '../fixtures/sample-contracts/witnesses/SampleZOwnableWitnesses'; import { type ContractAddress, type Either, ledger, Contract as SampleZOwnable, type ZswapCoinPublicKey, -} from '../fixtures/test-artifacts/SampleZOwnable/contract/index.cjs'; +} from '../fixtures/artifacts/SampleZOwnable/contract/index.js'; +import { + SampleZOwnablePrivateState, + SampleZOwnableWitnesses, +} from '../fixtures/sample-contracts/witnesses/SampleZOwnableWitnesses'; /** * Type constructor args @@ -26,6 +26,7 @@ const SampleZOwnableSimulatorBase = createSimulator< SampleZOwnablePrivateState, ReturnType, ReturnType, + SampleZOwnable, SampleZOwnableArgs >({ contractFactory: (witnesses) => @@ -113,15 +114,6 @@ export class SampleZOwnableSimulator extends SampleZOwnableSimulatorBase { return this.circuits.pure._computeOwnerId(pk, nonce); } - /** - * @description Transfers ownership to owner id `newOwnerId` without - * enforcing permission checks on the caller. - * @param newOwnerId - The unique identifier of the new owner calculated by `SHA256(pk, nonce)`. - */ - public _transferOwnership(newOwnerId: Uint8Array) { - this.circuits.impure._transferOwnership(newOwnerId); - } - public readonly privateState = { /** * @description Contextually sets a new nonce into the private state. diff --git a/packages/simulator/test/integration/SimpleSimulator.ts b/packages/simulator/test/integration/SimpleSimulator.ts index 980b1457..411c5e9d 100644 --- a/packages/simulator/test/integration/SimpleSimulator.ts +++ b/packages/simulator/test/integration/SimpleSimulator.ts @@ -1,17 +1,22 @@ import { type BaseSimulatorOptions, createSimulator } from '../../src/index'; +import { + ledger, + Contract as SimpleContract, +} from '../fixtures/artifacts/Simple/contract/index.js'; import { SimplePrivateState, SimpleWitnesses, } from '../fixtures/sample-contracts/witnesses/SimpleWitnesses'; -import { - ledger, - Contract as SimpleContract, -} from '../fixtures/test-artifacts/Simple/contract/index.cjs'; /** * Base simulator */ -const SimpleSimulatorBase = createSimulator({ +const SimpleSimulatorBase = createSimulator< + SimplePrivateState, + ReturnType, + ReturnType, + SimpleContract +>({ contractFactory: (witnesses) => new SimpleContract(witnesses), defaultPrivateState: () => SimplePrivateState, diff --git a/packages/simulator/test/integration/WitnessSimulator.ts b/packages/simulator/test/integration/WitnessSimulator.ts index 3bc09536..c5b07041 100644 --- a/packages/simulator/test/integration/WitnessSimulator.ts +++ b/packages/simulator/test/integration/WitnessSimulator.ts @@ -1,12 +1,12 @@ import { type BaseSimulatorOptions, createSimulator } from '../../src/index'; +import { + ledger, + Contract as WitnessContract, +} from '../fixtures/artifacts/Witness/contract/index.js'; import { WitnessPrivateState, WitnessWitnesses, } from '../fixtures/sample-contracts/witnesses/WitnessWitnesses'; -import { - ledger, - Contract as SampleZOwnable, -} from '../fixtures/test-artifacts/Witness/contract/index.cjs'; /** * Type constructor args @@ -20,10 +20,11 @@ const WitnessSimulatorBase = createSimulator< WitnessPrivateState, ReturnType, ReturnType, + WitnessContract, WitnessArgs >({ contractFactory: (witnesses) => - new SampleZOwnable(witnesses), + new WitnessContract(witnesses), defaultPrivateState: () => WitnessPrivateState.generate(), contractArgs: () => { return []; @@ -33,7 +34,7 @@ const WitnessSimulatorBase = createSimulator< }); /** - * SampleZOwnable Simulator + * Witness Simulator */ export class WitnessSimulator extends WitnessSimulatorBase { constructor( diff --git a/packages/simulator/test/setup.ts b/packages/simulator/test/setup.ts new file mode 100644 index 00000000..a59b0cf7 --- /dev/null +++ b/packages/simulator/test/setup.ts @@ -0,0 +1,108 @@ +/** + * Test setup script that compiles sample contracts before running tests. + * Runs once before all tests via Vitest's globalSetup. + */ + +import { exec, type SpawnSyncReturns } from 'node:child_process'; +import { existsSync, mkdirSync, statSync } from 'node:fs'; +import { dirname, join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { promisify } from 'node:util'; + +const execAsync = promisify(exec); + +const __filename = fileURLToPath(import.meta.url); +const __dirname = dirname(__filename); + +const SAMPLE_CONTRACTS_DIR = join(__dirname, 'fixtures', 'sample-contracts'); +const ARTIFACTS_DIR = join(__dirname, 'fixtures', 'artifacts'); + +const CONTRACT_FILES = [ + 'Simple.compact', + 'Witness.compact', + 'SampleZOwnable.compact', +]; + +function isSpawnSyncRet( + err: unknown, +): err is SpawnSyncReturns { + if (typeof err !== 'object' || err === null) { + return false; + } + + const typedErr = err as Partial> & + Record; + + const okErr = typedErr.error instanceof Error; + const okStdout = + typeof typedErr.stdout === 'string' || Buffer.isBuffer(typedErr.stdout); + const okStderr = + typeof typedErr.stderr === 'string' || Buffer.isBuffer(typedErr.stderr); + const okStatus = + typeof typedErr.status === 'number' || typedErr.status === null; + + return okErr && okStdout && okStderr && okStatus; +} + +async function compileContract(contractFile: string): Promise { + const inputPath = join(SAMPLE_CONTRACTS_DIR, contractFile); + const contractName = contractFile.replace('.compact', ''); + const outputDir = join(ARTIFACTS_DIR, contractName); + const contractArtifact = join(outputDir, 'contract', 'index.js'); + + // Skip if artifact already exists and is newer than source + if (existsSync(contractArtifact) && existsSync(inputPath)) { + const artifactTime = statSync(contractArtifact).mtime; + const sourceTime = statSync(inputPath).mtime; + if (artifactTime >= sourceTime) { + console.log(`✓ ${contractFile} (already compiled)`); + return; // Already compiled and up to date + } + } + + if (!existsSync(inputPath)) { + throw new Error(`Contract file not found: ${inputPath}`); + } + + // Ensure output directory and keys subdirectory exist + mkdirSync(outputDir, { recursive: true }); + mkdirSync(join(outputDir, 'keys'), { recursive: true }); + + const command = `compact compile --skip-zk "${inputPath}" "${outputDir}"`; + try { + await execAsync(command); + } catch (err: unknown) { + if (!isSpawnSyncRet(err)) { + throw err; + } + + if (err.status === 127) { + throw new Error( + '`compact` not found (exit code 127). Is it installed and on PATH?', + ); + } + + throw err; + } + + console.log(`✓ Compiled ${contractFile}`); +} + +async function setup(): Promise { + mkdirSync(ARTIFACTS_DIR, { recursive: true }); + + // Compile each contract sequentially + for (const contractFile of CONTRACT_FILES) { + await compileContract(contractFile); + } +} + +// Export setup function for Vitest's globalSetup +export default async function globalSetup(): Promise { + try { + await setup(); + } catch (error) { + console.log(`❌ Setup failed: ${error}`); + process.exit(1); + } +} diff --git a/packages/simulator/test/unit/core/StateManager.test.ts b/packages/simulator/test/unit/core/StateManager.test.ts index 871d2b41..a765cd6b 100644 --- a/packages/simulator/test/unit/core/StateManager.test.ts +++ b/packages/simulator/test/unit/core/StateManager.test.ts @@ -1,22 +1,21 @@ import { + ChargedState, type CircuitContext, - ContractState, dummyContractAddress, - type EncodedQualifiedCoinInfo, + type EncodedQualifiedShieldedCoinInfo, type EncodedZswapLocalState, - encodeQualifiedCoinInfo, - type QualifiedCoinInfo, + encodeQualifiedShieldedCoinInfo, + type QualifiedShieldedCoinInfo, QueryContext, - StateValue, - sampleTokenType, + sampleRawTokenType, } from '@midnight-ntwrk/compact-runtime'; import { beforeEach, describe, expect, it } from 'vitest'; import { CircuitContextManager } from '../../../src/core/CircuitContextManager'; +import { Contract as MockSimple } from '../../fixtures/artifacts/Simple/contract/index.js'; import { type SimplePrivateState, SimpleWitnesses, } from '../../fixtures/sample-contracts/witnesses/SimpleWitnesses'; -import { Contract as MockSimple } from '../../fixtures/test-artifacts/Simple/contract/index.cjs'; import { encodeToAddress, toHexPadded } from '../../fixtures/utils/address'; // Constants @@ -65,17 +64,17 @@ describe('CircuitContextManager', () => { }); it('should set original state', () => { - expect(ctx.originalState).toBeInstanceOf(ContractState); - expect(ctx.originalState).toHaveProperty('__wbg_ptr'); - expect((ctx.originalState as any).__wbg_ptr).toBeTypeOf('number'); + expect(ctx.currentQueryContext).toBeInstanceOf(QueryContext); + expect(ctx.currentQueryContext).toHaveProperty('__wbg_ptr'); + expect((ctx.currentQueryContext as any).__wbg_ptr).toBeTypeOf('number'); }); it('should set tx ctx', () => { // Need to go deeper - expect(ctx.transactionContext).toBeInstanceOf(QueryContext); - expect(ctx.transactionContext.address).toEqual(dummyContractAddress()); - expect(ctx.transactionContext.state).toBeInstanceOf(StateValue); - expect(ctx.transactionContext.state).toHaveProperty('__wbg_ptr'); + expect(ctx.currentQueryContext).toBeInstanceOf(QueryContext); + expect(ctx.currentQueryContext.address).toEqual(dummyContractAddress()); + expect(ctx.currentQueryContext.state).toBeInstanceOf(ChargedState); + expect(ctx.currentQueryContext.state).toHaveProperty('__wbg_ptr'); }); }); @@ -100,14 +99,14 @@ describe('CircuitContextManager', () => { it('should set new ctx', () => { const oldCtx = circuitCtxManager.getContext(); - const qualCoin: QualifiedCoinInfo = { - type: sampleTokenType(), + const qualCoin: QualifiedShieldedCoinInfo = { + type: sampleRawTokenType(), nonce: toHexPadded('nonce'), value: 123n, mt_index: 987n, }; - const encQualCoin: EncodedQualifiedCoinInfo = - encodeQualifiedCoinInfo(qualCoin); + const encQualCoin: EncodedQualifiedShieldedCoinInfo = + encodeQualifiedShieldedCoinInfo(qualCoin); // zswap local state const zswapLocalState_1: EncodedZswapLocalState = { @@ -119,21 +118,18 @@ describe('CircuitContextManager', () => { outputs: [], }; - // OG state - const NEW_OG_STATE: ContractState = new ContractState(); - // Query ctx const modifiedTxCtx: QueryContext = { - ...ctx.transactionContext, + ...ctx.currentQueryContext, address: encodeToAddress('otherAddress'), } as unknown as QueryContext; // Build new ctx const newCtx: CircuitContext = { - originalState: NEW_OG_STATE, + currentQueryContext: modifiedTxCtx, currentPrivateState: initialPrivateState, currentZswapLocalState: zswapLocalState_1, - transactionContext: modifiedTxCtx, + costModel: ctx.costModel, }; circuitCtxManager.setContext(newCtx); diff --git a/packages/simulator/vitest.config.ts b/packages/simulator/vitest.config.ts index d57e53a7..7f52faf0 100644 --- a/packages/simulator/vitest.config.ts +++ b/packages/simulator/vitest.config.ts @@ -6,5 +6,6 @@ export default defineConfig({ environment: 'node', include: ['test/**/*.test.ts'], reporters: 'verbose', + globalSetup: ['./test/setup.ts'], }, }); diff --git a/turbo.json b/turbo.json index 6b411f5c..f1bb2905 100644 --- a/turbo.json +++ b/turbo.json @@ -41,7 +41,6 @@ "compact:security", "compact:utils", "compact:access", - "compact:archive", "compact:token" ], "env": ["COMPACT_HOME", "SKIP_ZK"], diff --git a/yarn.lock b/yarn.lock index 83276375..841280be 100644 --- a/yarn.lock +++ b/yarn.lock @@ -334,28 +334,28 @@ __metadata: languageName: node linkType: hard -"@midnight-ntwrk/compact-runtime@npm:^0.9.0": - version: 0.9.0 - resolution: "@midnight-ntwrk/compact-runtime@npm:0.9.0" +"@midnight-ntwrk/compact-runtime@npm:0.14.0": + version: 0.14.0 + resolution: "@midnight-ntwrk/compact-runtime@npm:0.14.0" dependencies: - "@midnight-ntwrk/onchain-runtime": "npm:^0.3.0" + "@midnight-ntwrk/onchain-runtime-v2": "npm:^2.0.0" "@types/object-inspect": "npm:^1.8.1" object-inspect: "npm:^1.12.3" - checksum: 10/51b6769cdfac42e9f640d8ad052a6ddc8be3438b43d4c49b5e4bbf660658f3a1ae1be2f026da672af26baaed89fbd54809d5476a4c3ba2a9c97a3fcbc9754777 + checksum: 10/bba44d09770b172b7a5ba193f59d2ec57ca0dff2e3fd538326942e102e8cbe0b0cc1cb736e1f469afc74258517e7d25fc4dfa7f89a299aed900efc89f1eed3a7 languageName: node linkType: hard -"@midnight-ntwrk/ledger@npm:^4.0.0": - version: 4.0.0 - resolution: "@midnight-ntwrk/ledger@npm:4.0.0" - checksum: 10/826f6d2743af2a3f199f1ad61cb946a529eb5755dfc68ea7f8fc436bb366716bd5118a4561ed541938caa9db6f366b7c9ee8047511f41e5bcaaf21c335d29b1d +"@midnight-ntwrk/ledger-v7@npm:7.0.0": + version: 7.0.0 + resolution: "@midnight-ntwrk/ledger-v7@npm:7.0.0" + checksum: 10/cd04c6cdfb2e15192c10c3beb4a3b65f5c6419eedb0f52f65d67cb50ae6ecb492a1fa96e76479f2db2796d89512d4290cf26de4424e47378c90c743529ddb82a languageName: node linkType: hard -"@midnight-ntwrk/onchain-runtime@npm:^0.3.0": - version: 0.3.0 - resolution: "@midnight-ntwrk/onchain-runtime@npm:0.3.0" - checksum: 10/e0d6a9a96314dbce99345b9794395682a3471568fde13d90122227f52082dba7b83dc05d419e4745e5bf997e93274c2a01f3938ccd20351de8249923c0c9ab45 +"@midnight-ntwrk/onchain-runtime-v2@npm:^2.0.0": + version: 2.0.0 + resolution: "@midnight-ntwrk/onchain-runtime-v2@npm:2.0.0" + checksum: 10/71b2b5e2270ce36fbdb63c0bd531f09f2de9151b286b6c7389966279750080b300893aef973621e438a934f9274277181cdf9bdc1350abc0e244fa892a145b19 languageName: node linkType: hard @@ -393,7 +393,7 @@ __metadata: resolution: "@openzeppelin-compact/compact@workspace:packages/compact" dependencies: "@tsconfig/node24": "npm:^24.0.3" - "@types/node": "npm:24.10.0" + "@types/node": "npm:24.10.1" chalk: "npm:^5.6.2" log-symbols: "npm:^7.0.0" ora: "npm:^9.0.0" @@ -409,8 +409,8 @@ __metadata: version: 0.0.0-use.local resolution: "@openzeppelin-compact/contracts-simulator@workspace:packages/simulator" dependencies: - "@midnight-ntwrk/compact-runtime": "npm:^0.9.0" - "@midnight-ntwrk/ledger": "npm:^4.0.0" + "@midnight-ntwrk/compact-runtime": "npm:0.14.0" + "@midnight-ntwrk/ledger-v7": "npm:7.0.0" "@midnight-ntwrk/zswap": "npm:^4.0.0" "@tsconfig/node24": "npm:^24.0.3" "@types/node": "npm:24.10.0" @@ -662,6 +662,15 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:24.10.1": + version: 24.10.1 + resolution: "@types/node@npm:24.10.1" + dependencies: + undici-types: "npm:~7.16.0" + checksum: 10/ddac8c97be5f7401e31ea0e9316c6e864993c6cd06689b7f9874ecfb576ef8349f2d14298248a08b94a6dd029570a46a285cddc4d50e524817f1a3730b29a86e + languageName: node + linkType: hard + "@types/object-inspect@npm:^1.8.1": version: 1.13.0 resolution: "@types/object-inspect@npm:1.13.0" @@ -1520,8 +1529,8 @@ __metadata: resolution: "openzeppelin-compact@workspace:." dependencies: "@biomejs/biome": "npm:^2.3.8" - "@midnight-ntwrk/compact-runtime": "npm:^0.9.0" - "@midnight-ntwrk/ledger": "npm:^4.0.0" + "@midnight-ntwrk/compact-runtime": "npm:0.14.0" + "@midnight-ntwrk/ledger-v7": "npm:7.0.0" "@midnight-ntwrk/zswap": "npm:^4.0.0" "@types/node": "npm:24.10.0" ts-node: "npm:^10.9.2"