diff --git a/.gitignore b/.gitignore index cececed..9b11677 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,7 @@ dist .env.test.local .env.production.local -.vscode \ No newline at end of file +.vscode + +.DS_Store +out \ No newline at end of file diff --git a/.mocharc.json b/.mocharc.json new file mode 100644 index 0000000..a3415f8 --- /dev/null +++ b/.mocharc.json @@ -0,0 +1,5 @@ +{ + "require": "./node_modules/hardhat/register.js", + "timeout": 40000, + "_": ["test/**/*.ts"] +} \ No newline at end of file diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..01eabfa --- /dev/null +++ b/.npmrc @@ -0,0 +1,11 @@ +# Security settings +minimum-release-age=1440 +audit-level=moderate +ignore-scripts=true +package-manager-strict=true + +# Registry configurations +@appliedblockchain:registry=https://npm.pkg.github.com +@tokenysolutions:registry=https://npm.pkg.github.com +@onchain-id:registry=https://npm.pkg.github.com +//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN} diff --git a/DEPLOY.md b/DEPLOY.md index 4f333f2..b6e4efb 100644 --- a/DEPLOY.md +++ b/DEPLOY.md @@ -24,7 +24,7 @@ SILENTDATA_CHAIN_ID= ### 2. Compile Contracts ```bash -pnpm compile +pnpm compile:all ``` ### 3. Deploy to Silent Data @@ -50,7 +50,7 @@ pnpm install ### 2. Compile Contracts ```bash -pnpm compile +pnpm compile:all ``` ### 3. Run Local Hardhat Node diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..bfee79b --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Applied Blockchain Ltd. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 4f21635..bb94ca9 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ The rapid growth of decentralised finance highlights a critical tension between **An unopinionated implementation** -To achieve a truly unopinionated implementation, cryptographic details should be abstracted away from the Solidity interface. This ensures that different cryptographic approaches can be swapped without altering the contract’s external behaviour. Furthermore, logic around permissions and visibility controls should be programmable using standard Solidity constructs, avoiding proprietary libraries or custom extensions. The UCEF approach preserves the ERC-20 standard’s simplicity and composability while enabling flexible privacy rules that can adapt to evolving security requirements and compliance needs. +To achieve a truly unopinionated implementation, cryptographic details should be abstracted away from the Solidity interface. This ensures that different cryptographic approaches can be swapped without altering the contract's external behaviour. Furthermore, logic around permissions and visibility controls should be programmable using standard Solidity constructs, avoiding proprietary libraries or custom extensions. The UCEF approach preserves the ERC-20 standard's simplicity and composability while enabling flexible privacy rules that can adapt to evolving security requirements and compliance needs. ## ***Features*** @@ -44,3 +44,7 @@ A range of examples are available at: [contracts/examples/](contracts/examples/) ## **Adopted By** Light Silent Data Logo +## **License** + +This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. + diff --git a/UCEF3643.md b/UCEF3643.md new file mode 100644 index 0000000..99c0947 --- /dev/null +++ b/UCEF3643.md @@ -0,0 +1,181 @@ +# UCEF3643 Testing and Deployment Guide + +This guide provides comprehensive instructions for testing and deploying the UCEF3643 token implementation. + +## Prerequisites + +- Node.js (v14 or higher) +- pnpm (recommended) or npm +- Hardhat +- Access to Silent Data credentials (for Silent Data deployment) + +## Project Structure + +The UCEF3643 implementation is located in the `packages/ucef-3643` directory, The root directory includes: +- Test fixtures +- Deployment script (scripts/deploy-suite.ts) +- Ignition module (ignition/modules/UCEF3643.ts) + +## Testing + +### Running Tests + +1. Install dependencies: +```bash +pnpm install +``` + +2. Compile contracts: +```bash +pnpm compile:all +``` + +3. Run all tests: +```bash +pnpm test +``` + +4. Run specific test file: +```bash +pnpm test -- test/UCEF3643.test.ts +``` + + +## Deployment + +### Local Development + +1. Start local Hardhat node: +```bash +pnpm chain +``` + +2. Configure environment: +Create a `.env` file in the root directory: +```env +PRIVATE_KEY= +``` + +3. Deploy using Ignition: +```bash +pnpm deploy:module UCEF3643 +``` + +### Silent Data Deployment + +1. Configure environment: +Create a `.env` file with Silent Data credentials: +```env +PRIVATE_KEY= +SILENTDATA_RPC_URL= +SILENTDATA_CHAIN_ID= +``` + +2. Deploy to Silent Data: +```bash +pnpm deploy:module UCEF3643 silentdata +``` + +### Available Modules +| Module Name | Description | +|------------|-------------| +| UCEF3643 | Basic UCEF3643 token deployment without initialization | +| UCEF3643Init | UCEF3643 token deployment with mock registry/compliance and initialization | +| UCEF3643Proxy | UCEF3643 token deployment with proxy pattern for upgradability | + + +### Deployment Script + +The deployment script (`scripts/deploy-suite.ts`) deploys the complete UCEF3643 suite including: +- ClaimTopicsRegistry +- TrustedIssuersRegistry +- IdentityRegistryStorage +- IdentityRegistry +- ModularCompliance +- TREXImplementationAuthority +- Token implementation + +To use the deployment script: +```bash +pnpm script deploy-basic-suite +``` + +To use the deployment script with Silent Data network: +```bash +pnpm script deploy-basic-suite silentdata +``` + +The script will output the deployment addresses to the a file `DeploymentOutput.json` in the `out` directory. It's possible to export the private keys of the accounts by prepending the `EXPORT_PRIVATE_KEYS` environment variable to `true`. + +```bash +EXPORT_PRIVATE_KEYS=true pnpm script deploy-basic-suite +``` + +## Contract Features + +The UCEF3643 implementation includes: +- ERC-3643 compliance +- Identity verification +- Compliance checks +- Token freezing capabilities +- Transfer restrictions +- Agent management + +## Troubleshooting + +If you encounter issues: + +1. Clean build artifacts: +```bash +pnpm clean:all +``` + +2. Recompile contracts: +```bash +pnpm compile:all +``` + +3. Verify environment configuration +4. Check network connectivity +5. Ensure sufficient funds for deployment + +It's possible to compile each package individually: + +Compile root contracts: +```bash +pnpm compile +``` + +Compile UCEF package contracts: +```bash +pnpm ucef compile +``` + +Compile UCEF3643 package contracts: +```bash +pnpm ucef-3643 compile +``` + +## Important Notes + +- Always test thoroughly on local network before deployment +- Keep private keys and API credentials secure +- Back up deployment addresses and transaction hashes +- Monitor gas prices for optimal deployment timing +- Ensure all required contracts are properly deployed in the correct order + +## Development Workflow + +1. Make changes to contracts +2. Run tests to verify changes +3. Deploy to local network for testing +4. Deploy to testnet if required +5. Deploy to production network + +## Security Considerations + +- Verify all contract interactions +- Implement proper access controls +- Test all security-critical functions +- Review compliance requirements +- Monitor for potential vulnerabilities diff --git a/contracts/examples/UCEFCustom.sol b/contracts/examples/UCEFCustom.sol index 77c6a41..97d8837 100644 --- a/contracts/examples/UCEFCustom.sol +++ b/contracts/examples/UCEFCustom.sol @@ -1,8 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; -import "../token/UCEF.sol"; -import "../extensions/UCEFOwned.sol"; +import {UCEF} from "@appliedblockchain/ucef/contracts/UCEF.sol"; contract UCEFCustom is UCEF { address public regulator; diff --git a/contracts/examples/UCEFOnlyOwner.sol b/contracts/examples/UCEFOnlyOwner.sol index b50b589..bdfc857 100644 --- a/contracts/examples/UCEFOnlyOwner.sol +++ b/contracts/examples/UCEFOnlyOwner.sol @@ -1,9 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; -import "../extensions/UCEFOwned.sol"; +import {UCEFOwned} from "@appliedblockchain/ucef/contracts/UCEFOwned.sol"; + contract UCEFOnlyOwner is UCEFOwned { - constructor() UCEF("UCEFOnlyOwner", "uOOT") {} + constructor() UCEFOwned("UCEFOnlyOwner", "uOOT") {} function mint(address account, uint256 amount) public { _mint(account, amount); diff --git a/contracts/examples/UCEFOnlyOwnerAndRegulator.sol b/contracts/examples/UCEFOnlyOwnerAndRegulator.sol index 59962ca..3249006 100644 --- a/contracts/examples/UCEFOnlyOwnerAndRegulator.sol +++ b/contracts/examples/UCEFOnlyOwnerAndRegulator.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; -import "../extensions/UCEFRegulated.sol"; +import {UCEFRegulated} from "@appliedblockchain/ucef/contracts/UCEFRegulated.sol"; contract UCEFOnlyOwnerAndRegulator is UCEFRegulated { - constructor() UCEF('UCEFOnlyOwnerAndRegulator', 'uOOT') UCEFRegulated(msg.sender) {} + constructor() UCEFRegulated(msg.sender, 'UCEFOnlyOwnerAndRegulator', 'uOOT') {} function mint(address account, uint256 amount) public { _mint(account, amount); diff --git a/contracts/examples/UCEFOnlyOwnerSharable.sol b/contracts/examples/UCEFOnlyOwnerSharable.sol index 224450c..5cb2eaf 100644 --- a/contracts/examples/UCEFOnlyOwnerSharable.sol +++ b/contracts/examples/UCEFOnlyOwnerSharable.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; -import "../extensions/UCEFSharable.sol"; +import {UCEFSharable} from "@appliedblockchain/ucef/contracts/UCEFSharable.sol"; contract UCEFOnlyOwnerSharable is UCEFSharable { - constructor() UCEF('UCEFOnlyOwnerSharable', 'uOOT') UCEFSharable(msg.sender) {} + constructor() UCEFSharable(msg.sender, 'UCEFOnlyOwnerSharable', 'uOOT') {} function mint(address account, uint256 amount) public { _mint(account, amount); diff --git a/contracts/examples/UCEFOnlyOwnerWithPermit.sol b/contracts/examples/UCEFOnlyOwnerWithPermit.sol index 1552384..464312a 100644 --- a/contracts/examples/UCEFOnlyOwnerWithPermit.sol +++ b/contracts/examples/UCEFOnlyOwnerWithPermit.sol @@ -1,11 +1,11 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.24; -import "../extensions/UCEFOwned.sol"; -import "../extensions/UCEFPermit.sol"; +import {UCEFOwned, UCEF} from "@appliedblockchain/ucef/contracts/UCEFOwned.sol"; +import {UCEFPermit} from "@appliedblockchain/ucef/contracts/extensions/UCEFPermit.sol"; contract UCEFOnlyOwnerWithPermit is UCEFOwned, UCEFPermit { - constructor() UCEF("UCEFOnlyOwner", "uOOT") UCEFPermit("UCEFOnlyOwner") {} + constructor() UCEFOwned("UCEFOnlyOwner", "uOOT") UCEFPermit("UCEFOnlyOwner") {} function mint(address account, uint256 amount) public { _mint(account, amount); diff --git a/contracts/extensions/UCEFRegulated.sol b/contracts/extensions/UCEFRegulated.sol deleted file mode 100644 index d73809e..0000000 --- a/contracts/extensions/UCEFRegulated.sol +++ /dev/null @@ -1,130 +0,0 @@ -// SPDX-License-Identifier: MIT -// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/ERC20Permit.sol) - -pragma solidity ^0.8.20; - -import {UCEF} from "../token/UCEF.sol"; - -/** - * @title UCEFRegulated - * @dev Extension for UCEF token that implements a regulated authorization model. - * This model allows both account owners and a designated regulator to view balances. - * - * This implementation is suitable for scenarios where regulatory oversight is required - * while still maintaining privacy from the general public. - * - * Features: - * - Designated regulator with balance viewing privileges - * - Updatable regulator address - * - Account owners can still view their own balances - * - * Security considerations: - * - The regulator has visibility into all account balances - * - Only the current regulator can update the regulator address - * - Zero address checks prevent locking of regulatory functions - */ -abstract contract UCEFRegulated is UCEF { - address private _regulator; - - /** - * @dev Error thrown when an unauthorized account attempts to perform a regulated operation - * @param account The address that attempted the operation - */ - error UCEFRegulatedUnauthorizedAccount(address account); - - /** - * @dev Error thrown when attempting to set an invalid regulator address - * @param owner The invalid address that was provided - */ - error UCEFRegulatedInvalidRegulator(address owner); - - /** - * @dev Emitted when the regulator address is updated - * @param previousRegulator Address of the previous regulator - * @param newRegulator Address of the new regulator - */ - event RegulatorUpdated(address indexed previousRegulator, address indexed newRegulator); - - /** - * @dev Constructor that sets the initial regulator address - * @param initalRegulator The address to be set as the first regulator - * - * Requirements: - * - `initalRegulator` cannot be the zero address - */ - constructor(address initalRegulator) { - if (initalRegulator == address(0)) { - revert UCEFRegulatedInvalidRegulator(address(0)); - } - - _updateRegulator(initalRegulator); - } - - /** - * @dev Modifier to restrict function access to the current regulator - * - * Requirements: - * - The caller must be the current regulator - */ - modifier onlyRegulator() { - if (msg.sender != _regulator) { - revert UCEFRegulatedUnauthorizedAccount(msg.sender); - } - _; - } - - /** - * @dev Returns the address of the current regulator - * @return The regulator address - */ - function regulator() public view virtual returns (address) { - return _regulator; - } - - /** - * @dev Allows the current regulator to update the regulator address - * @param newRegulator Address to set as the new regulator - * - * Requirements: - * - The caller must be the current regulator - * - `newRegulator` cannot be the zero address - * - * Emits a {RegulatorUpdated} event - */ - function updateRegulator(address newRegulator) public virtual onlyRegulator { - if (newRegulator == address(0)) { - revert UCEFRegulatedInvalidRegulator(address(0)); - } - - _updateRegulator(newRegulator); - } - - /** - * @dev Internal function to update the regulator address - * @param newRegulator Address to set as the new regulator - * - * Emits a {RegulatorUpdated} event - */ - function _updateRegulator(address newRegulator) internal virtual { - address oldRegulator = _regulator; - _regulator = newRegulator; - emit RegulatorUpdated(oldRegulator, newRegulator); - } - - /** - * @dev Implementation of the balance authorization check - * @param account The account address to check authorization for - * @return bool True if authorized, reverts otherwise - * - * Requirements: - * - The caller must be either the account owner or the current regulator - * - * Note: - * - This implementation reverts for unauthorized access rather than returning false - * - Both account owners and the regulator can view balances - */ - function _authorizeBalance(address account) internal view virtual override returns (bool) { - require(msg.sender == account || msg.sender == _regulator, "Unauthorized access to balance"); - return true; - } -} diff --git a/contracts/extensions/UCEFSharable.sol b/contracts/extensions/UCEFSharable.sol deleted file mode 100644 index 17b44a0..0000000 --- a/contracts/extensions/UCEFSharable.sol +++ /dev/null @@ -1,204 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.20; - -import {UCEF} from "../token/UCEF.sol"; - -/** - * @title UCEFSharable - * @dev Extension for UCEF token that implements a sharable authorization model with optional supervisor oversight. - * This model allows account owners to grant balance viewing permissions to specific addresses, - * while maintaining an optional supervisor role for auditing purposes. - * - * Features: - * - Account owners can grant and revoke balance viewing permissions - * - Multiple viewers can be authorized per account - * - Optional supervisor with universal balance viewing privileges - * - Supervisor can be permanently disabled by setting to zero address - * - Clear permission management through events - * - * Security considerations: - * - Only account owners can manage their viewing permissions - * - Viewers can only see balances of accounts that have explicitly granted them permission - * - When enabled, the supervisor has visibility into all account balances - * - Only the current supervisor can update the supervisor address - * - Setting supervisor to zero address permanently disables supervision - * - Once supervision is disabled, it cannot be re-enabled - * - Permission changes are tracked through events for auditability - */ -abstract contract UCEFSharable is UCEF { - // Mapping from account address to viewer address to permission status - mapping(address account => mapping(address viewer => bool)) private _authorizedViewers; - - // Supervisor address for auditing purposes (zero address means supervision is permanently disabled) - address private _supervisor; - - /** - * @dev Error thrown when an unauthorized account attempts to view a balance - * @param account The address that attempted the viewing - */ - error UCEFSharableUnauthorizedViewer(address account); - - /** - * @dev Error thrown when an unauthorized account attempts to perform a supervised operation - * @param account The address that attempted the operation - */ - error UCEFSharableUnauthorizedAccount(address account); - - /** - * @dev Error thrown when attempting to re-enable supervision after it has been disabled - */ - error UCEFSharableSupervisionPermanentlyDisabled(); - - /** - * @dev Emitted when viewing permissions are granted or revoked - * @param account The account whose balance viewing permissions were modified - * @param viewer The address that was granted or revoked viewing permission - * @param status The new permission status (true for granted, false for revoked) - */ - event ViewerPermissionUpdated( - address indexed account, - address indexed viewer, - bool status - ); - - /** - * @dev Emitted when the supervisor address is updated - * @param previousSupervisor Address of the previous supervisor - * @param newSupervisor Address of the new supervisor (zero address means supervision permanently disabled) - */ - event SupervisorUpdated(address indexed previousSupervisor, address indexed newSupervisor); - - /** - * @dev Constructor that sets the initial supervisor address - * @param initialSupervisor The address to be set as the first supervisor (can be zero address to start unregulated) - */ - constructor(address initialSupervisor) { - _updateSupervisor(initialSupervisor); - } - - /** - * @dev Modifier to restrict function access to the current supervisor - * Requirements: - * - The caller must be the current supervisor - */ - modifier onlySupervisor() { - if (msg.sender != _supervisor) { - revert UCEFSharableUnauthorizedAccount(msg.sender); - } - _; - } - - /** - * @dev Returns the address of the current supervisor - * @return The supervisor address (zero address means supervision is permanently disabled) - */ - function supervisor() public view virtual returns (address) { - return _supervisor; - } - - /** - * @dev Allows the current supervisor to update the supervisor address or permanently disable supervision - * @param newSupervisor Address to set as the new supervisor (setting to zero address permanently disables supervision) - * - * Requirements: - * - The caller must be the current supervisor - * - Supervision must be currently enabled - * - If supervision was previously disabled (supervisor is zero address), it cannot be re-enabled - * - * Note: - * - Setting the supervisor to zero address permanently disables supervision - * - * Emits a {SupervisorUpdated} event - */ - function updateSupervisor(address newSupervisor) public virtual onlySupervisor { - _updateSupervisor(newSupervisor); - } - - /** - * @dev Internal function to update the supervisor address - * @param newSupervisor Address to set as the new supervisor (zero address permanently disables supervision) - * - * Emits a {SupervisorUpdated} event - */ - function _updateSupervisor(address newSupervisor) internal virtual { - address oldSupervisor = _supervisor; - _supervisor = newSupervisor; - emit SupervisorUpdated(oldSupervisor, newSupervisor); - } - - /** - * @dev Grants balance viewing permission to a specific address - * @param viewer The address to grant viewing permission to - * - * Requirements: - * - Only the account owner can grant viewing permissions - * - * Emits a {ViewerPermissionUpdated} event - */ - function grantViewer(address viewer) public virtual { - _updateViewerPermission(msg.sender, viewer, true); - } - - /** - * @dev Revokes balance viewing permission from a specific address - * @param viewer The address to revoke viewing permission from - * - * Requirements: - * - Only the account owner can revoke viewing permissions - * - * Emits a {ViewerPermissionUpdated} event - */ - function revokeViewer(address viewer) public virtual { - _updateViewerPermission(msg.sender, viewer, false); - } - - /** - * @dev Checks if an address has viewing permission for a specific account - * @param account The account whose permissions to check - * @param viewer The address to check viewing permissions for - * @return bool True if the viewer has permission, false otherwise - */ - function hasViewPermission(address account, address viewer) public view virtual returns (bool) { - return _authorizedViewers[account][viewer]; - } - - /** - * @dev Internal function to update viewer permissions - * @param account The account whose permissions are being updated - * @param viewer The viewer whose permissions are being updated - * @param status The new permission status - * - * Emits a {ViewerPermissionUpdated} event - */ - function _updateViewerPermission( - address account, - address viewer, - bool status - ) internal virtual { - _authorizedViewers[account][viewer] = status; - emit ViewerPermissionUpdated(account, viewer, status); - } - - /** - * @dev Implementation of the balance authorization check - * @param account The account address to check authorization for - * @return bool True if authorized, reverts otherwise - * - * Requirements: - * - The caller must be either: - * 1. The account owner - * 2. An authorized viewer for the account - * 3. The current supervisor (if supervision is enabled) - * - * Note: - * - This implementation reverts for unauthorized access rather than returning false - */ - function _authorizeBalance(address account) internal view virtual override returns (bool) { - if (msg.sender != account && - !_authorizedViewers[account][msg.sender] && - (_supervisor == address(0) || msg.sender != _supervisor)) { - revert UCEFSharableUnauthorizedViewer(msg.sender); - } - return true; - } -} \ No newline at end of file diff --git a/contracts/mocks/MockCompliance.sol b/contracts/mocks/MockCompliance.sol new file mode 100644 index 0000000..7e3ed90 --- /dev/null +++ b/contracts/mocks/MockCompliance.sol @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +contract MockCompliance { + mapping(address => bool) private _canTransfer; + bool private _canMint; + address private _token; + + function canTransfer( + address _from, + address /*_to*/, + uint256 /*_amount*/ + ) external view returns (bool) { + return _canTransfer[_from]; + } + + function transferred( + address _from, + address _to, + uint256 _amount + ) external {} + + function created( + address _to, + uint256 _amount + ) external {} + + function destroyed(address _userAddress, uint256 _amount) external {} + + /** + * @dev used for testing purpose + */ + function setCanTransfer(address _address, bool _status) external { + _canTransfer[_address] = _status; + } + + function bindToken(address _tokenAddress) external { + _token = _tokenAddress; + } + + function unbindToken(address _tokenAddress) external { + if (_token == _tokenAddress) { + _token = address(0); + } + } +} \ No newline at end of file diff --git a/contracts/mocks/MockIdentityRegistry.sol b/contracts/mocks/MockIdentityRegistry.sol new file mode 100644 index 0000000..2b8775c --- /dev/null +++ b/contracts/mocks/MockIdentityRegistry.sol @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; +struct IdentityData { + bool isVerified; + uint256 country; +} + +contract MockIdentityRegistry { + mapping(address => IdentityData) private _verified; + + function isVerified(address _userAddress) external view returns (bool) { + return _verified[_userAddress].isVerified; + } + + /** + * @dev used for testing purpose + */ + function setVerified(address _userAddress, bool _status) external { + IdentityData memory data = _verified[_userAddress]; + data.isVerified = _status; + _verified[_userAddress] = data; + } + + /** + * @dev used for testing purpose + */ + function isIdentityRegistered(address _userAddress) external view returns (IdentityData memory) { + return _verified[_userAddress]; + } + + /** + * @dev used for testing purpose + */ + function registerIdentity(address _userAddress, uint256 _country, bool _isVerified) external { + _verified[_userAddress] = IdentityData(_isVerified, _country); + } + + function identity(address /*_userAddress*/) public pure returns (address) { + // Returning hardcoded address for testing + return 0x26291175Fa0Ea3C8583fEdEB56805eA68289b105; + } +} \ No newline at end of file diff --git a/contracts/mocks/MockTrexImplementationAuthority.sol b/contracts/mocks/MockTrexImplementationAuthority.sol new file mode 100644 index 0000000..e53c7fb --- /dev/null +++ b/contracts/mocks/MockTrexImplementationAuthority.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +contract MockTrexImplementationAuthority { + address _tokenImplementation; + + constructor(address tokenImplementation) { + _tokenImplementation = tokenImplementation; + } + + function getTokenImplementation() external view returns (address) { + return _tokenImplementation; + } + + function updateTokenImplementation(address newTokenImplementation) external { + _tokenImplementation = newTokenImplementation; + } +} \ No newline at end of file diff --git a/hardhat.config.ts b/hardhat.config.ts index c8fc6cb..8c3e8ed 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -10,13 +10,27 @@ Config() const config: HardhatUserConfig = { solidity: { - version: '0.8.28', - settings: { - optimizer: { - enabled: true, - runs: 200, + compilers: [ + { + version: '0.8.28', + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, }, - }, + // Version 0.8.17 is required for the ERC3643 contract + { + version: '0.8.17', + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, + ], }, networks: { localhost: { diff --git a/ignition/modules/UCEF3643.ts b/ignition/modules/UCEF3643.ts new file mode 100644 index 0000000..37131da --- /dev/null +++ b/ignition/modules/UCEF3643.ts @@ -0,0 +1,11 @@ +import { buildModule } from '@nomicfoundation/hardhat-ignition/modules' +import { UCEF3643Contracts } from '@appliedblockchain/ucef-3643' + +export default buildModule('UCEF3643Module', (m) => { + // Deploy UCEF3643 token Implementation + const token = m.contract('UCEF3643', UCEF3643Contracts.UCEF3643, [], { + id: 'UCEF3643', + }) + + return { token } +}) diff --git a/ignition/modules/UCEF3643Init.ts b/ignition/modules/UCEF3643Init.ts new file mode 100644 index 0000000..cc324a5 --- /dev/null +++ b/ignition/modules/UCEF3643Init.ts @@ -0,0 +1,86 @@ +import { buildModule } from '@nomicfoundation/hardhat-ignition/modules' +import { UCEF3643Contracts } from '@appliedblockchain/ucef-3643' + +export default buildModule('UCEF3643Module', (m) => { + // Deploy mock contracts first + const mockIdentityRegistry = m.contract('MockIdentityRegistry', [], { + id: 'MockIdentityRegistry', + }) + + const mockCompliance = m.contract('MockCompliance', [], { + id: 'MockCompliance', + }) + + // Deploy UCEF3643 token + const token = m.contract('UCEF3643', UCEF3643Contracts.UCEF3643, [], { + id: 'UCEF3643', + }) + + // Get deployer address + const deployerAddress = m.getAccount(0) + + // Initialize the token with mock contracts + const initToken = m.call( + token, + 'init', + [ + mockIdentityRegistry, + mockCompliance, + 'ConfidentialToken', + 'CONF', + 18, + '0x0000000000000000000000000000000000000000', // onchainID + ], + { + id: 'initializeToken', + after: [mockIdentityRegistry, mockCompliance, token], + }, + ) + + // Grant agent role to deployer + const addAgent = m.call(token, 'addAgent', [deployerAddress], { + id: 'addAgent', + after: [initToken], + }) + + // Register and verify deployer identity + m.call( + mockIdentityRegistry, + 'registerIdentity', + [ + deployerAddress, + 1, // country code + true, // isVerified + ], + { + id: 'registerIdentity', + after: [addAgent], + }, + ) + + // Set up mock to allow minting + m.call( + mockCompliance, + 'setCanTransfer', + [ + '0x0000000000000000000000000000000000000000', // Zero address for minting + true, + ], + { + id: 'setupMint', + after: [addAgent], + }, + ) + + // Unpause the token + m.call(token, 'unpause', [], { + id: 'unpauseToken', + after: [addAgent], + }) + + return { + mockIdentityRegistry, + mockCompliance, + token, + } +}) diff --git a/ignition/modules/UCEF3643Proxy.ts b/ignition/modules/UCEF3643Proxy.ts new file mode 100644 index 0000000..ffdbbd1 --- /dev/null +++ b/ignition/modules/UCEF3643Proxy.ts @@ -0,0 +1,101 @@ +import { buildModule } from '@nomicfoundation/hardhat-ignition/modules' +import { UCEF3643Contracts } from '@appliedblockchain/ucef-3643' +import TREX from '@tokenysolutions/t-rex' + +export default buildModule('UCEF3643Module', (m) => { + // Deploy mock contracts first + const mockIdentityRegistry = m.contract('MockIdentityRegistry', [], { + id: 'MockIdentityRegistry', + }) + + const mockCompliance = m.contract('MockCompliance', [], { + id: 'MockCompliance', + }) + + // Deploy UCEF3643 token implementation + const tokenImplementation = m.contract('UCEF3643', UCEF3643Contracts.UCEF3643, [], { + id: 'UCEF3643', + }) + + // Deploy Implementation Authority + const implementationAuthority = m.contract('MockTrexImplementationAuthority', [tokenImplementation], { + id: 'MockTrexImplementationAuthority', + }) + + // Deploy UCEF3643 with proxy + const tokenProxy = m.contract( + 'Token', + TREX.contracts.TokenProxy as any, + [ + implementationAuthority, + mockIdentityRegistry, + mockCompliance, + 'ConfidentialToken', + 'CONF', + 18, + '0x0000000000000000000000000000000000000000', + ], + { + id: 'TokenProxy', + after: [implementationAuthority], + }, + ) + + // Get deployer address + const deployerAddress = m.getAccount(0) + + const token = m.contractAt('UCEF3643', UCEF3643Contracts.UCEF3643, tokenProxy, { + id: 'Token', + after: [tokenProxy], + }) + + // Grant agent role to deployer + const addAgent = m.call(token, 'addAgent', [deployerAddress], { + id: 'addAgent', + after: [tokenProxy], + }) + + // Register and verify deployer identity + m.call( + mockIdentityRegistry, + 'registerIdentity', + [ + deployerAddress, + 1, // country code + true, // isVerified + ], + { + id: 'registerIdentity', + after: [addAgent], + }, + ) + + // Set up mock to allow minting + m.call( + mockCompliance, + 'setCanTransfer', + [ + '0x0000000000000000000000000000000000000000', // Zero address for minting + true, + ], + { + id: 'setupMint', + after: [addAgent], + }, + ) + + // Unpause the token + m.call(token, 'unpause', [], { + id: 'unpauseToken', + after: [addAgent], + from: deployerAddress, + }) + + return { + mockIdentityRegistry, + mockCompliance, + token, + implementationAuthority, + tokenProxy, + } +}) diff --git a/package.json b/package.json index aab6faa..6c3ccb8 100644 --- a/package.json +++ b/package.json @@ -1,52 +1,69 @@ { - "name": "@appliedblockchain/ucef", + "name": "@appliedblockchain/silentdata-contracts", "version": "0.0.1", "private": true, + "license": "MIT", "scripts": { "compile": "npx hardhat compile", + "compile:all": "pnpm -r --if-present compile && pnpm compile", "test": "npx hardhat test", "chain": "npx hardhat node", "coverage": "npx hardhat coverage", + "script": "script() { npx hardhat --network ${2:-localhost} run scripts/${1}.ts; }; script", "clean:ignition": "rm -rf .ignition && rm -rf ./ignition/deployments", - "clean:all": "pnpm clean && pnpm clean:ignition", - "deploy:module": "deploy() { npx hardhat ignition deploy ignition/modules/$1.ts --network ${2:-localhost} --deployment-id ${2:-localhost} --reset; }; deploy $@", + "deploy:module": "deploy() { npx hardhat ignition deploy ignition/modules/$1.ts --network ${2:-localhost} --deployment-id ${2:-localhost} --reset; }; deploy", "clean": "npx hardhat clean", + "clean:all": "pnpm clean && pnpm -r --if-present clean", "format": "prettier --write \"**/*.{js,jsx,ts,tsx}\" --ignore-path .prettierignore", "format:check": "prettier --check \"**/*.{js,jsx,ts,tsx}\" --ignore-path .prettierignore", "lint": "eslint . --ext .ts", - "lint:fix": "pnpm lint --fix" + "lint:fix": "pnpm lint --fix", + "ucef": "pnpm --filter @appliedblockchain/ucef", + "ucef-3643": "pnpm --filter @appliedblockchain/ucef-3643" }, "devDependencies": { - "@appliedblockchain/silentdatarollup-core": "^0.1.3", - "@appliedblockchain/silentdatarollup-hardhat-plugin": "^0.1.3", - "@nomicfoundation/hardhat-chai-matchers": "^2.0.0", - "@nomicfoundation/hardhat-ethers": "^3.0.0", - "@nomicfoundation/hardhat-ignition": "^0.15.0", - "@nomicfoundation/hardhat-network-helpers": "^1.0.0", - "@nomicfoundation/hardhat-toolbox": "^5.0.0", - "@nomicfoundation/hardhat-verify": "^2.0.0", - "@nomicfoundation/ignition-core": "^0.15.0", - "@openzeppelin/contracts": "5.2.0", - "@typechain/ethers-v6": "^0.5.0", - "@typechain/hardhat": "^9.0.0", - "@types/chai": "^4.3.11", - "@types/mocha": "^10.0.6", - "@types/node": "^20.0.0", - "@typescript-eslint/eslint-plugin": "^6.14.0", - "@typescript-eslint/parser": "^6.14.0", - "chai": "^4.2.0", - "dotenv": "^16.4.7", - "eslint": "^9.22.0", - "eslint-config-prettier": "^9.0.0", - "eslint-plugin-prettier": "^5.0.0", - "ethers": "^6.9.0", - "globals": "^16.0.0", - "hardhat": "^2.19.0", - "hardhat-gas-reporter": "^1.0.8", - "prettier": "^3.0.0", - "solidity-coverage": "^0.8.1", - "ts-node": "^10.9.2", - "typechain": "^8.3.0", - "typescript": "^5.0.0" + "@appliedblockchain/silentdatarollup-core": "1.0.6", + "@appliedblockchain/silentdatarollup-ethers-provider": "1.0.6", + "@appliedblockchain/silentdatarollup-hardhat-plugin": "1.0.6", + "@appliedblockchain/ucef": "workspace:*", + "@appliedblockchain/ucef-3643": "workspace:*", + "@nomicfoundation/hardhat-chai-matchers": "2.0.7", + "@nomicfoundation/hardhat-ethers": "3.0.6", + "@nomicfoundation/hardhat-ignition": "0.15.10", + "@nomicfoundation/hardhat-network-helpers": "1.0.10", + "@nomicfoundation/hardhat-toolbox": "5.0.0", + "@nomicfoundation/hardhat-verify": "2.0.8", + "@nomicfoundation/ignition-core": "0.15.13", + "@onchain-id/solidity": "2.2.1", + "@openzeppelin/contracts": "5.4.0", + "@openzeppelin/contracts-upgradeable": "5.4.0", + "@tokenysolutions/t-rex": "4.1.6", + "@typechain/ethers-v6": "0.5.1", + "@typechain/hardhat": "9.1.0", + "@types/chai": "4.3.20", + "@types/mocha": "10.0.10", + "@types/node": "20.19.17", + "@typescript-eslint/eslint-plugin": "8.0.0", + "@typescript-eslint/parser": "8.0.0", + "chai": "4.5.0", + "dotenv": "16.6.1", + "eslint": "9.36.0", + "eslint-config-prettier": "9.1.2", + "eslint-plugin-prettier": "5.5.4", + "ethers": "6.13.2", + "globals": "16.4.0", + "hardhat": "2.22.10", + "hardhat-gas-reporter": "1.0.10", + "picocolors": "1.1.1", + "prettier": "3.6.2", + "solidity-coverage": "0.8.16", + "ts-node": "10.9.2", + "typechain": "8.3.2", + "typescript": "5.9.2" + }, + "pnpm": { + "patchedDependencies": { + "@tokenysolutions/t-rex@4.1.6": "patches/@tokenysolutions__t-rex@4.1.6.patch" + } } } diff --git a/packages/ucef-3643/.gitignore b/packages/ucef-3643/.gitignore new file mode 100644 index 0000000..2c6bc09 --- /dev/null +++ b/packages/ucef-3643/.gitignore @@ -0,0 +1,10 @@ +node_modules + +# Hardhat files +cache +artifacts +types +typechain-types + +# Environment variables +.env \ No newline at end of file diff --git a/packages/ucef-3643/contracts/UCEF3643.sol b/packages/ucef-3643/contracts/UCEF3643.sol new file mode 100644 index 0000000..10a0f9e --- /dev/null +++ b/packages/ucef-3643/contracts/UCEF3643.sol @@ -0,0 +1,241 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.17; + +import {Token} from "@tokenysolutions/t-rex/contracts/token/Token.sol"; +import {IIdentityRegistry} from "@tokenysolutions/t-rex/contracts/registry/interface/IIdentityRegistry.sol"; + +contract UCEF3643 is Token { + + /** + * @dev Returns the balance of the specified account if authorized + * @param account The address to query the balance of + * @return uint256 The balance if authorized, 0 if unauthorized + */ + function balanceOf(address account) public view override returns (uint256) { + bool authorized = _authorizeBalance(account); + return authorized ? _balanceOf(account): 0; + } + + /** + * @dev Returns the remaining number of tokens that `spender` will be + * allowed to spend on behalf of `owner` through {transferFrom}. This is + * zero by default. + * + * This value changes when {approve} or {transferFrom} are called. + * + * Access Control: + * - Only the token owner or the approved spender can view the allowance + * - Any other address attempting to view the allowance will trigger UCEFUnauthorizedBalanceAccess + * + * Requirements: + * - msg.sender must be either the owner or the spender of the allowance + * + * @param owner The address that owns the tokens + * @param spender The address that can spend the tokens + * @return uint256 The number of tokens the spender is allowed to spend + * @custom:error UCEFUnauthorizedBalanceAccess Thrown when an unauthorized address attempts to view the allowance + */ + function allowance(address owner, address spender) public view virtual override returns (uint256) { + require(msg.sender == owner || msg.sender == spender, "Unauthorized allowance access"); + return _allowance(owner, spender); + } + + /** + * @dev ERC-3643 (v4.1.6) replacing `balanceOf` with `_balanceOf` + * @notice ERC-20 overridden function that include logic to check for trade validity. + * Require that the msg.sender and to addresses are not frozen. + * Require that the value should not exceed available balance . + * Require that the to address is a verified address + * @param _to The address of the receiver + * @param _amount The number of tokens to transfer + * @return `true` if successful and revert if unsuccessful + */ + function transfer(address _to, uint256 _amount) public override whenNotPaused returns (bool) { + require(!_frozen[_to] && !_frozen[msg.sender], "wallet is frozen"); + require(_amount <= _balanceOf(msg.sender) - (_frozenTokens[msg.sender]), "Insufficient Balance"); + if (_tokenIdentityRegistry.isVerified(_to) && _tokenCompliance.canTransfer(msg.sender, _to, _amount)) { + _transfer(msg.sender, _to, _amount); + _tokenCompliance.transferred(msg.sender, _to, _amount); + return true; + } + revert("Transfer not possible"); + } + + /** + * @dev ERC-3643 (v4.1.6) replacing `balanceOf` with `_balanceOf` + * @notice ERC-20 overridden function that include logic to check for trade validity. + * Require that the from and to addresses are not frozen. + * Require that the value should not exceed available balance . + * Require that the to address is a verified address + * @param _from The address of the sender + * @param _to The address of the receiver + * @param _amount The number of tokens to transfer + * @return `true` if successful and revert if unsuccessful + */ + function transferFrom( + address _from, + address _to, + uint256 _amount + ) external override whenNotPaused returns (bool) { + require(!_frozen[_to] && !_frozen[_from], "wallet is frozen"); + require(_amount <= _balanceOf(_from) - (_frozenTokens[_from]), "Insufficient Balance"); + if (_tokenIdentityRegistry.isVerified(_to) && _tokenCompliance.canTransfer(_from, _to, _amount)) { + _approve(_from, msg.sender, _allowances[_from][msg.sender] - (_amount)); + _transfer(_from, _to, _amount); + _tokenCompliance.transferred(_from, _to, _amount); + return true; + } + revert("Transfer not possible"); + } + + /** + * @dev ERC-3643 (v4.1.6) replacing `balanceOf` with `_balanceOf`; and emitting 0 amount on `TokensUnfrozen` event. + * @dev See {IToken-forcedTransfer}. + */ + function forcedTransfer( + address _from, + address _to, + uint256 _amount + ) public override onlyAgent returns (bool) { + require(_balanceOf(_from) >= _amount, "sender balance too low"); + uint256 freeBalance = _balanceOf(_from) - (_frozenTokens[_from]); + if (_amount > freeBalance) { + uint256 tokensToUnfreeze = _amount - (freeBalance); + _frozenTokens[_from] = _frozenTokens[_from] - (tokensToUnfreeze); + emit TokensUnfrozen(_from, 0); + } + if (_tokenIdentityRegistry.isVerified(_to)) { + _transfer(_from, _to, _amount); + _tokenCompliance.transferred(_from, _to, _amount); + return true; + } + revert("Transfer not possible"); + } + + /** + * @dev ERC-3643 (v4.1.6) replacing `balanceOf` with `_balanceOf`; and emitting zero amount on `TokensUnfrozen` event. + * @dev See {IToken-burn}. + */ + function burn(address _userAddress, uint256 _amount) public override onlyAgent { + require(_balanceOf(_userAddress) >= _amount, "cannot burn more than balance"); + uint256 freeBalance = _balanceOf(_userAddress) - _frozenTokens[_userAddress]; + if (_amount > freeBalance) { + uint256 tokensToUnfreeze = _amount - (freeBalance); + _frozenTokens[_userAddress] = _frozenTokens[_userAddress] - (tokensToUnfreeze); + emit TokensUnfrozen(_userAddress, 0); + } + _burn(_userAddress, _amount); + _tokenCompliance.destroyed(_userAddress, _amount); + } + + /** + * @dev ERC-3643 (v4.1.6) replacing `balanceOf` with `_balanceOf`; and emitting zero amount on `TokensFrozen` event + * @dev See {IToken-freezePartialTokens}. + */ + function freezePartialTokens(address _userAddress, uint256 _amount) public override onlyAgent { + uint256 balance = _balanceOf(_userAddress); + require(balance >= _frozenTokens[_userAddress] + _amount, "Amount exceeds available balance"); + _frozenTokens[_userAddress] = _frozenTokens[_userAddress] + (_amount); + emit TokensFrozen(_userAddress, 0); + } + + /** + * @dev ERC-3643 (v4.1.6) emitting zero amount on `TokensUnfrozen` event. + * @dev See {IToken-unfreezePartialTokens}. + */ + function unfreezePartialTokens(address _userAddress, uint256 _amount) public override onlyAgent { + require(_frozenTokens[_userAddress] >= _amount, "Amount should be less than or equal to frozen tokens"); + _frozenTokens[_userAddress] = _frozenTokens[_userAddress] - (_amount); + emit TokensUnfrozen(_userAddress, 0); + } + + /** + * @dev Internal function to determine if an address is authorized to view a balance + * This implementation only owner or sender's identity are allowed to see balance. Can be overridden on derived contracts. + * @param account The address to check authorization for + * @return bool True if authorized, false otherwise + */ + function _authorizeBalance(address account) internal view virtual returns (bool) { + require( + msg.sender == account || address(IIdentityRegistry(_tokenIdentityRegistry).identity(msg.sender)) == account, + 'Unauthorized balance access' + ); + return true; + } + + /** + * @dev Internal function to get the actual balance of an account + * @param account The address to query the balance of + * @return uint256 The actual balance of the account + */ + function _balanceOf(address account) internal view returns (uint256) { + return _balances[account]; + } + + /** + * @dev See {ERC20-_transfer}. + */ + function _transfer( + address _from, + address _to, + uint256 _amount + ) internal virtual override { + require(_from != address(0), "ERC20: transfer from the zero address"); + require(_to != address(0), "ERC20: transfer to the zero address"); + + _beforeTokenTransfer(_from, _to, _amount); + + _balances[_from] = _balances[_from] - _amount; + _balances[_to] = _balances[_to] + _amount; + emit Transfer(address(0), address(0), 0); + } + + /** + * @dev See {ERC20-_mint}. + */ + function _mint(address _userAddress, uint256 _amount) internal virtual override { + require(_userAddress != address(0), "ERC20: mint to the zero address"); + + _beforeTokenTransfer(address(0), _userAddress, _amount); + + _totalSupply = _totalSupply + _amount; + _balances[_userAddress] = _balances[_userAddress] + _amount; + emit Transfer(address(0), address(0), 0); + } + + /** + * @dev See {ERC20-_burn}. + */ + function _burn(address _userAddress, uint256 _amount) internal virtual override { + require(_userAddress != address(0), "ERC20: burn from the zero address"); + + _beforeTokenTransfer(_userAddress, address(0), _amount); + + _balances[_userAddress] = _balances[_userAddress] - _amount; + _totalSupply = _totalSupply - _amount; + emit Transfer(address(0), address(0), 0); + } + + /** + * @dev See {ERC20-_approve}. + */ + function _approve( + address _owner, + address _spender, + uint256 _amount + ) internal virtual override { + require(_owner != address(0), "ERC20: approve from the zero address"); + require(_spender != address(0), "ERC20: approve to the zero address"); + + _allowances[_owner][_spender] = _amount; + emit Approval(address(0), address(0), 0); + } + + /** + * @dev Internal helper function to access the allowance mapping directly. + */ + function _allowance(address owner, address spender) internal view returns (uint256) { + return _allowances[owner][spender]; + } +} diff --git a/packages/ucef-3643/contracts/mocks/MockNewTokenImplementation.sol b/packages/ucef-3643/contracts/mocks/MockNewTokenImplementation.sol new file mode 100644 index 0000000..803e4fd --- /dev/null +++ b/packages/ucef-3643/contracts/mocks/MockNewTokenImplementation.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +import {UCEF3643} from '../UCEF3643.sol'; + +contract MockNewTokenImplementation is UCEF3643 { + // Overriding a method for testing + function allowance(address /*owner*/, address /*spender*/) public view virtual override returns (uint256) { + // Mock value to check in tests + return 99900; + } +} diff --git a/packages/ucef-3643/contracts/vendor/tokenysolutions/DeploySuite.sol b/packages/ucef-3643/contracts/vendor/tokenysolutions/DeploySuite.sol new file mode 100644 index 0000000..fc0fbc0 --- /dev/null +++ b/packages/ucef-3643/contracts/vendor/tokenysolutions/DeploySuite.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.17; + +/** + * @title TREX Deploy Suite Contract + * @notice Required to compile the artifacts used by `deploy-suite.ts` script + */ + +import "@tokenysolutions/t-rex/contracts/registry/implementation/ClaimTopicsRegistry.sol"; +import "@tokenysolutions/t-rex/contracts/registry/implementation/TrustedIssuersRegistry.sol"; +import "@tokenysolutions/t-rex/contracts/registry/implementation/IdentityRegistryStorage.sol"; +import "@tokenysolutions/t-rex/contracts/registry/implementation/IdentityRegistry.sol"; +import "@tokenysolutions/t-rex/contracts/compliance/modular/ModularCompliance.sol"; +import "@tokenysolutions/t-rex/contracts/proxy/authority/TREXImplementationAuthority.sol"; +import "@tokenysolutions/t-rex/contracts/factory/TREXFactory.sol"; +import "@tokenysolutions/t-rex/contracts/proxy/ClaimTopicsRegistryProxy.sol"; +import "@tokenysolutions/t-rex/contracts/registry/implementation/ClaimTopicsRegistry.sol"; +import "@tokenysolutions/t-rex/contracts/proxy/TrustedIssuersRegistryProxy.sol"; +import "@tokenysolutions/t-rex/contracts/registry/implementation/TrustedIssuersRegistry.sol"; +import "@tokenysolutions/t-rex/contracts/proxy/IdentityRegistryStorageProxy.sol"; +import "@tokenysolutions/t-rex/contracts/registry/implementation/IdentityRegistryStorage.sol"; +import "@tokenysolutions/t-rex/contracts/compliance/legacy/DefaultCompliance.sol"; +import "@tokenysolutions/t-rex/contracts/proxy/IdentityRegistryProxy.sol"; +import "@tokenysolutions/t-rex/contracts/proxy/TokenProxy.sol"; +import "@onchain-id/solidity/contracts/Identity.sol"; +import "@onchain-id/solidity/contracts/proxy/ImplementationAuthority.sol"; +import "@onchain-id/solidity/contracts/proxy/IdentityProxy.sol"; +import "@onchain-id/solidity/contracts/factory/IdFactory.sol"; +import "@onchain-id/solidity/contracts/ClaimIssuer.sol"; + +contract DeploySuite {} \ No newline at end of file diff --git a/packages/ucef-3643/hardhat.config.ts b/packages/ucef-3643/hardhat.config.ts new file mode 100644 index 0000000..2817eb3 --- /dev/null +++ b/packages/ucef-3643/hardhat.config.ts @@ -0,0 +1,30 @@ +import { HardhatUserConfig } from 'hardhat/config' +import '@typechain/hardhat' + +const config: HardhatUserConfig = { + solidity: { + compilers: [ + { + version: '0.8.17', + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, + ], + }, + typechain: { + outDir: './types', + target: 'ethers-v6', + }, + paths: { + sources: './contracts', + tests: './test', + cache: './cache', + artifacts: './artifacts', + }, +} + +export default config diff --git a/packages/ucef-3643/index.d.ts b/packages/ucef-3643/index.d.ts new file mode 100644 index 0000000..d6986ea --- /dev/null +++ b/packages/ucef-3643/index.d.ts @@ -0,0 +1,18 @@ +export { UCEF3643 } from './types' +export { Identity, Token, ClaimIssuer } from './types' + +export type Abi = any[]; +export interface Artifact { + contractName: string; + sourceName: string; + bytecode: string; + abi: AbiT; + linkReferences: Record>>; +} + +export namespace UCEF3643Contracts { + export const UCEF3643: Artifact +} diff --git a/packages/ucef-3643/index.js b/packages/ucef-3643/index.js new file mode 100644 index 0000000..7bf2388 --- /dev/null +++ b/packages/ucef-3643/index.js @@ -0,0 +1,9 @@ +const UCEF3643 = require('./artifacts/contracts/UCEF3643.sol/UCEF3643.json') + +const UCEF3643Contracts = { + UCEF3643, +} + +module.exports = { + UCEF3643Contracts, +} diff --git a/packages/ucef-3643/package.json b/packages/ucef-3643/package.json new file mode 100644 index 0000000..d6dbd85 --- /dev/null +++ b/packages/ucef-3643/package.json @@ -0,0 +1,51 @@ +{ + "name": "@appliedblockchain/ucef-3643", + "description": "Unopinionated Confidential ERC-20 Framework (UCEF) for ERC-3643", + "version": "0.0.1", + "keywords": [ + "solidity", + "ethereum", + "smart", + "contracts", + "erc-20", + "confidential", + "privacy", + "UCEF", + "ERC-3643" + ], + "author": "Applied Blockchain ", + "license": "MIT", + "files": [ + "contracts", + "artifacts", + "typechain-types", + "index.js", + "index.d.ts" + ], + "main": "index.js", + "types": "index.d.ts", + "scripts": { + "compile": "hardhat compile", + "clean": "hardhat clean" + }, + "dependencies": { + "ethers": "6.13.2" + }, + "devDependencies": { + "@onchain-id/solidity": "2.2.1", + "@openzeppelin/contracts": "4.9.6", + "@openzeppelin/contracts-upgradeable": "4.9.6", + "@tokenysolutions/t-rex": "4.1.6", + "@typechain/ethers-v6": "0.5.1", + "@typechain/hardhat": "9.1.0", + "hardhat": "2.22.10" + }, + "repository": { + "type": "git", + "url": "https://github.com/appliedblockchain/confidential-erc-20.git" + }, + "bugs": { + "url": "https://github.com/appliedblockchain/confidential-erc-20/issues" + }, + "homepage": "https://github.com/appliedblockchain/confidential-erc-20#readme" +} diff --git a/packages/ucef/.gitignore b/packages/ucef/.gitignore new file mode 100644 index 0000000..2c6bc09 --- /dev/null +++ b/packages/ucef/.gitignore @@ -0,0 +1,10 @@ +node_modules + +# Hardhat files +cache +artifacts +types +typechain-types + +# Environment variables +.env \ No newline at end of file diff --git a/contracts/token/UCEF.sol b/packages/ucef/contracts/UCEF.sol similarity index 61% rename from contracts/token/UCEF.sol rename to packages/ucef/contracts/UCEF.sol index b295c0e..9bf3961 100644 --- a/contracts/token/UCEF.sol +++ b/packages/ucef/contracts/UCEF.sol @@ -7,12 +7,20 @@ import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; * @title UCEF (User Confidential ERC20 Funds) * @dev Implementation of a confidential ERC20 token where balance visibility is restricted. * This contract extends the standard ERC20 implementation with additional privacy features - * that control who can view token balances. + * that control who can view token balances and events. * * Key features: * - Balance visibility control through authorization mechanism + * - Private Events for selective event visibility * - Standard ERC20 functionality - * - Protected balance access + * - Protected balance and allowance access + * + * Private Events Integration: + * This contract implements the Silent Data Private Events system, which enables selective + * visibility of on-chain events. Events are emitted as PrivateEvent logs with: + * - allowedViewers: addresses authorized to view the event + * - eventType: hash of the original event signature + * - payload: ABI-encoded event arguments * * Extension system: * The contract provides two official extensions: @@ -22,18 +30,51 @@ import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; * Custom extensions can be created by: * 1. Inheriting from this contract * 2. Implementing the _authorizeBalance function with custom logic - * 3. Choosing between silent failure (return false) or explicit revert for unauthorized access + * 3. Overriding _getTransferEventViewers and _getApprovalEventViewers for event privacy + * 4. Overriding _emitTransferEvent and _emitApprovalEvent for custom emission logic + * 5. Choosing between silent failure (return false) or explicit revert for unauthorized access * * Security considerations: * - Balance authorization must be properly implemented in derived contracts + * - Event viewer lists should align with the privacy model * - The contract maintains actual balances internally while exposing only authorized views * - Extensions should carefully consider their privacy model and access control */ abstract contract UCEF is ERC20 { + // Event type constants for Private Events + /** + * @notice Transfer event parameter mapping: + * - address param0: from - Token sender (address(0) for minting) + * - address param1: to - Token receiver (address(0) for burning) + * - uint256 param2: value - Amount of tokens transferred + * @custom:signature Transfer(address from, address to, uint256 value) + */ + bytes32 public constant EVENT_TYPE_TRANSFER = keccak256("Transfer(address,address,uint256)"); + /** + * @notice Approval event parameter mapping: + * - address param0: from - Token sender (address(0) for minting) + * - address param1: to - Token receiver (address(0) for burning) + * - uint256 param2: value - Amount of tokens approved + * @custom:signature Approval(address from, address to, uint256 value) + */ + bytes32 public constant EVENT_TYPE_APPROVAL = keccak256("Approval(address,address,uint256)"); + mapping(address account => uint256) private _balances; uint256 private _totalSupply; mapping(address account => mapping(address spender => uint256)) private _allowances; + /** + * @dev Private Event for selective visibility of on-chain events + * @param allowedViewers List of addresses authorized to view the event + * @param eventType The keccak256 hash of the original event signature + * @param payload The ABI-encoded event arguments + */ + event PrivateEvent( + address[] allowedViewers, + bytes32 indexed eventType, + bytes payload + ); + /** * @dev Thrown when an unauthorized address attempts to view a balance * @param sender The address attempting to view the balance @@ -62,7 +103,7 @@ abstract contract UCEF is ERC20 { * @custom:security Implementing contracts should carefully consider their authorization logic * as it directly impacts the privacy of user balances */ - function _authorizeBalance(address account) internal view virtual returns (bool) {} + function _authorizeBalance(address account) internal view virtual returns (bool); /** * @dev Returns the balance of the specified account if authorized @@ -125,7 +166,7 @@ abstract contract UCEF is ERC20 { } } - emit Transfer(address(0), address(0), 0); + _emitTransferEvent(from, to, value); } /** @@ -194,7 +235,7 @@ abstract contract UCEF is ERC20 { } _allowances[owner][spender] = value; if (emitEvent) { - emit Approval(address(0), address(0), 0); + _emitApprovalEvent(owner, spender, value); } } @@ -229,4 +270,100 @@ abstract contract UCEF is ERC20 { } } } + + /** + * @dev Internal function to emit Transfer events + * Can be overridden by derived contracts to implement custom emission logic + * Default implementation emits private events with selective visibility + * @param from The sending address (address(0) for minting) + * @param to The receiving address (address(0) for burning) + * @param value The amount of tokens transferred + */ + function _emitTransferEvent(address from, address to, uint256 value) internal virtual { + address[] memory allowedViewers = _getTransferEventViewers(from, to, value); + bytes memory payload = abi.encode(from, to, value); + + emit PrivateEvent(allowedViewers, EVENT_TYPE_TRANSFER, payload); + } + + /** + * @dev Internal function to determine who can view Transfer events + * Can be overridden by derived contracts to implement custom viewer logic + * Default implementation: only sender and receiver can view + * @param from The sending address + * @param to The receiving address + * @param value The amount of tokens transferred (available for derived contracts) + * @return allowedViewers Array of addresses authorized to view this transfer + */ + function _getTransferEventViewers( + address from, + address to, + uint256 value + ) internal view virtual returns (address[] memory allowedViewers) { + value; // Available for derived contracts + + // Count unique non-zero addresses + uint256 viewerCount = 0; + if (from != address(0)) viewerCount++; + if (to != address(0) && to != from) viewerCount++; + + allowedViewers = new address[](viewerCount); + uint256 index = 0; + + // Populate viewer list + if (from != address(0)) { + allowedViewers[index++] = from; + } + if (to != address(0) && to != from) { + allowedViewers[index] = to; + } + } + + /** + * @dev Internal function to emit Approval events + * Can be overridden by derived contracts to implement custom emission logic + * Default implementation emits private events with selective visibility + * @param owner The address that owns the tokens + * @param spender The address that can spend the tokens + * @param value The amount of tokens approved + */ + function _emitApprovalEvent(address owner, address spender, uint256 value) internal virtual { + address[] memory allowedViewers = _getApprovalEventViewers(owner, spender, value); + bytes memory payload = abi.encode(owner, spender, value); + + emit PrivateEvent(allowedViewers, EVENT_TYPE_APPROVAL, payload); + } + + /** + * @dev Internal function to determine who can view Approval events + * Can be overridden by derived contracts to implement custom viewer logic + * Default implementation: only owner and spender can view + * @param owner The address that owns the tokens + * @param spender The address that can spend the tokens + * @param value The amount of tokens approved (available for derived contracts) + * @return allowedViewers Array of addresses authorized to view this approval + */ + function _getApprovalEventViewers( + address owner, + address spender, + uint256 value + ) internal view virtual returns (address[] memory allowedViewers) { + value; // Available for derived contracts + + // Count unique non-zero addresses + uint256 viewerCount = 0; + if (owner != address(0)) viewerCount++; + if (spender != address(0) && spender != owner) viewerCount++; + + allowedViewers = new address[](viewerCount); + uint256 index = 0; + + // Populate viewer list + if (owner != address(0)) { + allowedViewers[index++] = owner; + } + if (spender != address(0) && spender != owner) { + allowedViewers[index] = spender; + } + } } \ No newline at end of file diff --git a/contracts/extensions/UCEFOwned.sol b/packages/ucef/contracts/UCEFOwned.sol similarity index 75% rename from contracts/extensions/UCEFOwned.sol rename to packages/ucef/contracts/UCEFOwned.sol index 0245195..0e49691 100644 --- a/contracts/extensions/UCEFOwned.sol +++ b/packages/ucef/contracts/UCEFOwned.sol @@ -3,22 +3,31 @@ pragma solidity ^0.8.20; -import {UCEF} from "../token/UCEF.sol"; +import {UCEF} from "./UCEF.sol"; /** * @title UCEFOwned * @dev Extension for UCEF token that implements a simple owner-based authorization model. - * In this model, only the account owner can view their own balance. + * In this model, only the account owner can view their own balance and related events. * * This implementation provides the strictest privacy model where each user can only - * see their own balance and no one else's. + * see their own balance and events, with no visibility into other accounts. + * + * Event Behavior: + * - Transfer events: Only visible to the account owner involved in the transfer + * - Approval events: Only visible to the token owner (not the spender) + * - No third parties can view any events, maintaining maximum privacy * * Security considerations: * - Each account can only be accessed by its owner + * - Event visibility follows the same strict owner-only model * - Unauthorized access attempts will revert with UCEFUnauthorizedBalanceAccess * - No administrative override is possible */ -abstract contract UCEFOwned is UCEF { +contract UCEFOwned is UCEF { + + constructor(string memory name, string memory symbol) UCEF(name, symbol) {} + /** * @dev Modifier to restrict function access to the account owner diff --git a/packages/ucef/contracts/UCEFRegulated.sol b/packages/ucef/contracts/UCEFRegulated.sol new file mode 100644 index 0000000..3190698 --- /dev/null +++ b/packages/ucef/contracts/UCEFRegulated.sol @@ -0,0 +1,249 @@ +// SPDX-License-Identifier: MIT +// OpenZeppelin Contracts (last updated v5.1.0) (token/ERC20/extensions/ERC20Permit.sol) + +pragma solidity ^0.8.20; + +import {UCEF} from "./UCEF.sol"; + +/** + * @title UCEFRegulated + * @dev Extension for UCEF token that implements a regulated authorization model. + * This model allows both account owners and a designated regulator to view balances and events. + * + * This implementation is suitable for scenarios where regulatory oversight is required + * while still maintaining privacy from the general public. + * + * Features: + * - Designated regulator with balance and event viewing privileges + * - Updatable regulator address + * - Account owners can still view their own balances and related events + * + * Event Behavior: + * - Transfer events: Visible to sender, receiver, and regulator + * - Approval events: Visible to owner, spender, and regulator + * - RegulatorUpdated events: Visible only to old and new regulator + * - Regulator has oversight of all token activities for compliance + * + * Security considerations: + * - The regulator has visibility into all account balances and events + * - Only the current regulator can update the regulator address + * - Zero address checks prevent locking of regulatory functions + */ +contract UCEFRegulated is UCEF { + // Event type constant for Private Events + /** + * @notice RegulatorUpdated event parameter mapping: + * - address param0: previousRegulator - Address of the previous regulator + * - address param1: newRegulator - Address of the new regulator + * @custom:signature RegulatorUpdated(address previousRegulator, address newRegulator) + */ + bytes32 public constant EVENT_TYPE_REGULATOR_UPDATED = keccak256("RegulatorUpdated(address,address)"); + + address private _regulator; + + /** + * @dev Error thrown when an unauthorized account attempts to perform a regulated operation + * @param account The address that attempted the operation + */ + error UCEFRegulatedUnauthorizedAccount(address account); + + /** + * @dev Error thrown when attempting to set an invalid regulator address + * @param owner The invalid address that was provided + */ + error UCEFRegulatedInvalidRegulator(address owner); + + /** + * @dev Emitted when the regulator address is updated + * @param previousRegulator Address of the previous regulator + * @param newRegulator Address of the new regulator + */ + event RegulatorUpdated(address indexed previousRegulator, address indexed newRegulator); + + /** + * @dev Constructor that sets the initial regulator address + * @param initialRegulator The address to be set as the first regulator + * + * Requirements: + * - `initialRegulator` cannot be the zero address + */ + constructor(address initialRegulator, string memory name, string memory symbol) UCEF(name, symbol) { + if (initialRegulator == address(0)) { + revert UCEFRegulatedInvalidRegulator(address(0)); + } + + _updateRegulator(initialRegulator); + } + + /** + * @dev Modifier to restrict function access to the current regulator + * + * Requirements: + * - The caller must be the current regulator + */ + modifier onlyRegulator() { + if (msg.sender != _regulator) { + revert UCEFRegulatedUnauthorizedAccount(msg.sender); + } + _; + } + + /** + * @dev Returns the address of the current regulator + * @return The regulator address + */ + function regulator() public view virtual returns (address) { + return _regulator; + } + + /** + * @dev Allows the current regulator to update the regulator address + * @param newRegulator Address to set as the new regulator + * + * Requirements: + * - The caller must be the current regulator + * - `newRegulator` cannot be the zero address + * + * Emits a {RegulatorUpdated} event + */ + function updateRegulator(address newRegulator) public virtual onlyRegulator { + if (newRegulator == address(0)) { + revert UCEFRegulatedInvalidRegulator(address(0)); + } + + _updateRegulator(newRegulator); + } + + /** + * @dev Internal function to update the regulator address + * @param newRegulator Address to set as the new regulator + * + * Emits a RegulatorUpdated event visible only to old and new regulator + */ + function _updateRegulator(address newRegulator) internal virtual { + address oldRegulator = _regulator; + _regulator = newRegulator; + _emitRegulatorUpdatedEvent(oldRegulator, newRegulator); + } + + /** + * @dev Implementation of the balance authorization check + * @param account The account address to check authorization for + * @return bool True if authorized, reverts otherwise + * + * Requirements: + * - The caller must be either the account owner or the current regulator + * + * Note: + * - This implementation reverts for unauthorized access rather than returning false + * - Both account owners and the regulator can view balances + */ + function _authorizeBalance(address account) internal view virtual override returns (bool) { + if (msg.sender != account && msg.sender != _regulator) { + revert UCEFUnauthorizedBalanceAccess(msg.sender, account); + } + return true; + } + + /** + * @dev Override to implement regulated event visibility for transfers + * Regulator can view all transfers for oversight alongside the involved parties + * @param from The sending address + * @param to The receiving address + * @return allowedViewers Array containing sender, receiver, and regulator + */ + function _getTransferEventViewers( + address from, + address to, + uint256 /* value */ + ) internal view virtual override returns (address[] memory allowedViewers) { + // Count unique non-zero addresses including regulator + uint256 viewerCount = 1; // Always include regulator + if (from != address(0) && from != _regulator) viewerCount++; + if (to != address(0) && to != from && to != _regulator) viewerCount++; + + allowedViewers = new address[](viewerCount); + uint256 index = 0; + + // Populate viewer list + allowedViewers[index++] = _regulator; // Always include regulator + if (from != address(0) && from != _regulator) { + allowedViewers[index++] = from; + } + if (to != address(0) && to != from && to != _regulator) { + allowedViewers[index] = to; + } + } + + /** + * @dev Override to implement regulated event visibility for approvals + * Regulator can view all approvals for oversight alongside owner and spender + * @param owner The address that owns the tokens + * @param spender The address that can spend the tokens + * @return allowedViewers Array containing owner, spender, and regulator + */ + function _getApprovalEventViewers( + address owner, + address spender, + uint256 /* value */ + ) internal view virtual override returns (address[] memory allowedViewers) { + // Count unique addresses including regulator + uint256 viewerCount = 1; // Always include regulator + if (owner != _regulator) viewerCount++; + if (spender != owner && spender != _regulator) viewerCount++; + + allowedViewers = new address[](viewerCount); + uint256 index = 0; + + // Populate viewer list + allowedViewers[index++] = _regulator; // Always include regulator + if (owner != _regulator) { + allowedViewers[index++] = owner; + } + if (spender != owner && spender != _regulator) { + allowedViewers[index] = spender; + } + } + + /** + * @dev Internal function to emit RegulatorUpdated events + * Can be overridden by derived contracts to implement custom emission logic + * Default implementation: only old and new regulator can view regulator changes + * @param previousRegulator The address of the previous regulator + * @param newRegulator The address of the new regulator + */ + function _emitRegulatorUpdatedEvent(address previousRegulator, address newRegulator) internal virtual { + address[] memory allowedViewers = _getRegulatorUpdatedEventViewers(previousRegulator, newRegulator); + bytes memory payload = abi.encode(previousRegulator, newRegulator); + + emit PrivateEvent(allowedViewers, EVENT_TYPE_REGULATOR_UPDATED, payload); + } + + /** + * @dev Internal function to determine who can view RegulatorUpdated events + * Only old and new regulator should see regulator changes for maximum privacy + * @param previousRegulator The address of the previous regulator + * @param newRegulator The address of the new regulator + * @return allowedViewers Array containing only old and new regulator + */ + function _getRegulatorUpdatedEventViewers( + address previousRegulator, + address newRegulator + ) internal view virtual returns (address[] memory allowedViewers) { + // Count unique non-zero addresses + uint256 viewerCount = 0; + if (previousRegulator != address(0)) viewerCount++; + if (newRegulator != address(0) && newRegulator != previousRegulator) viewerCount++; + + allowedViewers = new address[](viewerCount); + uint256 index = 0; + + // Populate viewer list + if (previousRegulator != address(0)) { + allowedViewers[index++] = previousRegulator; + } + if (newRegulator != address(0) && newRegulator != previousRegulator) { + allowedViewers[index] = newRegulator; + } + } +} diff --git a/packages/ucef/contracts/UCEFSharable.sol b/packages/ucef/contracts/UCEFSharable.sol new file mode 100644 index 0000000..922b9f7 --- /dev/null +++ b/packages/ucef/contracts/UCEFSharable.sol @@ -0,0 +1,387 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {UCEF} from "./UCEF.sol"; + +/** + * @title UCEFSharable + * @dev Extension for UCEF token that implements a sharable authorization model with optional supervisor oversight. + * This model allows account owners to grant balance viewing permissions to specific addresses, + * while maintaining an optional supervisor role for auditing purposes. + * + * Features: + * - Account owners can grant and revoke balance viewing permissions + * - Multiple viewers can be authorized per account + * - Optional supervisor with universal balance and event viewing privileges + * - Supervisor can be permanently disabled by setting to zero address + * - Events for selective visibility of permission changes + * + * Event Behavior: + * - Transfer events: Visible to sender, receiver, and supervisor (if enabled) + * - Approval events: Visible to owner, spender, and supervisor (if enabled) + * - ViewerPermissionUpdated events: Visible to account, viewer, and supervisor (if enabled) + * - SupervisorUpdated events: Visible only to old and new supervisor + * + * Security considerations: + * - Only account owners can manage their viewing permissions + * - Viewers can only see balances of accounts that have explicitly granted them permission + * - Viewers can only see balances, not transaction events (unless direct participants) + * - When enabled, the supervisor has visibility into all account balances and events + * - Only the current supervisor can update the supervisor address + * - Setting supervisor to zero address permanently disables supervision + * - Once supervision is disabled, it cannot be re-enabled + * - Permission changes are tracked through events for auditability while maintaining privacy + */ +contract UCEFSharable is UCEF { + // Event type constants for Private Events + /** + * @notice ViewerPermissionUpdated event parameter mapping: + * - address param0: account - The account whose balance viewing permissions were modified + * - address param1: viewer - The address that was granted or revoked viewing permission + * - bool param2: status - The new permission status (true for granted, false for revoked) + * @custom:signature ViewerPermissionUpdated(address account, address viewer, bool status) + */ + bytes32 public constant EVENT_TYPE_VIEWER_PERMISSION_UPDATED = keccak256("ViewerPermissionUpdated(address,address,bool)"); + /** + * @notice SupervisorUpdated event parameter mapping: + * - address param0: previousSupervisor - Address of the previous supervisor + * - address param1: newSupervisor - Address of the new supervisor (zero address means supervision permanently disabled) + * @custom:signature SupervisorUpdated(address previousSupervisor, address newSupervisor) + */ + bytes32 public constant EVENT_TYPE_SUPERVISOR_UPDATED = keccak256("SupervisorUpdated(address,address)"); + + // Mapping from account address to viewer address to permission status + mapping(address account => mapping(address viewer => bool)) private _authorizedViewers; + + // Supervisor address for auditing purposes (zero address means supervision is permanently disabled) + address private _supervisor; + + /** + * @dev Error thrown when an unauthorized account attempts to view a balance + * @param account The address that attempted the viewing + */ + error UCEFSharableUnauthorizedViewer(address account); + + /** + * @dev Error thrown when an unauthorized account attempts to perform a supervised operation + * @param account The address that attempted the operation + */ + error UCEFSharableUnauthorizedAccount(address account); + + /** + * @dev Error thrown when attempting to re-enable supervision after it has been disabled + */ + error UCEFSharableSupervisionPermanentlyDisabled(); + + /** + * @dev Emitted when viewing permissions are granted or revoked + * @param account The account whose balance viewing permissions were modified + * @param viewer The address that was granted or revoked viewing permission + * @param status The new permission status (true for granted, false for revoked) + */ + event ViewerPermissionUpdated( + address indexed account, + address indexed viewer, + bool status + ); + + /** + * @dev Emitted when the supervisor address is updated + * @param previousSupervisor Address of the previous supervisor + * @param newSupervisor Address of the new supervisor (zero address means supervision permanently disabled) + */ + event SupervisorUpdated(address indexed previousSupervisor, address indexed newSupervisor); + + /** + * @dev Constructor that sets the initial supervisor address + * @param initialSupervisor The address to be set as the first supervisor (can be zero address to start unregulated) + */ + constructor(address initialSupervisor, string memory name, string memory symbol) UCEF(name, symbol) { + _updateSupervisor(initialSupervisor); + } + + /** + * @dev Modifier to restrict function access to the current supervisor + * Requirements: + * - The caller must be the current supervisor + */ + modifier onlySupervisor() { + if (msg.sender != _supervisor) { + revert UCEFSharableUnauthorizedAccount(msg.sender); + } + _; + } + + /** + * @dev Returns the address of the current supervisor + * @return The supervisor address (zero address means supervision is permanently disabled) + */ + function supervisor() public view virtual returns (address) { + return _supervisor; + } + + /** + * @dev Allows the current supervisor to update the supervisor address or permanently disable supervision + * @param newSupervisor Address to set as the new supervisor (setting to zero address permanently disables supervision) + * + * Requirements: + * - The caller must be the current supervisor + * - Supervision must be currently enabled + * - If supervision was previously disabled (supervisor is zero address), it cannot be re-enabled + * + * Note: + * - Setting the supervisor to zero address permanently disables supervision + * + * Emits a {SupervisorUpdated} event + */ + function updateSupervisor(address newSupervisor) public virtual onlySupervisor { + _updateSupervisor(newSupervisor); + } + + /** + * @dev Internal function to update the supervisor address + * @param newSupervisor Address to set as the new supervisor (zero address permanently disables supervision) + * + * Emits a SupervisorUpdated event visible only to old and new supervisor + */ + function _updateSupervisor(address newSupervisor) internal virtual { + address oldSupervisor = _supervisor; + _supervisor = newSupervisor; + + _emitSupervisorUpdatedEvent(oldSupervisor, newSupervisor); + } + + /** + * @dev Grants balance viewing permission to a specific address + * @param viewer The address to grant viewing permission to + * + * Requirements: + * - Only the account owner can grant viewing permissions + * + * Emits a ViewerPermissionUpdated event + */ + function grantViewer(address viewer) public virtual { + _updateViewerPermission(msg.sender, viewer, true); + } + + /** + * @dev Revokes balance viewing permission from a specific address + * @param viewer The address to revoke viewing permission from + * + * Requirements: + * - Only the account owner can revoke viewing permissions + * + * Emits a ViewerPermissionUpdated event + */ + function revokeViewer(address viewer) public virtual { + _updateViewerPermission(msg.sender, viewer, false); + } + + /** + * @dev Checks if an address has viewing permission for a specific account + * @param account The account whose permissions to check + * @param viewer The address to check viewing permissions for + * @return bool True if the viewer has permission, false otherwise + */ + function hasViewPermission(address account, address viewer) public view virtual returns (bool) { + return _authorizedViewers[account][viewer]; + } + + /** + * @dev Internal function to update viewer permissions + * @param account The account whose permissions are being updated + * @param viewer The viewer whose permissions are being updated + * @param status The new permission status + * + * Emits a ViewerPermissionUpdated event + */ + function _updateViewerPermission( + address account, + address viewer, + bool status + ) internal virtual { + _authorizedViewers[account][viewer] = status; + _emitViewerPermissionUpdatedEvent(account, viewer, status); + } + + /** + * @dev Implementation of the balance authorization check + * @param account The account address to check authorization for + * @return bool True if authorized, reverts otherwise + * + * Requirements: + * - The caller must be either: + * 1. The account owner + * 2. An authorized viewer for the account + * 3. The current supervisor (if supervision is enabled) + * + * Note: + * - This implementation reverts for unauthorized access rather than returning false + */ + function _authorizeBalance(address account) internal view virtual override returns (bool) { + if (msg.sender != account && + !_authorizedViewers[account][msg.sender] && + (_supervisor == address(0) || msg.sender != _supervisor)) { + revert UCEFSharableUnauthorizedViewer(msg.sender); + } + return true; + } + + /** + * @dev Override to implement supervisor-inclusive event visibility for transfers + * Supervisor can view all transfers for oversight alongside the involved parties + * @param from The sending address + * @param to The receiving address + * @return allowedViewers Array containing sender, receiver, and supervisor (if enabled) + */ + function _getTransferEventViewers( + address from, + address to, + uint256 /* value */ + ) internal view virtual override returns (address[] memory allowedViewers) { + // Count unique non-zero addresses including supervisor (if enabled) + uint256 viewerCount = 0; + if (_supervisor != address(0)) viewerCount++; // Include supervisor if enabled + if (from != address(0) && from != _supervisor) viewerCount++; + if (to != address(0) && to != from && to != _supervisor) viewerCount++; + + allowedViewers = new address[](viewerCount); + uint256 index = 0; + + // Populate viewer list + if (_supervisor != address(0)) { + allowedViewers[index++] = _supervisor; + } + if (from != address(0) && from != _supervisor) { + allowedViewers[index++] = from; + } + if (to != address(0) && to != from && to != _supervisor) { + allowedViewers[index] = to; + } + } + + /** + * @dev Override to implement supervisor-inclusive event visibility for approvals + * Supervisor can view all approvals for oversight alongside owner and spender + * @param owner The address that owns the tokens + * @param spender The address that can spend the tokens + * @return allowedViewers Array containing owner, spender, and supervisor (if enabled) + */ + function _getApprovalEventViewers( + address owner, + address spender, + uint256 /* value */ + ) internal view virtual override returns (address[] memory allowedViewers) { + // Count unique addresses including supervisor (if enabled) + uint256 viewerCount = 0; + if (_supervisor != address(0)) viewerCount++; // Include supervisor if enabled + if (owner != _supervisor) viewerCount++; + if (spender != owner && spender != _supervisor) viewerCount++; + + allowedViewers = new address[](viewerCount); + uint256 index = 0; + + // Populate viewer list + if (_supervisor != address(0)) { + allowedViewers[index++] = _supervisor; + } + if (owner != _supervisor) { + allowedViewers[index++] = owner; + } + if (spender != owner && spender != _supervisor) { + allowedViewers[index] = spender; + } + } + + /** + * @dev Internal function to emit ViewerPermissionUpdated events + * Can be overridden by derived contracts to implement custom emission logic + * Default implementation: visible to account, viewer, and supervisor (if enabled) + * @param account The account whose permissions were updated + * @param viewer The viewer whose permissions were updated + * @param status The new permission status + */ + function _emitViewerPermissionUpdatedEvent(address account, address viewer, bool status) internal virtual { + address[] memory allowedViewers = _getViewerPermissionUpdatedEventViewers(account, viewer, status); + bytes memory payload = abi.encode(account, viewer, status); + + emit PrivateEvent(allowedViewers, EVENT_TYPE_VIEWER_PERMISSION_UPDATED, payload); + } + + /** + * @dev Internal function to determine who can view ViewerPermissionUpdated events + * @param account The account whose permissions were updated + * @param viewer The viewer whose permissions were updated + * @param status The new permission status + * @return allowedViewers Array containing account, viewer, and supervisor (if enabled) + */ + function _getViewerPermissionUpdatedEventViewers( + address account, + address viewer, + bool status + ) internal view virtual returns (address[] memory allowedViewers) { + status; // Available for derived contracts + + // Count unique addresses including supervisor (if enabled) + uint256 viewerCount = 0; + if (_supervisor != address(0)) viewerCount++; // Include supervisor if enabled + if (account != _supervisor) viewerCount++; + if (viewer != account && viewer != _supervisor) viewerCount++; + + allowedViewers = new address[](viewerCount); + uint256 index = 0; + + // Populate viewer list + if (_supervisor != address(0)) { + allowedViewers[index++] = _supervisor; + } + if (account != _supervisor) { + allowedViewers[index++] = account; + } + if (viewer != account && viewer != _supervisor) { + allowedViewers[index] = viewer; + } + } + + /** + * @dev Internal function to emit SupervisorUpdated events + * Can be overridden by derived contracts to implement custom emission logic + * Default implementation: only old and new supervisor can view supervisor changes + * @param previousSupervisor The address of the previous supervisor + * @param newSupervisor The address of the new supervisor + */ + function _emitSupervisorUpdatedEvent(address previousSupervisor, address newSupervisor) internal virtual { + address[] memory allowedViewers = _getSupervisorUpdatedEventViewers(previousSupervisor, newSupervisor); + bytes memory payload = abi.encode(previousSupervisor, newSupervisor); + + emit PrivateEvent(allowedViewers, EVENT_TYPE_SUPERVISOR_UPDATED, payload); + } + + /** + * @dev Internal function to determine who can view SupervisorUpdated events + * Default implementation: only old and new supervisor should see supervisor changes + * @param previousSupervisor The address of the previous supervisor + * @param newSupervisor The address of the new supervisor + * @return allowedViewers Array containing only old and new supervisor + */ + function _getSupervisorUpdatedEventViewers( + address previousSupervisor, + address newSupervisor + ) internal view virtual returns (address[] memory allowedViewers) { + // Count unique non-zero addresses + uint256 viewerCount = 0; + if (previousSupervisor != address(0)) viewerCount++; + if (newSupervisor != address(0) && newSupervisor != previousSupervisor) viewerCount++; + + allowedViewers = new address[](viewerCount); + uint256 index = 0; + + // Populate viewer list + if (previousSupervisor != address(0)) { + allowedViewers[index++] = previousSupervisor; + } + if (newSupervisor != address(0) && newSupervisor != previousSupervisor) { + allowedViewers[index] = newSupervisor; + } + } +} \ No newline at end of file diff --git a/contracts/extensions/ERC1363.sol b/packages/ucef/contracts/extensions/ERC1363.sol similarity index 99% rename from contracts/extensions/ERC1363.sol rename to packages/ucef/contracts/extensions/ERC1363.sol index 9266af2..b093988 100644 --- a/contracts/extensions/ERC1363.sol +++ b/packages/ucef/contracts/extensions/ERC1363.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.20; -import {UCEF} from "../token/UCEF.sol"; +import {UCEF} from "../UCEF.sol"; import {IERC165, ERC165} from "@openzeppelin/contracts/utils/introspection/ERC165.sol"; import {IERC1363} from "@openzeppelin/contracts/interfaces/IERC1363.sol"; import {ERC1363Utils} from "@openzeppelin/contracts/token/ERC20/utils/ERC1363Utils.sol"; diff --git a/contracts/extensions/ERC4626.sol b/packages/ucef/contracts/extensions/ERC4626.sol similarity index 99% rename from contracts/extensions/ERC4626.sol rename to packages/ucef/contracts/extensions/ERC4626.sol index e91e9e1..859f3cf 100644 --- a/contracts/extensions/ERC4626.sol +++ b/packages/ucef/contracts/extensions/ERC4626.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.20; -import {UCEF} from "../token/UCEF.sol"; -import {IUCEF} from "../token/IUCEF.sol"; +import {UCEF} from "../UCEF.sol"; +import {IUCEF} from "../interfaces/IUCEF.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; diff --git a/contracts/extensions/UCEFBurnable.sol b/packages/ucef/contracts/extensions/UCEFBurnable.sol similarity index 96% rename from contracts/extensions/UCEFBurnable.sol rename to packages/ucef/contracts/extensions/UCEFBurnable.sol index 5fcf19a..fda8218 100644 --- a/contracts/extensions/UCEFBurnable.sol +++ b/packages/ucef/contracts/extensions/UCEFBurnable.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.20; -import {UCEF} from "../token/UCEF.sol"; +import {UCEF} from "../UCEF.sol"; import {Context} from "@openzeppelin/contracts/utils/Context.sol"; /** diff --git a/contracts/extensions/UCEFCapped.sol b/packages/ucef/contracts/extensions/UCEFCapped.sol similarity index 97% rename from contracts/extensions/UCEFCapped.sol rename to packages/ucef/contracts/extensions/UCEFCapped.sol index c168075..c4c00fa 100644 --- a/contracts/extensions/UCEFCapped.sol +++ b/packages/ucef/contracts/extensions/UCEFCapped.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.20; -import {UCEF} from "../token/UCEF.sol"; +import {UCEF} from "../UCEF.sol"; /** * @dev Extension of {ERC20} that adds a cap to the supply of tokens. diff --git a/contracts/extensions/UCEFFlashMint.sol b/packages/ucef/contracts/extensions/UCEFFlashMint.sol similarity index 99% rename from contracts/extensions/UCEFFlashMint.sol rename to packages/ucef/contracts/extensions/UCEFFlashMint.sol index c2edf49..1933c74 100644 --- a/contracts/extensions/UCEFFlashMint.sol +++ b/packages/ucef/contracts/extensions/UCEFFlashMint.sol @@ -5,7 +5,7 @@ pragma solidity ^0.8.20; import {IERC3156FlashBorrower} from "@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol"; import {IERC3156FlashLender} from "@openzeppelin/contracts/interfaces/IERC3156FlashLender.sol"; -import {UCEF} from "../token/UCEF.sol"; +import {UCEF} from "../UCEF.sol"; /** * @dev Implementation of the ERC-3156 Flash loans extension, as defined in diff --git a/contracts/extensions/UCEFPausable.sol b/packages/ucef/contracts/extensions/UCEFPausable.sol similarity index 96% rename from contracts/extensions/UCEFPausable.sol rename to packages/ucef/contracts/extensions/UCEFPausable.sol index eccc3a4..c12c905 100644 --- a/contracts/extensions/UCEFPausable.sol +++ b/packages/ucef/contracts/extensions/UCEFPausable.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.20; -import {UCEF} from "../token/UCEF.sol"; +import {UCEF} from "../UCEF.sol"; import {Pausable} from "@openzeppelin/contracts/utils/Pausable.sol"; /** diff --git a/contracts/extensions/UCEFPermit.sol b/packages/ucef/contracts/extensions/UCEFPermit.sol similarity index 98% rename from contracts/extensions/UCEFPermit.sol rename to packages/ucef/contracts/extensions/UCEFPermit.sol index 4476c53..9776969 100644 --- a/contracts/extensions/UCEFPermit.sol +++ b/packages/ucef/contracts/extensions/UCEFPermit.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.20; -import {UCEF} from "../token/UCEF.sol"; +import {UCEF} from "../UCEF.sol"; import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol"; import {ECDSA} from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import {EIP712} from "@openzeppelin/contracts/utils/cryptography/EIP712.sol"; diff --git a/contracts/extensions/UCEFVotes.sol b/packages/ucef/contracts/extensions/UCEFVotes.sol similarity index 98% rename from contracts/extensions/UCEFVotes.sol rename to packages/ucef/contracts/extensions/UCEFVotes.sol index bd7a5b7..1ed370a 100644 --- a/contracts/extensions/UCEFVotes.sol +++ b/packages/ucef/contracts/extensions/UCEFVotes.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.20; -import {UCEF} from "../token/UCEF.sol"; +import {UCEF} from "../UCEF.sol"; import {Votes} from "@openzeppelin/contracts/governance/utils/Votes.sol"; import {Checkpoints} from "@openzeppelin/contracts/utils/structs/Checkpoints.sol"; diff --git a/contracts/extensions/UCEFWrapper.sol b/packages/ucef/contracts/extensions/UCEFWrapper.sol similarity index 97% rename from contracts/extensions/UCEFWrapper.sol rename to packages/ucef/contracts/extensions/UCEFWrapper.sol index 8dbfc66..3f70bb7 100644 --- a/contracts/extensions/UCEFWrapper.sol +++ b/packages/ucef/contracts/extensions/UCEFWrapper.sol @@ -3,8 +3,8 @@ pragma solidity ^0.8.20; -import {UCEF} from "../token/UCEF.sol"; -import {IUCEF} from "../token/IUCEF.sol"; +import {UCEF} from "../UCEF.sol"; +import {IUCEF} from "../interfaces/IUCEF.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; diff --git a/contracts/interfaces/IERC1363.sol b/packages/ucef/contracts/interfaces/IERC1363.sol similarity index 97% rename from contracts/interfaces/IERC1363.sol rename to packages/ucef/contracts/interfaces/IERC1363.sol index 5cdd86d..2f4bdf3 100644 --- a/contracts/interfaces/IERC1363.sol +++ b/packages/ucef/contracts/interfaces/IERC1363.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import {IUCEF} from "../token/IUCEF.sol"; +import {IUCEF} from "../interfaces/IUCEF.sol"; import {IERC165} from "@openzeppelin/contracts/utils/introspection/IERC165.sol"; /** diff --git a/contracts/interfaces/IERC4626.sol b/packages/ucef/contracts/interfaces/IERC4626.sol similarity index 98% rename from contracts/interfaces/IERC4626.sol rename to packages/ucef/contracts/interfaces/IERC4626.sol index 52d1265..d0111e8 100644 --- a/contracts/interfaces/IERC4626.sol +++ b/packages/ucef/contracts/interfaces/IERC4626.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import {IUCEF} from "../token/IUCEF.sol"; +import {IUCEF} from "../interfaces/IUCEF.sol"; import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; /** diff --git a/contracts/token/IUCEF.sol b/packages/ucef/contracts/interfaces/IUCEF.sol similarity index 80% rename from contracts/token/IUCEF.sol rename to packages/ucef/contracts/interfaces/IUCEF.sol index 1b68f24..10b6671 100644 --- a/contracts/token/IUCEF.sol +++ b/packages/ucef/contracts/interfaces/IUCEF.sol @@ -8,6 +8,18 @@ import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; * @dev Interface for the UCEF (User Confidential ERC20 Funds) contract */ interface IUCEF is IERC20 { + /** + * @dev Private Event for selective visibility of on-chain events + * @param allowedViewers List of addresses authorized to view the event + * @param eventType The keccak256 hash of the original event signature + * @param payload The ABI-encoded event arguments + */ + event PrivateEvent( + address[] allowedViewers, + bytes32 indexed eventType, + bytes payload + ); + /** * @dev Returns the amount of tokens owned by `account`. * Only returns balance if the caller is authorized. diff --git a/contracts/interfaces/IUCEFBurnable.sol b/packages/ucef/contracts/interfaces/IUCEFBurnable.sol similarity index 93% rename from contracts/interfaces/IUCEFBurnable.sol rename to packages/ucef/contracts/interfaces/IUCEFBurnable.sol index c072d79..d363fbb 100644 --- a/contracts/interfaces/IUCEFBurnable.sol +++ b/packages/ucef/contracts/interfaces/IUCEFBurnable.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import {IUCEF} from "../token/IUCEF.sol"; +import {IUCEF} from "../interfaces/IUCEF.sol"; /** * @dev Interface of the UCEFBurnable extension, which allows token holders to destroy their tokens diff --git a/contracts/interfaces/IUCEFCapped.sol b/packages/ucef/contracts/interfaces/IUCEFCapped.sol similarity index 89% rename from contracts/interfaces/IUCEFCapped.sol rename to packages/ucef/contracts/interfaces/IUCEFCapped.sol index 91cd181..652a5bc 100644 --- a/contracts/interfaces/IUCEFCapped.sol +++ b/packages/ucef/contracts/interfaces/IUCEFCapped.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import {IUCEF} from "../token/IUCEF.sol"; +import {IUCEF} from "../interfaces/IUCEF.sol"; /** * @dev Interface for the UCEFCapped extension that adds a cap to the supply of tokens. diff --git a/contracts/interfaces/IUCEFFlashMint.sol b/packages/ucef/contracts/interfaces/IUCEFFlashMint.sol similarity index 94% rename from contracts/interfaces/IUCEFFlashMint.sol rename to packages/ucef/contracts/interfaces/IUCEFFlashMint.sol index 742983c..41e4d8d 100644 --- a/contracts/interfaces/IUCEFFlashMint.sol +++ b/packages/ucef/contracts/interfaces/IUCEFFlashMint.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import {IUCEF} from "../token/IUCEF.sol"; +import {IUCEF} from "../interfaces/IUCEF.sol"; import {IERC3156FlashBorrower} from "@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol"; import {IERC3156FlashLender} from "@openzeppelin/contracts/interfaces/IERC3156FlashLender.sol"; diff --git a/contracts/interfaces/IUCEFOwned.sol b/packages/ucef/contracts/interfaces/IUCEFOwned.sol similarity index 94% rename from contracts/interfaces/IUCEFOwned.sol rename to packages/ucef/contracts/interfaces/IUCEFOwned.sol index 6ae0179..8515305 100644 --- a/contracts/interfaces/IUCEFOwned.sol +++ b/packages/ucef/contracts/interfaces/IUCEFOwned.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import {IUCEF} from "../token/IUCEF.sol"; +import {IUCEF} from "../interfaces/IUCEF.sol"; /** * @title IUCEFOwned diff --git a/contracts/interfaces/IUCEFPausable.sol b/packages/ucef/contracts/interfaces/IUCEFPausable.sol similarity index 84% rename from contracts/interfaces/IUCEFPausable.sol rename to packages/ucef/contracts/interfaces/IUCEFPausable.sol index 7017a59..f6ab1ca 100644 --- a/contracts/interfaces/IUCEFPausable.sol +++ b/packages/ucef/contracts/interfaces/IUCEFPausable.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import {IUCEF} from "../token/IUCEF.sol"; +import {IUCEF} from "../interfaces/IUCEF.sol"; /** * @dev Interface for the UCEFPausable extension, which allows token transfers diff --git a/contracts/interfaces/IUCEFPermit.sol b/packages/ucef/contracts/interfaces/IUCEFPermit.sol similarity index 100% rename from contracts/interfaces/IUCEFPermit.sol rename to packages/ucef/contracts/interfaces/IUCEFPermit.sol diff --git a/contracts/interfaces/IUCEFRegulated.sol b/packages/ucef/contracts/interfaces/IUCEFRegulated.sol similarity index 97% rename from contracts/interfaces/IUCEFRegulated.sol rename to packages/ucef/contracts/interfaces/IUCEFRegulated.sol index e1d9223..cae2729 100644 --- a/contracts/interfaces/IUCEFRegulated.sol +++ b/packages/ucef/contracts/interfaces/IUCEFRegulated.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import {IUCEF} from "../token/IUCEF.sol"; +import {IUCEF} from "../interfaces/IUCEF.sol"; /** * @title IUCEFRegulated diff --git a/contracts/interfaces/IUCEFSharable.sol b/packages/ucef/contracts/interfaces/IUCEFSharable.sol similarity index 98% rename from contracts/interfaces/IUCEFSharable.sol rename to packages/ucef/contracts/interfaces/IUCEFSharable.sol index de8e501..d286539 100644 --- a/contracts/interfaces/IUCEFSharable.sol +++ b/packages/ucef/contracts/interfaces/IUCEFSharable.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import {IUCEF} from "../token/IUCEF.sol"; +import {IUCEF} from "../interfaces/IUCEF.sol"; /** * @title IUCEFSharable diff --git a/contracts/interfaces/IUCEFVotes.sol b/packages/ucef/contracts/interfaces/IUCEFVotes.sol similarity index 95% rename from contracts/interfaces/IUCEFVotes.sol rename to packages/ucef/contracts/interfaces/IUCEFVotes.sol index 4daee0c..7be11db 100644 --- a/contracts/interfaces/IUCEFVotes.sol +++ b/packages/ucef/contracts/interfaces/IUCEFVotes.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import {IUCEF} from "../token/IUCEF.sol"; +import {IUCEF} from "../interfaces/IUCEF.sol"; import {Checkpoints} from "@openzeppelin/contracts/utils/structs/Checkpoints.sol"; /** diff --git a/contracts/interfaces/IUCEFWrapper.sol b/packages/ucef/contracts/interfaces/IUCEFWrapper.sol similarity index 91% rename from contracts/interfaces/IUCEFWrapper.sol rename to packages/ucef/contracts/interfaces/IUCEFWrapper.sol index a6738b3..3997fec 100644 --- a/contracts/interfaces/IUCEFWrapper.sol +++ b/packages/ucef/contracts/interfaces/IUCEFWrapper.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.20; -import {IUCEF} from "../token/IUCEF.sol"; +import {IUCEF} from "../interfaces/IUCEF.sol"; /** * @dev Interface for the UCEFWrapper extension, which supports wrapping of underlying tokens. diff --git a/packages/ucef/hardhat.config.ts b/packages/ucef/hardhat.config.ts new file mode 100644 index 0000000..f4115a5 --- /dev/null +++ b/packages/ucef/hardhat.config.ts @@ -0,0 +1,30 @@ +import { HardhatUserConfig } from 'hardhat/config' +import '@typechain/hardhat' + +const config: HardhatUserConfig = { + solidity: { + compilers: [ + { + version: '0.8.28', + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, + ], + }, + typechain: { + outDir: './types', + target: 'ethers-v6', + }, + paths: { + sources: './contracts', + tests: './test', + cache: './cache', + artifacts: './artifacts', + }, +} + +export default config diff --git a/packages/ucef/index.d.ts b/packages/ucef/index.d.ts new file mode 100644 index 0000000..b2d8230 --- /dev/null +++ b/packages/ucef/index.d.ts @@ -0,0 +1,35 @@ +export { + UCEF, + UCEFOwned, + UCEFRegulated, + UCEFSharable, + // Extensions + UCEFBurnable, + UCEFCapped, + UCEFFlashMint, + UCEFPausable, + UCEFPermit, + UCEFVotes, + UCEFWrapper, + ERC1363, + ERC4626, +} from './types' + +export type Abi = any[]; +export interface Artifact { + contractName: string; + sourceName: string; + bytecode: string; + abi: AbiT; + linkReferences: Record>>; +} + +export namespace UCEFContracts { + export const UCEF: Artifact + export const UCEFOwned: Artifact + export const UCEFRegulated: Artifact + export const UCEFSharable: Artifact +} diff --git a/packages/ucef/index.js b/packages/ucef/index.js new file mode 100644 index 0000000..fc3bb7c --- /dev/null +++ b/packages/ucef/index.js @@ -0,0 +1,10 @@ +const UCEFContracts = { + UCEF: require('./artifacts/contracts/UCEF.sol/UCEF.json'), + UCEFOwned: require('./artifacts/contracts/UCEFOwned.sol/UCEFOwned.json'), + UCEFRegulated: require('./artifacts/contracts/UCEFRegulated.sol/UCEFRegulated.json'), + UCEFSharable: require('./artifacts/contracts/UCEFSharable.sol/UCEFSharable.json'), +} + +module.exports = { + UCEFContracts, +} diff --git a/packages/ucef/package.json b/packages/ucef/package.json new file mode 100644 index 0000000..5dc55e4 --- /dev/null +++ b/packages/ucef/package.json @@ -0,0 +1,49 @@ +{ + "name": "@appliedblockchain/ucef", + "description": "Unopinionated Confidential ERC-20 Framework (UCEF)", + "version": "0.0.1", + "keywords": [ + "solidity", + "ethereum", + "smart", + "contracts", + "erc-20", + "confidential", + "privacy", + "UCEF" + ], + "author": "Applied Blockchain ", + "license": "MIT", + "files": [ + "contracts", + "artifacts", + "types", + "index.js", + "index.d.ts" + ], + "main": "index.js", + "types": "index.d.ts", + "scripts": { + "compile": "hardhat compile", + "clean": "hardhat clean" + }, + "dependencies": { + "ethers": "6.13.2" + }, + "devDependencies": { + "@openzeppelin/contracts": "5.4.0", + "@openzeppelin/contracts-upgradeable": "5.4.0", + "@tokenysolutions/t-rex": "4.1.6", + "@typechain/ethers-v6": "0.5.1", + "@typechain/hardhat": "9.1.0", + "hardhat": "2.22.10" + }, + "repository": { + "type": "git", + "url": "https://github.com/appliedblockchain/confidential-erc-20.git" + }, + "bugs": { + "url": "https://github.com/appliedblockchain/confidential-erc-20/issues" + }, + "homepage": "https://github.com/appliedblockchain/confidential-erc-20#readme" +} diff --git a/patches/@tokenysolutions__t-rex@4.1.6.patch b/patches/@tokenysolutions__t-rex@4.1.6.patch new file mode 100644 index 0000000..67fab38 --- /dev/null +++ b/patches/@tokenysolutions__t-rex@4.1.6.patch @@ -0,0 +1,67 @@ +diff --git a/contracts/token/Token.sol b/contracts/token/Token.sol +index 4ea309184be4b34cd92c6cf4c983e8b084c320c2..752209ead4f71c7e0045a4dd92e9f22792c70efa 100755 +--- a/contracts/token/Token.sol ++++ b/contracts/token/Token.sol +@@ -221,7 +221,7 @@ contract Token is IToken, AgentRoleUpgradeable, TokenStorage { + address _from, + address _to, + uint256 _amount +- ) external override whenNotPaused returns (bool) { ++ ) external virtual whenNotPaused returns (bool) { + require(!_frozen[_to] && !_frozen[_from], "wallet is frozen"); + require(_amount <= balanceOf(_from) - (_frozenTokens[_from]), "Insufficient Balance"); + if (_tokenIdentityRegistry.isVerified(_to) && _tokenCompliance.canTransfer(_from, _to, _amount)) { +@@ -414,7 +414,7 @@ contract Token is IToken, AgentRoleUpgradeable, TokenStorage { + * @param _amount The number of tokens to transfer + * @return `true` if successful and revert if unsuccessful + */ +- function transfer(address _to, uint256 _amount) public override whenNotPaused returns (bool) { ++ function transfer(address _to, uint256 _amount) public virtual whenNotPaused returns (bool) { + require(!_frozen[_to] && !_frozen[msg.sender], "wallet is frozen"); + require(_amount <= balanceOf(msg.sender) - (_frozenTokens[msg.sender]), "Insufficient Balance"); + if (_tokenIdentityRegistry.isVerified(_to) && _tokenCompliance.canTransfer(msg.sender, _to, _amount)) { +@@ -432,7 +432,7 @@ contract Token is IToken, AgentRoleUpgradeable, TokenStorage { + address _from, + address _to, + uint256 _amount +- ) public override onlyAgent returns (bool) { ++ ) public virtual onlyAgent returns (bool) { + require(balanceOf(_from) >= _amount, "sender balance too low"); + uint256 freeBalance = balanceOf(_from) - (_frozenTokens[_from]); + if (_amount > freeBalance) { +@@ -461,7 +461,7 @@ contract Token is IToken, AgentRoleUpgradeable, TokenStorage { + /** + * @dev See {IToken-burn}. + */ +- function burn(address _userAddress, uint256 _amount) public override onlyAgent { ++ function burn(address _userAddress, uint256 _amount) public virtual onlyAgent { + require(balanceOf(_userAddress) >= _amount, "cannot burn more than balance"); + uint256 freeBalance = balanceOf(_userAddress) - _frozenTokens[_userAddress]; + if (_amount > freeBalance) { +@@ -485,7 +485,7 @@ contract Token is IToken, AgentRoleUpgradeable, TokenStorage { + /** + * @dev See {IToken-freezePartialTokens}. + */ +- function freezePartialTokens(address _userAddress, uint256 _amount) public override onlyAgent { ++ function freezePartialTokens(address _userAddress, uint256 _amount) public virtual onlyAgent { + uint256 balance = balanceOf(_userAddress); + require(balance >= _frozenTokens[_userAddress] + _amount, "Amount exceeds available balance"); + _frozenTokens[_userAddress] = _frozenTokens[_userAddress] + (_amount); +@@ -495,7 +495,7 @@ contract Token is IToken, AgentRoleUpgradeable, TokenStorage { + /** + * @dev See {IToken-unfreezePartialTokens}. + */ +- function unfreezePartialTokens(address _userAddress, uint256 _amount) public override onlyAgent { ++ function unfreezePartialTokens(address _userAddress, uint256 _amount) public virtual onlyAgent { + require(_frozenTokens[_userAddress] >= _amount, "Amount should be less than or equal to frozen tokens"); + _frozenTokens[_userAddress] = _frozenTokens[_userAddress] - (_amount); + emit TokensUnfrozen(_userAddress, _amount); +@@ -524,7 +524,7 @@ contract Token is IToken, AgentRoleUpgradeable, TokenStorage { + /** + * @dev See {IERC20-balanceOf}. + */ +- function balanceOf(address _userAddress) public view override returns (uint256) { ++ function balanceOf(address _userAddress) public view virtual returns (uint256) { + return _balances[_userAddress]; + } + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 42a198e..0b15356 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,126 +4,209 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +patchedDependencies: + '@tokenysolutions/t-rex@4.1.6': + hash: iry6mwuqzhz255vox72o2g6uvq + path: patches/@tokenysolutions__t-rex@4.1.6.patch + importers: .: devDependencies: '@appliedblockchain/silentdatarollup-core': - specifier: ^0.1.3 - version: 0.1.3 + specifier: 1.0.6 + version: 1.0.6 + '@appliedblockchain/silentdatarollup-ethers-provider': + specifier: 1.0.6 + version: 1.0.6 '@appliedblockchain/silentdatarollup-hardhat-plugin': - specifier: ^0.1.3 - version: 0.1.3(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)) + specifier: 1.0.6 + version: 1.0.6(ethers@6.13.2)(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)) + '@appliedblockchain/ucef': + specifier: workspace:* + version: link:packages/ucef + '@appliedblockchain/ucef-3643': + specifier: workspace:* + version: link:packages/ucef-3643 '@nomicfoundation/hardhat-chai-matchers': - specifier: ^2.0.0 - version: 2.0.8(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(chai@4.5.0)(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)) + specifier: 2.0.7 + version: 2.0.7(@nomicfoundation/hardhat-ethers@3.0.6(ethers@6.13.2)(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)))(chai@4.5.0)(ethers@6.13.2)(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)) '@nomicfoundation/hardhat-ethers': - specifier: ^3.0.0 - version: 3.0.8(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)) + specifier: 3.0.6 + version: 3.0.6(ethers@6.13.2)(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)) '@nomicfoundation/hardhat-ignition': - specifier: ^0.15.0 - version: 0.15.10(@nomicfoundation/hardhat-verify@2.0.13(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)) + specifier: 0.15.10 + version: 0.15.10(@nomicfoundation/hardhat-verify@2.0.8(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)))(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)) '@nomicfoundation/hardhat-network-helpers': - specifier: ^1.0.0 - version: 1.0.12(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)) + specifier: 1.0.10 + version: 1.0.10(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)) '@nomicfoundation/hardhat-toolbox': - specifier: ^5.0.0 - version: 5.0.0(@nomicfoundation/hardhat-chai-matchers@2.0.8(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(chai@4.5.0)(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(@nomicfoundation/hardhat-ignition-ethers@0.15.10(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(@nomicfoundation/hardhat-ignition@0.15.10(@nomicfoundation/hardhat-verify@2.0.13(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(@nomicfoundation/ignition-core@0.15.10)(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(@nomicfoundation/hardhat-network-helpers@1.0.12(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(@nomicfoundation/hardhat-verify@2.0.13(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(@typechain/ethers-v6@0.5.1(ethers@6.13.5)(typechain@8.3.2(typescript@5.8.2))(typescript@5.8.2))(@typechain/hardhat@9.1.0(@typechain/ethers-v6@0.5.1(ethers@6.13.5)(typechain@8.3.2(typescript@5.8.2))(typescript@5.8.2))(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2))(typechain@8.3.2(typescript@5.8.2)))(@types/chai@4.3.20)(@types/mocha@10.0.10)(@types/node@20.17.24)(chai@4.5.0)(ethers@6.13.5)(hardhat-gas-reporter@1.0.10(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2))(solidity-coverage@0.8.14(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typechain@8.3.2(typescript@5.8.2))(typescript@5.8.2) + specifier: 5.0.0 + version: 5.0.0(32tvdyqhusnhk5bf77tetugxmm) '@nomicfoundation/hardhat-verify': - specifier: ^2.0.0 - version: 2.0.13(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)) + specifier: 2.0.8 + version: 2.0.8(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)) '@nomicfoundation/ignition-core': - specifier: ^0.15.0 - version: 0.15.10 + specifier: 0.15.13 + version: 0.15.13 + '@onchain-id/solidity': + specifier: 2.2.1 + version: 2.2.1 '@openzeppelin/contracts': - specifier: 5.2.0 - version: 5.2.0 + specifier: 5.4.0 + version: 5.4.0 + '@openzeppelin/contracts-upgradeable': + specifier: 5.4.0 + version: 5.4.0(@openzeppelin/contracts@5.4.0) + '@tokenysolutions/t-rex': + specifier: 4.1.6 + version: 4.1.6(patch_hash=iry6mwuqzhz255vox72o2g6uvq) '@typechain/ethers-v6': - specifier: ^0.5.0 - version: 0.5.1(ethers@6.13.5)(typechain@8.3.2(typescript@5.8.2))(typescript@5.8.2) + specifier: 0.5.1 + version: 0.5.1(ethers@6.13.2)(typechain@8.3.2(typescript@5.9.2))(typescript@5.9.2) '@typechain/hardhat': - specifier: ^9.0.0 - version: 9.1.0(@typechain/ethers-v6@0.5.1(ethers@6.13.5)(typechain@8.3.2(typescript@5.8.2))(typescript@5.8.2))(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2))(typechain@8.3.2(typescript@5.8.2)) + specifier: 9.1.0 + version: 9.1.0(@typechain/ethers-v6@0.5.1(ethers@6.13.2)(typechain@8.3.2(typescript@5.9.2))(typescript@5.9.2))(ethers@6.13.2)(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2))(typechain@8.3.2(typescript@5.9.2)) '@types/chai': - specifier: ^4.3.11 + specifier: 4.3.20 version: 4.3.20 '@types/mocha': - specifier: ^10.0.6 + specifier: 10.0.10 version: 10.0.10 '@types/node': - specifier: ^20.0.0 - version: 20.17.24 + specifier: 20.19.17 + version: 20.19.17 '@typescript-eslint/eslint-plugin': - specifier: ^6.14.0 - version: 6.21.0(@typescript-eslint/parser@6.21.0(eslint@9.22.0)(typescript@5.8.2))(eslint@9.22.0)(typescript@5.8.2) + specifier: 8.0.0 + version: 8.0.0(@typescript-eslint/parser@8.0.0(eslint@9.36.0)(typescript@5.9.2))(eslint@9.36.0)(typescript@5.9.2) '@typescript-eslint/parser': - specifier: ^6.14.0 - version: 6.21.0(eslint@9.22.0)(typescript@5.8.2) + specifier: 8.0.0 + version: 8.0.0(eslint@9.36.0)(typescript@5.9.2) chai: - specifier: ^4.2.0 + specifier: 4.5.0 version: 4.5.0 dotenv: - specifier: ^16.4.7 - version: 16.4.7 + specifier: 16.6.1 + version: 16.6.1 eslint: - specifier: ^9.22.0 - version: 9.22.0 + specifier: 9.36.0 + version: 9.36.0 eslint-config-prettier: - specifier: ^9.0.0 - version: 9.1.0(eslint@9.22.0) + specifier: 9.1.2 + version: 9.1.2(eslint@9.36.0) eslint-plugin-prettier: - specifier: ^5.0.0 - version: 5.2.3(eslint-config-prettier@9.1.0(eslint@9.22.0))(eslint@9.22.0)(prettier@3.5.3) + specifier: 5.5.4 + version: 5.5.4(eslint-config-prettier@9.1.2(eslint@9.36.0))(eslint@9.36.0)(prettier@3.6.2) ethers: - specifier: ^6.9.0 - version: 6.13.5 + specifier: 6.13.2 + version: 6.13.2 globals: - specifier: ^16.0.0 - version: 16.0.0 + specifier: 16.4.0 + version: 16.4.0 hardhat: - specifier: ^2.19.0 - version: 2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2) + specifier: 2.22.10 + version: 2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2) hardhat-gas-reporter: - specifier: ^1.0.8 - version: 1.0.10(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)) + specifier: 1.0.10 + version: 1.0.10(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)) + picocolors: + specifier: 1.1.1 + version: 1.1.1 prettier: - specifier: ^3.0.0 - version: 3.5.3 + specifier: 3.6.2 + version: 3.6.2 solidity-coverage: - specifier: ^0.8.1 - version: 0.8.14(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)) + specifier: 0.8.16 + version: 0.8.16(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)) ts-node: - specifier: ^10.9.2 - version: 10.9.2(@types/node@20.17.24)(typescript@5.8.2) + specifier: 10.9.2 + version: 10.9.2(@types/node@20.19.17)(typescript@5.9.2) typechain: - specifier: ^8.3.0 - version: 8.3.2(typescript@5.8.2) + specifier: 8.3.2 + version: 8.3.2(typescript@5.9.2) typescript: - specifier: ^5.0.0 - version: 5.8.2 + specifier: 5.9.2 + version: 5.9.2 + + packages/ucef: + dependencies: + ethers: + specifier: 6.13.2 + version: 6.13.2 + devDependencies: + '@openzeppelin/contracts': + specifier: 5.4.0 + version: 5.4.0 + '@openzeppelin/contracts-upgradeable': + specifier: 5.4.0 + version: 5.4.0(@openzeppelin/contracts@5.4.0) + '@tokenysolutions/t-rex': + specifier: 4.1.6 + version: 4.1.6(patch_hash=iry6mwuqzhz255vox72o2g6uvq) + '@typechain/ethers-v6': + specifier: 0.5.1 + version: 0.5.1(ethers@6.13.2)(typechain@8.3.2(typescript@5.9.2))(typescript@5.9.2) + '@typechain/hardhat': + specifier: 9.1.0 + version: 9.1.0(@typechain/ethers-v6@0.5.1(ethers@6.13.2)(typechain@8.3.2(typescript@5.9.2))(typescript@5.9.2))(ethers@6.13.2)(hardhat@2.22.10(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2))(typescript@5.9.2))(typechain@8.3.2(typescript@5.9.2)) + hardhat: + specifier: 2.22.10 + version: 2.22.10(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2))(typescript@5.9.2) + + packages/ucef-3643: + dependencies: + ethers: + specifier: 6.13.2 + version: 6.13.2 + devDependencies: + '@onchain-id/solidity': + specifier: 2.2.1 + version: 2.2.1 + '@openzeppelin/contracts': + specifier: 4.9.6 + version: 4.9.6 + '@openzeppelin/contracts-upgradeable': + specifier: 4.9.6 + version: 4.9.6 + '@tokenysolutions/t-rex': + specifier: 4.1.6 + version: 4.1.6(patch_hash=iry6mwuqzhz255vox72o2g6uvq) + '@typechain/ethers-v6': + specifier: 0.5.1 + version: 0.5.1(ethers@6.13.2)(typechain@8.3.2(typescript@5.9.2))(typescript@5.9.2) + '@typechain/hardhat': + specifier: 9.1.0 + version: 9.1.0(@typechain/ethers-v6@0.5.1(ethers@6.13.2)(typechain@8.3.2(typescript@5.9.2))(typescript@5.9.2))(ethers@6.13.2)(hardhat@2.22.10(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2))(typescript@5.9.2))(typechain@8.3.2(typescript@5.9.2)) + hardhat: + specifier: 2.22.10 + version: 2.22.10(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2))(typescript@5.9.2) packages: '@adraffy/ens-normalize@1.10.1': resolution: {integrity: sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==} - '@appliedblockchain/silentdatarollup-core@0.1.3': - resolution: {integrity: sha512-bP/BeIk322eR3C54+pvpxfbJOhLPHDGX6M8qdgYqBvYkWYiz7oVwn3QnxnGbLnrYjA/k8Wwa9mC8RXBQkvjfjw==, tarball: https://npm.pkg.github.com/download/@appliedblockchain/silentdatarollup-core/0.1.3/668af20792e9536693a2101256cd99dfdcdd6e73} + '@appliedblockchain/silentdatarollup-core@1.0.6': + resolution: {integrity: sha512-GEahN9bpVMkas4vhw7Npjln0r28Z04bk1kWWOu0UEQJYuex675ITrYQQHFA6CdoLnUBRNzA5usm6ytRXkFY/tQ==} + engines: {node: '>=18.0.0'} + + '@appliedblockchain/silentdatarollup-ethers-provider@1.0.6': + resolution: {integrity: sha512-gt6SbZWaR1Uqg2dkJ5Opp1rtBM7SqNBDZq26q9PRl82sSRtIYqFF4JSTQqekRUTqEcOV2xpSK0u/X36xeMkp5w==} engines: {node: '>=18.0.0'} - '@appliedblockchain/silentdatarollup-hardhat-plugin@0.1.3': - resolution: {integrity: sha512-EmV1x4QHo9Yd8/nX+6rCBXt0haGzsuvMtEJfrerNNencOpQfZUirEH9t+Jr1Kvl/Py+WKt7/j7fka/eGwAPNoA==, tarball: https://npm.pkg.github.com/download/@appliedblockchain/silentdatarollup-hardhat-plugin/0.1.3/5f055fd89d8c86a4ee9aad8fa8764f7c50c1881b} + '@appliedblockchain/silentdatarollup-hardhat-plugin@1.0.6': + resolution: {integrity: sha512-aBAb3u2qCQpIG4zVbw5z/h1es4o0Y6Xiyi3xpWSaoKEfLeBhkSpuyjARyweSFlWBag8+6QcRBV5oYSolfXq1Cw==} engines: {node: '>=18.0.0'} peerDependencies: - ethers: ^6.13.2 - hardhat: ^2.22.10 + ethers: 6.13.2 + hardhat: 2.22.10 '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} - '@eslint-community/eslint-utils@4.5.0': - resolution: {integrity: sha512-RoV8Xs9eNwiDvhv7M+xcL4PWyRyIXRY/FLp3buU4h1EYfdF7unWUy3dOjPqb3C7rMUewIcqwW850PgS8h1o1yg==} + '@eslint-community/eslint-utils@4.9.0': + resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 @@ -132,32 +215,32 @@ packages: resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/config-array@0.19.2': - resolution: {integrity: sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w==} + '@eslint/config-array@0.21.0': + resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/config-helpers@0.1.0': - resolution: {integrity: sha512-kLrdPDJE1ckPo94kmPPf9Hfd0DU0Jw6oKYrhe+pwSC0iTUInmTa+w6fw8sGgcfkFJGNdWOUeOaDM4quW4a7OkA==} + '@eslint/config-helpers@0.3.1': + resolution: {integrity: sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/core@0.12.0': - resolution: {integrity: sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==} + '@eslint/core@0.15.2': + resolution: {integrity: sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/eslintrc@3.3.0': - resolution: {integrity: sha512-yaVPAiNAalnCZedKLdR21GOGILMLKPyqSLWaAjQFvYA2i/ciDi8ArYVr69Anohb6cH2Ukhqti4aFnYyPm8wdwQ==} + '@eslint/eslintrc@3.3.1': + resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/js@9.22.0': - resolution: {integrity: sha512-vLFajx9o8d1/oL2ZkpMYbkLv8nDB6yaIwFNt7nI4+I80U/z03SxmfOMsLbvWr3p7C+Wnoh//aOu2pQW8cS0HCQ==} + '@eslint/js@9.36.0': + resolution: {integrity: sha512-uhCbYtYynH30iZErszX78U+nR3pJU3RHGQ57NXy5QupD4SBVwDeU8TNBy+MjMngc1UyIW9noKqsRqfjQTBU2dw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/object-schema@2.1.6': resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/plugin-kit@0.2.7': - resolution: {integrity: sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==} + '@eslint/plugin-kit@0.3.5': + resolution: {integrity: sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ethereumjs/rlp@4.0.1': @@ -270,28 +353,32 @@ packages: resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} - '@humanfs/node@0.16.6': - resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} + '@humanfs/node@0.16.7': + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} engines: {node: '>=18.18.0'} '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} - '@humanwhocodes/retry@0.3.1': - resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - '@humanwhocodes/retry@0.4.2': - resolution: {integrity: sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==} - engines: {node: '>=18.18'} + '@isaacs/balanced-match@4.0.1': + resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} + engines: {node: 20 || >=22} + + '@isaacs/brace-expansion@5.0.0': + resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} + engines: {node: 20 || >=22} '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} - '@jridgewell/sourcemap-codec@1.5.0': - resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} @@ -317,8 +404,8 @@ packages: resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} engines: {node: '>= 16'} - '@noble/hashes@1.7.1': - resolution: {integrity: sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==} + '@noble/hashes@1.8.0': + resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} engines: {node: ^14.21.3 || >=16} '@noble/secp256k1@1.7.1': @@ -336,36 +423,36 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@nomicfoundation/edr-darwin-arm64@0.8.0': - resolution: {integrity: sha512-sKTmOu/P5YYhxT0ThN2Pe3hmCE/5Ag6K/eYoiavjLWbR7HEb5ZwPu2rC3DpuUk1H+UKJqt7o4/xIgJxqw9wu6A==} + '@nomicfoundation/edr-darwin-arm64@0.5.2': + resolution: {integrity: sha512-Gm4wOPKhbDjGTIRyFA2QUAPfCXA1AHxYOKt3yLSGJkQkdy9a5WW+qtqKeEKHc/+4wpJSLtsGQfpzyIzggFfo/A==} engines: {node: '>= 18'} - '@nomicfoundation/edr-darwin-x64@0.8.0': - resolution: {integrity: sha512-8ymEtWw1xf1Id1cc42XIeE+9wyo3Dpn9OD/X8GiaMz9R70Ebmj2g+FrbETu8o6UM+aL28sBZQCiCzjlft2yWAg==} + '@nomicfoundation/edr-darwin-x64@0.5.2': + resolution: {integrity: sha512-ClyABq2dFCsrYEED3/UIO0c7p4H1/4vvlswFlqUyBpOkJccr75qIYvahOSJRM62WgUFRhbSS0OJXFRwc/PwmVg==} engines: {node: '>= 18'} - '@nomicfoundation/edr-linux-arm64-gnu@0.8.0': - resolution: {integrity: sha512-h/wWzS2EyQuycz+x/SjMRbyA+QMCCVmotRsgM1WycPARvVZWIVfwRRsKoXKdCftsb3S8NTprqBdJlOmsFyETFA==} + '@nomicfoundation/edr-linux-arm64-gnu@0.5.2': + resolution: {integrity: sha512-HWMTVk1iOabfvU2RvrKLDgtFjJZTC42CpHiw2h6rfpsgRqMahvIlx2jdjWYzFNy1jZKPTN1AStQ/91MRrg5KnA==} engines: {node: '>= 18'} - '@nomicfoundation/edr-linux-arm64-musl@0.8.0': - resolution: {integrity: sha512-gnWxDgdkka0O9GpPX/gZT3REeKYV28Guyg13+Vj/bbLpmK1HmGh6Kx+fMhWv+Ht/wEmGDBGMCW1wdyT/CftJaQ==} + '@nomicfoundation/edr-linux-arm64-musl@0.5.2': + resolution: {integrity: sha512-CwsQ10xFx/QAD5y3/g5alm9+jFVuhc7uYMhrZAu9UVF+KtVjeCvafj0PaVsZ8qyijjqVuVsJ8hD1x5ob7SMcGg==} engines: {node: '>= 18'} - '@nomicfoundation/edr-linux-x64-gnu@0.8.0': - resolution: {integrity: sha512-DTMiAkgAx+nyxcxKyxFZk1HPakXXUCgrmei7r5G7kngiggiGp/AUuBBWFHi8xvl2y04GYhro5Wp+KprnLVoAPA==} + '@nomicfoundation/edr-linux-x64-gnu@0.5.2': + resolution: {integrity: sha512-CWVCEdhWJ3fmUpzWHCRnC0/VLBDbqtqTGTR6yyY1Ep3S3BOrHEAvt7h5gx85r2vLcztisu2vlDq51auie4IU1A==} engines: {node: '>= 18'} - '@nomicfoundation/edr-linux-x64-musl@0.8.0': - resolution: {integrity: sha512-iTITWe0Zj8cNqS0xTblmxPbHVWwEtMiDC+Yxwr64d7QBn/1W0ilFQ16J8gB6RVVFU3GpfNyoeg3tUoMpSnrm6Q==} + '@nomicfoundation/edr-linux-x64-musl@0.5.2': + resolution: {integrity: sha512-+aJDfwhkddy2pP5u1ISg3IZVAm0dO836tRlDTFWtvvSMQ5hRGqPcWwlsbobhDQsIxhPJyT7phL0orCg5W3WMeA==} engines: {node: '>= 18'} - '@nomicfoundation/edr-win32-x64-msvc@0.8.0': - resolution: {integrity: sha512-mNRDyd/C3j7RMcwapifzv2K57sfA5xOw8g2U84ZDvgSrXVXLC99ZPxn9kmolb+dz8VMm9FONTZz9ESS6v8DTnA==} + '@nomicfoundation/edr-win32-x64-msvc@0.5.2': + resolution: {integrity: sha512-CcvvuA3sAv7liFNPsIR/68YlH6rrybKzYttLlMr80d4GKJjwJ5OKb3YgE6FdZZnOfP19HEHhsLcE0DPLtY3r0w==} engines: {node: '>= 18'} - '@nomicfoundation/edr@0.8.0': - resolution: {integrity: sha512-dwWRrghSVBQDpt0wP+6RXD8BMz2i/9TI34TcmZqeEAZuCLei3U9KZRgGTKVAM1rMRvrpf5ROfPqrWNetKVUTag==} + '@nomicfoundation/edr@0.5.2': + resolution: {integrity: sha512-hW/iLvUQZNTVjFyX/I40rtKvvDOqUEyIi96T28YaLfmPL+3LW2lxmYLUXEJ6MI14HzqxDqrLyhf6IbjAa2r3Dw==} engines: {node: '>= 18'} '@nomicfoundation/ethereumjs-common@4.0.4': @@ -394,14 +481,20 @@ packages: c-kzg: optional: true - '@nomicfoundation/hardhat-chai-matchers@2.0.8': - resolution: {integrity: sha512-Z5PiCXH4xhNLASROlSUOADfhfpfhYO6D7Hn9xp8PddmHey0jq704cr6kfU8TRrQ4PUZbpfsZadPj+pCfZdjPIg==} + '@nomicfoundation/hardhat-chai-matchers@2.0.7': + resolution: {integrity: sha512-RQfsiTwdf0SP+DtuNYvm4921X6VirCQq0Xyh+mnuGlTwEFSPZ/o27oQC+l+3Y/l48DDU7+ZcYBR+Fp+Rp94LfQ==} peerDependencies: '@nomicfoundation/hardhat-ethers': ^3.0.0 chai: ^4.2.0 ethers: ^6.1.0 hardhat: ^2.9.4 + '@nomicfoundation/hardhat-ethers@3.0.6': + resolution: {integrity: sha512-/xzkFQAaHQhmIAYOQmvHBPwL+NkwLzT9gRZBsgWUYeV+E6pzXsBQsHfRYbAZ3XEYare+T7S+5Tg/1KDJgepSkA==} + peerDependencies: + ethers: ^6.1.0 + hardhat: ^2.0.0 + '@nomicfoundation/hardhat-ethers@3.0.8': resolution: {integrity: sha512-zhOZ4hdRORls31DTOqg+GmEZM0ujly8GGIuRY7t7szEk2zW/arY1qDug/py8AEktT00v5K+b6RvbVog+va51IA==} peerDependencies: @@ -423,8 +516,8 @@ packages: '@nomicfoundation/hardhat-verify': ^2.0.1 hardhat: ^2.18.0 - '@nomicfoundation/hardhat-network-helpers@1.0.12': - resolution: {integrity: sha512-xTNQNI/9xkHvjmCJnJOTyqDSl8uq1rKb2WOVmixQxFtRd7Oa3ecO8zM0cyC2YmOK+jHB9WPZ+F/ijkHg1CoORA==} + '@nomicfoundation/hardhat-network-helpers@1.0.10': + resolution: {integrity: sha512-R35/BMBlx7tWN5V6d/8/19QCwEmIdbnA4ZrsuXgvs8i2qFx5i7h6mH5pBS4Pwi4WigLH+upl6faYusrNPuzMrQ==} peerDependencies: hardhat: ^2.9.5 @@ -450,16 +543,16 @@ packages: typechain: ^8.3.0 typescript: '>=4.5.0' - '@nomicfoundation/hardhat-verify@2.0.13': - resolution: {integrity: sha512-i57GX1sC0kYGyRVnbQrjjyBTpWTKgrvKC+jH8CMKV6gHp959Upb8lKaZ58WRHIU0espkulTxLnacYeUDirwJ2g==} + '@nomicfoundation/hardhat-verify@2.0.8': + resolution: {integrity: sha512-x/OYya7A2Kcz+3W/J78dyDHxr0ezU23DKTrRKfy5wDPCnePqnr79vm8EXqX3gYps6IjPBYyGPZ9K6E5BnrWx5Q==} peerDependencies: hardhat: ^2.0.4 - '@nomicfoundation/ignition-core@0.15.10': - resolution: {integrity: sha512-AWvCviNlBkPT8EKcg34N+yUdQTYFiC/HdpfFZdw8oMFuAs9SMZE0zQA9gJQSCay41GbuyXt2Kietp5/1/nlBIA==} + '@nomicfoundation/ignition-core@0.15.13': + resolution: {integrity: sha512-Z4T1WIbw0EqdsN9RxtnHeQXBi7P/piAmCu8bZmReIdDo/2h06qgKWxjDoNfc9VBFZJ0+Dx79tkgQR3ewxMDcpA==} - '@nomicfoundation/ignition-ui@0.15.10': - resolution: {integrity: sha512-82XQPF+1fvxTimDUPgDVwpTjHjfjFgFs84rERbBiMLQbz6sPtgTlV8HHrlbMx8tT/JKCI/SCU4gxV8xA4CPfcg==} + '@nomicfoundation/ignition-ui@0.15.12': + resolution: {integrity: sha512-nQl8tusvmt1ANoyIj5RQl9tVSEmG0FnNbtwnWbTim+F8JLm4YLHWS0yEgYUZC+BEO3oS0D8r6V8a02JGZJgqiQ==} '@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.2': resolution: {integrity: sha512-JaqcWPDZENCvm++lFFGjrDd8mxtf+CtLd2MiXvMNTBD33dContTZ9TWETwNFwg7JTJT5Q9HEecH7FA+HTSsIUw==} @@ -493,11 +586,25 @@ packages: resolution: {integrity: sha512-q4n32/FNKIhQ3zQGGw5CvPF6GTvDCpYwIf7bEY/dZTZbgfDsHyjJwURxUJf3VQuuJj+fDIFl4+KkBVbw4Ef6jA==} engines: {node: '>= 12'} - '@openzeppelin/contracts@5.2.0': - resolution: {integrity: sha512-bxjNie5z89W1Ea0NZLZluFh8PrFNn9DH8DQlujEok2yjsOlraUPKID5p1Wk3qdNbf6XkQ1Os2RvfiHrrXLHWKA==} + '@onchain-id/solidity@2.2.1': + resolution: {integrity: sha512-B54InT8yi89qlh9UVCARcfdQLVDP7Lef87B/Ww2Wn19oyEbPmlWho2EK1sgnrt/8Q0fGX/7y5rDnx3HPy28NTA==} + + '@openzeppelin/contracts-upgradeable@4.9.6': + resolution: {integrity: sha512-m4iHazOsOCv1DgM7eD7GupTJ+NFVujRZt1wzddDPSVGpWdKq1SKkla5htKG7+IS4d2XOCtzkUNwRZ7Vq5aEUMA==} - '@pkgr/core@0.1.1': - resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} + '@openzeppelin/contracts-upgradeable@5.4.0': + resolution: {integrity: sha512-STJKyDzUcYuB35Zub1JpWW58JxvrFFVgQ+Ykdr8A9PGXgtq/obF5uoh07k2XmFyPxfnZdPdBdhkJ/n2YxJ87HQ==} + peerDependencies: + '@openzeppelin/contracts': 5.4.0 + + '@openzeppelin/contracts@4.9.6': + resolution: {integrity: sha512-xSmezSupL+y9VkHZJGDoCBpmnB2ogM13ccaYDWqJTfS3dbuHkgjuwDFUmaFauBCboQMGB/S5UqUl2y54X99BmA==} + + '@openzeppelin/contracts@5.4.0': + resolution: {integrity: sha512-eCYgWnLg6WO+X52I16TZt8uEjbtdkgLC0SUX/xnAksjjrQI4Xfn4iBRoI5j55dmlOhDv1Y7BoR3cU7e3WWhC6A==} + + '@pkgr/core@0.2.9': + resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} '@scure/base@1.1.9': @@ -546,8 +653,11 @@ packages: '@solidity-parser/parser@0.14.5': resolution: {integrity: sha512-6dKnHZn7fg/iQATVEzqyUOyEidbn05q7YA2mQ9hC0MMXhhV3/JrsxmFSYZAcr7j1yUP700LLhTruvJ3MiQmjJg==} - '@solidity-parser/parser@0.19.0': - resolution: {integrity: sha512-RV16k/qIxW/wWc+mLzV3ARyKUaMUTBy9tOLMzFhtNSKYeTAanQ3a5MudJKf/8arIFnA2L27SNjarQKmFg0w/jA==} + '@solidity-parser/parser@0.20.2': + resolution: {integrity: sha512-rbu0bzwNvMcwAjH86hiEAcOeRI2EeK8zCkHDrFykh/Al8mvJeFmjy3UrE7GYQjNwOgbGUUtCn5/k8CB8zIu7QA==} + + '@tokenysolutions/t-rex@4.1.6': + resolution: {integrity: sha512-GNmVAC11cqwF6bmVCl0yhaVfPLBptF4K0vmepghTPbSogky1WG+38h7RR/p7909Si2JgswreeeLZZyBLN0KZrg==} '@tsconfig/node10@1.0.11': resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} @@ -579,8 +689,8 @@ packages: '@types/bn.js@4.11.6': resolution: {integrity: sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==} - '@types/bn.js@5.1.6': - resolution: {integrity: sha512-Xh8vSwUeMKeYYrj3cX4lGQgFSF/N03r+tv4AiLl1SucqV+uTQpxRcnM8AkXKHwYP9ZPXOYXRr2KPXpVlIvqh9w==} + '@types/bn.js@5.2.0': + resolution: {integrity: sha512-DLbJ1BPqxvQhIGbeu8VbUC1DiAiahHtAYvA0ZEAa4P31F7IaArc8z3C3BRQdWX4mtLQuABG4yzp76ZrS02Ui1Q==} '@types/chai-as-promised@7.1.8': resolution: {integrity: sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw==} @@ -591,8 +701,8 @@ packages: '@types/concat-stream@1.6.1': resolution: {integrity: sha512-eHE4cQPoj6ngxBZMvVf6Hw7Mh4jMW4U9lpGmS5GBPB9RYxlFg+CHaVN7ErNY4W9XfLIEn20b4VDYaIrbq0q4uA==} - '@types/estree@1.0.6': - resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} '@types/form-data@0.0.33': resolution: {integrity: sha512-8BSvG1kGm83cyJITQMZSulnl6QV8jqAGreJsc5tPu1Jq0vTSOiY/k24Wx82JRpWwZSqrala6sd5rWi6aNXvqcw==} @@ -606,8 +716,9 @@ packages: '@types/lru-cache@5.1.1': resolution: {integrity: sha512-ssE3Vlrys7sdIzs5LOxCzTVMsU7i9oa/IaW92wF32JFb3CVczqOkru2xspuKczHEbG3nvmPY7IFqVmGGHdNbYw==} - '@types/minimatch@5.1.2': - resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} + '@types/minimatch@6.0.0': + resolution: {integrity: sha512-zmPitbQ8+6zNutpwgcQuLcsEpn/Cj54Kbn7L5pX0Os5kdWplB7xPgEh/g+SWOB/qmows2gpuCaPyduq8ZZRnxA==} + deprecated: This is a stub types definition. minimatch provides its own type definitions, so you do not need this installed. '@types/mocha@10.0.10': resolution: {integrity: sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==} @@ -618,12 +729,15 @@ packages: '@types/node@18.15.13': resolution: {integrity: sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q==} - '@types/node@20.17.24': - resolution: {integrity: sha512-d7fGCyB96w9BnWQrOsJtpyiSaBcAYYr75bnK6ZRjDbql2cGLj/3GsL5OYmLPNq76l7Gf2q4Rv9J2o6h5CrD9sA==} + '@types/node@20.19.17': + resolution: {integrity: sha512-gfehUI8N1z92kygssiuWvLiwcbOB3IRktR6hTDgJlXMYh5OvkPSRmgfoBUmfZt+vhwJtX7v1Yw4KvvAf7c5QKQ==} '@types/node@22.7.5': resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==} + '@types/node@24.5.2': + resolution: {integrity: sha512-FYxk1I7wPv3K2XBaoyH2cTnocQEu8AOZ60hPbsyukMPLv5/5qr7V1i8PLHdl6Zf87I+xZXFvPCXYjiTFq+YSDQ==} + '@types/node@8.10.66': resolution: {integrity: sha512-tktOkFUA4kXx2hhhrB8bIFb5TbwzS4uOhKEmwiD+NoiL0qtP2OQ9mFldbgD4dV1djrlBYP6eBuQZiWjuHUpqFw==} @@ -633,72 +747,68 @@ packages: '@types/prettier@2.7.3': resolution: {integrity: sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==} - '@types/qs@6.9.18': - resolution: {integrity: sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==} + '@types/qs@6.14.0': + resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} '@types/secp256k1@4.0.6': resolution: {integrity: sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==} - '@types/semver@7.5.8': - resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} - - '@typescript-eslint/eslint-plugin@6.21.0': - resolution: {integrity: sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/eslint-plugin@8.0.0': + resolution: {integrity: sha512-STIZdwEQRXAHvNUS6ILDf5z3u95Gc8jzywunxSNqX00OooIemaaNIA0vEgynJlycL5AjabYLLrIyHd4iazyvtg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha - eslint: ^7.0.0 || ^8.0.0 + '@typescript-eslint/parser': ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 typescript: '*' peerDependenciesMeta: typescript: optional: true - '@typescript-eslint/parser@6.21.0': - resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/parser@8.0.0': + resolution: {integrity: sha512-pS1hdZ+vnrpDIxuFXYQpLTILglTjSYJ9MbetZctrUawogUsPdz31DIIRZ9+rab0LhYNTsk88w4fIzVheiTbWOQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^7.0.0 || ^8.0.0 + eslint: ^8.57.0 || ^9.0.0 typescript: '*' peerDependenciesMeta: typescript: optional: true - '@typescript-eslint/scope-manager@6.21.0': - resolution: {integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/scope-manager@8.0.0': + resolution: {integrity: sha512-V0aa9Csx/ZWWv2IPgTfY7T4agYwJyILESu/PVqFtTFz9RIS823mAze+NbnBI8xiwdX3iqeQbcTYlvB04G9wyQw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/type-utils@6.21.0': - resolution: {integrity: sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/type-utils@8.0.0': + resolution: {integrity: sha512-mJAFP2mZLTBwAn5WI4PMakpywfWFH5nQZezUQdSKV23Pqo6o9iShQg1hP2+0hJJXP2LnZkWPphdIq4juYYwCeg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^7.0.0 || ^8.0.0 typescript: '*' peerDependenciesMeta: typescript: optional: true - '@typescript-eslint/types@6.21.0': - resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/types@8.0.0': + resolution: {integrity: sha512-wgdSGs9BTMWQ7ooeHtu5quddKKs5Z5dS+fHLbrQI+ID0XWJLODGMHRfhwImiHoeO2S5Wir2yXuadJN6/l4JRxw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@6.21.0': - resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/typescript-estree@8.0.0': + resolution: {integrity: sha512-5b97WpKMX+Y43YKi4zVcCVLtK5F98dFls3Oxui8LbnmRsseKenbbDinmvxrWegKDMmlkIq/XHuyy0UGLtpCDKg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '*' peerDependenciesMeta: typescript: optional: true - '@typescript-eslint/utils@6.21.0': - resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/utils@8.0.0': + resolution: {integrity: sha512-k/oS/A/3QeGLRvOWCg6/9rATJL5rec7/5s1YmdS0ZU6LHveJyGFwBvLhSRBv6i9xaj7etmosp+l+ViN1I9Aj/Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^7.0.0 || ^8.0.0 + eslint: ^8.57.0 || ^9.0.0 - '@typescript-eslint/visitor-keys@6.21.0': - resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/visitor-keys@8.0.0': + resolution: {integrity: sha512-oN0K4nkHuOyF3PVMyETbpP5zp6wfyOvm7tWhTMfoqxSSsPmJIh6JNASuZDlODE8eE+0EB9uar+6+vxr9DBTYOA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} abbrev@1.0.9: resolution: {integrity: sha512-LEyx4aLEC3x6T0UguF6YILf+ntvmOaWsVfENmIW0E9H09vKlLDGelMjjSm0jkDHALj8A8quZ/HapKNigzwge+Q==} @@ -712,8 +822,8 @@ packages: resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} engines: {node: '>=0.4.0'} - acorn@8.14.1: - resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} hasBin: true @@ -824,8 +934,12 @@ packages: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} - axios@1.8.3: - resolution: {integrity: sha512-iP4DebzoNlP/YN2dpwCgb8zoCmhtkajzS48JvwmkSkXvPI3DHc7m+XYL5tGnSlJtR6nImXZmdCuN5aP8dh1d8A==} + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + + axios@1.12.2: + resolution: {integrity: sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==} balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -849,18 +963,18 @@ packages: bn.js@4.12.1: resolution: {integrity: sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==} - bn.js@5.2.1: - resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} + bn.js@5.2.2: + resolution: {integrity: sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==} boxen@5.1.2: resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==} engines: {node: '>=10'} - brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} - brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} @@ -895,6 +1009,10 @@ packages: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} + call-bound@1.0.4: resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} @@ -945,10 +1063,6 @@ packages: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} - chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} - ci-info@2.0.0: resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} @@ -1049,8 +1163,8 @@ packages: supports-color: optional: true - debug@4.4.0: - resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -1073,6 +1187,10 @@ packages: deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -1096,8 +1214,8 @@ packages: resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} engines: {node: '>=8'} - dotenv@16.4.7: - resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} engines: {node: '>=12'} dunder-proto@1.0.1: @@ -1151,19 +1269,19 @@ packages: engines: {node: '>=0.12.0'} hasBin: true - eslint-config-prettier@9.1.0: - resolution: {integrity: sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==} + eslint-config-prettier@9.1.2: + resolution: {integrity: sha512-iI1f+D2ViGn+uvv5HuHVUamg8ll4tN+JRHGc6IJi4TP9Kl976C57fzPXgseXNs8v0iA8aSJpHsTWjDb9QJamGQ==} hasBin: true peerDependencies: eslint: '>=7.0.0' - eslint-plugin-prettier@5.2.3: - resolution: {integrity: sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw==} + eslint-plugin-prettier@5.5.4: + resolution: {integrity: sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: '@types/eslint': '>=8.0.0' eslint: '>=8.0.0' - eslint-config-prettier: '*' + eslint-config-prettier: '>= 7.0.0 <10.0.0 || >=10.1.0' prettier: '>=3.0.0' peerDependenciesMeta: '@types/eslint': @@ -1171,20 +1289,20 @@ packages: eslint-config-prettier: optional: true - eslint-scope@8.3.0: - resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==} + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - eslint-visitor-keys@4.2.0: - resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - eslint@9.22.0: - resolution: {integrity: sha512-9V/QURhsRN40xuHXWjV64yvrzMjcz7ZyNoF2jJFmy9j/SLk0u1OLSZgXi28MrXjymnjEGSR80WCdab3RGMDveQ==} + eslint@9.36.0: + resolution: {integrity: sha512-hB4FIzXovouYzwzECDcUkJ4OcfOEkXTv2zRY6B9bkwjx/cprAq0uvm1nl7zvQ0/TsUk0zQiN4uPfJpB9m+rPMQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true peerDependencies: @@ -1193,8 +1311,8 @@ packages: jiti: optional: true - espree@10.3.0: - resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} esprima@2.7.3: @@ -1265,8 +1383,8 @@ packages: resolution: {integrity: sha512-9VkriTTed+/27BGuY1s0hf441kqwHJ1wtN2edksEtiRvXx+soxRX3iSXTfFqq2+YwrOqbDoTHjIhQnjJRlzKmg==} engines: {node: '>=14.0.0'} - ethers@6.13.5: - resolution: {integrity: sha512-+knKNieu5EKRThQJWwqaJ10a6HE9sSehGeqWN65//wE7j47ZpFhKAnHB/JJFibwwg61I/koxaPsXbXpD/skNOQ==} + ethers@6.15.0: + resolution: {integrity: sha512-Kf/3ZW54L4UT0pZtsY/rf+EkBU7Qi5nnhonjUb8yTXcxH3cdcWrV2cRyk0Xk/4jK6OoHhxxZHriyhje20If2hQ==} engines: {node: '>=14.0.0'} ethjs-unit@0.1.6: @@ -1296,20 +1414,12 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-uri@3.0.6: - resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} + fast-uri@3.1.0: + resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} - fdir@6.4.3: - resolution: {integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -1322,6 +1432,10 @@ packages: resolution: {integrity: sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==} engines: {node: '>=4.0.0'} + find-up@2.1.0: + resolution: {integrity: sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ==} + engines: {node: '>=4'} + find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -1337,8 +1451,8 @@ packages: flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} - follow-redirects@1.15.9: - resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + follow-redirects@1.15.11: + resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} engines: {node: '>=4.0'} peerDependencies: debug: '*' @@ -1346,12 +1460,16 @@ packages: debug: optional: true - form-data@2.5.3: - resolution: {integrity: sha512-XHIrMD0NpDrNM/Ckf7XJiBbLl57KEhT3+i3yY+eWm+cqYZJQTZrKo8Y8AWKnuV5GT4scfuUGt9LzNoIx3dU1nQ==} + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} + + form-data@2.5.5: + resolution: {integrity: sha512-jqdObeR2rxZZbPSGL+3VckHMYtu+f9//KXBsVny6JSX/pa38Fy+bGjuG8eW/H6USNQWhLi8Num++cU2yOCNz4A==} engines: {node: '>= 0.12'} - form-data@4.0.2: - resolution: {integrity: sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==} + form-data@4.0.4: + resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} engines: {node: '>= 6'} fp-ts@1.19.3: @@ -1426,6 +1544,10 @@ packages: resolution: {integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==} deprecated: Glob versions prior to v9 are no longer supported + glob@7.2.0: + resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} + deprecated: Glob versions prior to v9 are no longer supported + glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported @@ -1447,8 +1569,8 @@ packages: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} - globals@16.0.0: - resolution: {integrity: sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==} + globals@16.4.0: + resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} engines: {node: '>=18'} globby@10.0.2: @@ -1479,8 +1601,8 @@ packages: peerDependencies: hardhat: ^2.0.2 - hardhat@2.22.19: - resolution: {integrity: sha512-jptJR5o6MCgNbhd7eKa3mrteR+Ggq1exmE5RUL5ydQEVKcZm0sss5laa86yZ0ixIavIvF4zzS7TdGDuyopj0sQ==} + hardhat@2.22.10: + resolution: {integrity: sha512-JRUDdiystjniAvBGFmJRsiIZSOP2/6s++8xRDe3TzLeQXlWWHsXBrd9wd3JWFyKXvgMqMeLL5Sz/oNxXKYw9vg==} hasBin: true peerDependencies: ts-node: '*' @@ -1503,6 +1625,9 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + has-symbols@1.1.0: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} @@ -1511,9 +1636,9 @@ packages: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} - hash-base@3.1.0: - resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} - engines: {node: '>=4'} + hash-base@3.1.2: + resolution: {integrity: sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==} + engines: {node: '>= 0.8'} hash.js@1.1.7: resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} @@ -1594,6 +1719,10 @@ packages: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + is-core-module@2.16.1: resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} @@ -1626,6 +1755,10 @@ packages: resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} engines: {node: '>=8'} + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} + is-unicode-supported@0.1.0: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} @@ -1633,6 +1766,9 @@ packages: isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} @@ -1659,10 +1795,6 @@ packages: json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - json-stream-stringify@3.1.6: - resolution: {integrity: sha512-x7fpwxOkbhFCaJDJ8vb1fBY3DdSa4AlITaz+HHILQJzdPMnHEFjxPwVUi1ALIbcIxDE0PNe/0i7frnY8QnBQog==} - engines: {node: '>=7.10.1'} - json-stringify-safe@5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} @@ -1674,8 +1806,8 @@ packages: jsonfile@4.0.0: resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} - jsonfile@6.1.0: - resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + jsonfile@6.2.0: + resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} jsonschema@1.5.0: resolution: {integrity: sha512-K+A9hhqbn0f3pJX17Q/7H6yQfD/5OXgdrR5UE12gMXCiN9D5Xq2o5mddV2QEcX/bjla99ASsAAQUyMCCRWAEhw==} @@ -1703,6 +1835,10 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + locate-path@2.0.0: + resolution: {integrity: sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA==} + engines: {node: '>=4'} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} @@ -1778,6 +1914,10 @@ packages: minimalistic-crypto-utils@1.0.1: resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + minimatch@10.0.3: + resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} + engines: {node: 20 || >=22} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -1785,8 +1925,8 @@ packages: resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} engines: {node: '>=10'} - minimatch@9.0.3: - resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} minimist@1.2.8: @@ -1881,10 +2021,18 @@ packages: resolution: {integrity: sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==} engines: {node: '>=0.10.0'} + p-limit@1.3.0: + resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==} + engines: {node: '>=4'} + p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} + p-locate@2.0.0: + resolution: {integrity: sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg==} + engines: {node: '>=4'} + p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} @@ -1893,6 +2041,10 @@ packages: resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} engines: {node: '>=10'} + p-try@1.0.0: + resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==} + engines: {node: '>=4'} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -1900,6 +2052,10 @@ packages: parse-cache-control@1.0.1: resolution: {integrity: sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==} + path-exists@3.0.0: + resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} + engines: {node: '>=4'} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -1922,8 +2078,8 @@ packages: pathval@1.1.1: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} - pbkdf2@3.1.2: - resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} + pbkdf2@3.1.4: + resolution: {integrity: sha512-0yPXNT01PxSUdkIxL85Fd+yPdeCcvGwFPAAHbR3Z2ukMERcRrJFfLUKK3oglbQ9eUPeX6qDY3QiELqiDarZYUQ==} engines: {node: '>=0.12'} picocolors@1.1.1: @@ -1933,14 +2089,14 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - picomatch@4.0.2: - resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} - engines: {node: '>=12'} - pify@4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + engines: {node: '>= 0.4'} + prelude-ls@1.1.2: resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} engines: {node: '>= 0.8.0'} @@ -1958,8 +2114,8 @@ packages: engines: {node: '>=10.13.0'} hasBin: true - prettier@3.5.3: - resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==} + prettier@3.6.2: + resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} engines: {node: '>=14'} hasBin: true @@ -2005,10 +2161,6 @@ packages: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} - readdirp@4.1.2: - resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} - engines: {node: '>= 14.18.0'} - rechoir@0.6.2: resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} engines: {node: '>= 0.10'} @@ -2060,8 +2212,9 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - ripemd160@2.0.2: - resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} + ripemd160@2.0.3: + resolution: {integrity: sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==} + engines: {node: '>= 0.8'} rlp@2.2.7: resolution: {integrity: sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==} @@ -2098,22 +2251,27 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.7.1: - resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} + semver@7.7.2: + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} engines: {node: '>=10'} hasBin: true serialize-javascript@6.0.2: resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + setimmediate@1.0.5: resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - sha.js@2.4.11: - resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} + sha.js@2.4.12: + resolution: {integrity: sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==} + engines: {node: '>= 0.10'} hasBin: true sha1@1.1.1: @@ -2164,8 +2322,8 @@ packages: engines: {node: '>=10.0.0'} hasBin: true - solidity-coverage@0.8.14: - resolution: {integrity: sha512-ItAAObe5GaEOp20kXC2BZRnph+9P7Rtoqg2mQc2SXGEHgSDF2wWd1Wxz3ntzQWXkbCtIIGdJT918HG00cObwbA==} + solidity-coverage@0.8.16: + resolution: {integrity: sha512-qKqgm8TPpcnCK0HCDLJrjbOA2tQNEJY4dHX/LSSQ9iwYFS973MwjtgYn2Iv3vfCEQJTj5xtm4cuUMzlJsJSMbg==} hasBin: true peerDependencies: hardhat: ^2.11.0 @@ -2255,8 +2413,8 @@ packages: sync-rpc@1.3.6: resolution: {integrity: sha512-J8jTXuZzRlvU7HemDgHi3pGnh/rkoqR/OZSjhTyyZrEkkYQbk7Z33AXp37mkPfPpfdOuj7Ex3H/TJM1z48uPQw==} - synckit@0.9.2: - resolution: {integrity: sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==} + synckit@0.11.11: + resolution: {integrity: sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==} engines: {node: ^14.18.0 || >=16.0.0} table-layout@1.0.2: @@ -2274,14 +2432,14 @@ packages: through2@4.0.2: resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} - tinyglobby@0.2.12: - resolution: {integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==} - engines: {node: '>=12.0.0'} - tmp@0.0.33: resolution: {integrity: sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==} engines: {node: '>=0.6.0'} + to-buffer@1.2.1: + resolution: {integrity: sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==} + engines: {node: '>= 0.4'} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -2328,9 +2486,6 @@ packages: tslib@2.7.0: resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - tsort@0.0.1: resolution: {integrity: sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==} @@ -2370,11 +2525,15 @@ packages: peerDependencies: typescript: '>=4.3.0' + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} + typedarray@0.0.6: resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} - typescript@5.8.2: - resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==} + typescript@5.9.2: + resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} engines: {node: '>=14.17'} hasBin: true @@ -2394,8 +2553,14 @@ packages: undici-types@6.19.8: resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} - undici@5.28.5: - resolution: {integrity: sha512-zICwjrDrcrUE0pyyJc1I2QzBkLM8FINsgOrt6WjA+BgajVq9Nxu2PbFFXUrAggLfDXlZGZBVZYw7WNV5KiBiBA==} + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + undici-types@7.12.0: + resolution: {integrity: sha512-goOacqME2GYyOZZfb5Lgtu+1IDmAlAEu5xnD3+xTzS10hT0vzpf0SPjkXwAw9Jm+4n/mQGDP3LO8CPbYROeBfQ==} + + undici@5.29.0: + resolution: {integrity: sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==} engines: {node: '>=14.0'} universalify@0.1.2: @@ -2430,6 +2595,10 @@ packages: resolution: {integrity: sha512-tsu8FiKJLk2PzhDl9fXbGUWTkkVXYhtTA+SmEFkKft+9BgwLxfCRpU96sWv7ICC8zixBNd3JURVoiR3dUXgP8A==} engines: {node: '>=8.0.0'} + which-typed-array@1.1.19: + resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} + engines: {node: '>= 0.4'} + which@1.3.1: resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} hasBin: true @@ -2528,8 +2697,18 @@ snapshots: '@adraffy/ens-normalize@1.10.1': {} - '@appliedblockchain/silentdatarollup-core@0.1.3': + '@appliedblockchain/silentdatarollup-core@1.0.6': + dependencies: + debug: 4.3.7 + ethers: 6.13.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@appliedblockchain/silentdatarollup-ethers-provider@1.0.6': dependencies: + '@appliedblockchain/silentdatarollup-core': 1.0.6 debug: 4.3.7 ethers: 6.13.2 transitivePeerDependencies: @@ -2537,13 +2716,13 @@ snapshots: - supports-color - utf-8-validate - '@appliedblockchain/silentdatarollup-hardhat-plugin@0.1.3(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2))': + '@appliedblockchain/silentdatarollup-hardhat-plugin@1.0.6(ethers@6.13.2)(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2))': dependencies: - '@appliedblockchain/silentdatarollup-core': 0.1.3 - '@nomicfoundation/hardhat-ethers': 3.0.8(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)) + '@appliedblockchain/silentdatarollup-core': 1.0.6 + '@nomicfoundation/hardhat-ethers': 3.0.8(ethers@6.13.2)(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)) debug: 4.3.7 - ethers: 6.13.5 - hardhat: 2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2) + ethers: 6.13.2 + hardhat: 2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2) transitivePeerDependencies: - bufferutil - supports-color @@ -2553,32 +2732,32 @@ snapshots: dependencies: '@jridgewell/trace-mapping': 0.3.9 - '@eslint-community/eslint-utils@4.5.0(eslint@9.22.0)': + '@eslint-community/eslint-utils@4.9.0(eslint@9.36.0)': dependencies: - eslint: 9.22.0 + eslint: 9.36.0 eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.1': {} - '@eslint/config-array@0.19.2': + '@eslint/config-array@0.21.0': dependencies: '@eslint/object-schema': 2.1.6 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) minimatch: 3.1.2 transitivePeerDependencies: - supports-color - '@eslint/config-helpers@0.1.0': {} + '@eslint/config-helpers@0.3.1': {} - '@eslint/core@0.12.0': + '@eslint/core@0.15.2': dependencies: '@types/json-schema': 7.0.15 - '@eslint/eslintrc@3.3.0': + '@eslint/eslintrc@3.3.1': dependencies: ajv: 6.12.6 - debug: 4.4.0(supports-color@8.1.1) - espree: 10.3.0 + debug: 4.4.3(supports-color@8.1.1) + espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 import-fresh: 3.3.1 @@ -2588,13 +2767,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@9.22.0': {} + '@eslint/js@9.36.0': {} '@eslint/object-schema@2.1.6': {} - '@eslint/plugin-kit@0.2.7': + '@eslint/plugin-kit@0.3.5': dependencies: - '@eslint/core': 0.12.0 + '@eslint/core': 0.15.2 levn: 0.4.1 '@ethereumjs/rlp@4.0.1': {} @@ -2664,7 +2843,7 @@ snapshots: dependencies: '@ethersproject/bytes': 5.8.0 '@ethersproject/logger': 5.8.0 - bn.js: 5.2.1 + bn.js: 5.2.2 '@ethersproject/bytes@5.8.0': dependencies: @@ -2797,7 +2976,7 @@ snapshots: '@ethersproject/bytes': 5.8.0 '@ethersproject/logger': 5.8.0 '@ethersproject/properties': 5.8.0 - bn.js: 5.2.1 + bn.js: 5.2.2 elliptic: 6.6.1 hash.js: 1.1.7 @@ -2872,25 +3051,29 @@ snapshots: '@humanfs/core@0.19.1': {} - '@humanfs/node@0.16.6': + '@humanfs/node@0.16.7': dependencies: '@humanfs/core': 0.19.1 - '@humanwhocodes/retry': 0.3.1 + '@humanwhocodes/retry': 0.4.3 '@humanwhocodes/module-importer@1.0.1': {} - '@humanwhocodes/retry@0.3.1': {} + '@humanwhocodes/retry@0.4.3': {} - '@humanwhocodes/retry@0.4.2': {} + '@isaacs/balanced-match@4.0.1': {} + + '@isaacs/brace-expansion@5.0.0': + dependencies: + '@isaacs/balanced-match': 4.0.1 '@jridgewell/resolve-uri@3.1.2': {} - '@jridgewell/sourcemap-codec@1.5.0': {} + '@jridgewell/sourcemap-codec@1.5.5': {} '@jridgewell/trace-mapping@0.3.9': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.5.5 '@metamask/eth-sig-util@4.0.1': dependencies: @@ -2914,7 +3097,7 @@ snapshots: '@noble/hashes@1.4.0': {} - '@noble/hashes@1.7.1': {} + '@noble/hashes@1.8.0': {} '@noble/secp256k1@1.7.1': {} @@ -2930,29 +3113,29 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.19.1 - '@nomicfoundation/edr-darwin-arm64@0.8.0': {} + '@nomicfoundation/edr-darwin-arm64@0.5.2': {} - '@nomicfoundation/edr-darwin-x64@0.8.0': {} + '@nomicfoundation/edr-darwin-x64@0.5.2': {} - '@nomicfoundation/edr-linux-arm64-gnu@0.8.0': {} + '@nomicfoundation/edr-linux-arm64-gnu@0.5.2': {} - '@nomicfoundation/edr-linux-arm64-musl@0.8.0': {} + '@nomicfoundation/edr-linux-arm64-musl@0.5.2': {} - '@nomicfoundation/edr-linux-x64-gnu@0.8.0': {} + '@nomicfoundation/edr-linux-x64-gnu@0.5.2': {} - '@nomicfoundation/edr-linux-x64-musl@0.8.0': {} + '@nomicfoundation/edr-linux-x64-musl@0.5.2': {} - '@nomicfoundation/edr-win32-x64-msvc@0.8.0': {} + '@nomicfoundation/edr-win32-x64-msvc@0.5.2': {} - '@nomicfoundation/edr@0.8.0': + '@nomicfoundation/edr@0.5.2': dependencies: - '@nomicfoundation/edr-darwin-arm64': 0.8.0 - '@nomicfoundation/edr-darwin-x64': 0.8.0 - '@nomicfoundation/edr-linux-arm64-gnu': 0.8.0 - '@nomicfoundation/edr-linux-arm64-musl': 0.8.0 - '@nomicfoundation/edr-linux-x64-gnu': 0.8.0 - '@nomicfoundation/edr-linux-x64-musl': 0.8.0 - '@nomicfoundation/edr-win32-x64-msvc': 0.8.0 + '@nomicfoundation/edr-darwin-arm64': 0.5.2 + '@nomicfoundation/edr-darwin-x64': 0.5.2 + '@nomicfoundation/edr-linux-arm64-gnu': 0.5.2 + '@nomicfoundation/edr-linux-arm64-musl': 0.5.2 + '@nomicfoundation/edr-linux-x64-gnu': 0.5.2 + '@nomicfoundation/edr-linux-x64-musl': 0.5.2 + '@nomicfoundation/edr-win32-x64-msvc': 0.5.2 '@nomicfoundation/ethereumjs-common@4.0.4': dependencies: @@ -2974,43 +3157,52 @@ snapshots: '@nomicfoundation/ethereumjs-rlp': 5.0.4 ethereum-cryptography: 0.1.3 - '@nomicfoundation/hardhat-chai-matchers@2.0.8(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(chai@4.5.0)(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2))': + '@nomicfoundation/hardhat-chai-matchers@2.0.7(@nomicfoundation/hardhat-ethers@3.0.6(ethers@6.13.2)(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)))(chai@4.5.0)(ethers@6.13.2)(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2))': dependencies: - '@nomicfoundation/hardhat-ethers': 3.0.8(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)) + '@nomicfoundation/hardhat-ethers': 3.0.6(ethers@6.13.2)(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)) '@types/chai-as-promised': 7.1.8 chai: 4.5.0 chai-as-promised: 7.1.2(chai@4.5.0) deep-eql: 4.1.4 - ethers: 6.13.5 - hardhat: 2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2) + ethers: 6.13.2 + hardhat: 2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2) ordinal: 1.0.3 - '@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2))': + '@nomicfoundation/hardhat-ethers@3.0.6(ethers@6.13.2)(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2))': + dependencies: + debug: 4.4.3(supports-color@8.1.1) + ethers: 6.13.2 + hardhat: 2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2) + lodash.isequal: 4.5.0 + transitivePeerDependencies: + - supports-color + + '@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.2)(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2))': dependencies: - debug: 4.4.0(supports-color@8.1.1) - ethers: 6.13.5 - hardhat: 2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2) + debug: 4.4.3(supports-color@8.1.1) + ethers: 6.13.2 + hardhat: 2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2) lodash.isequal: 4.5.0 transitivePeerDependencies: - supports-color - '@nomicfoundation/hardhat-ignition-ethers@0.15.10(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(@nomicfoundation/hardhat-ignition@0.15.10(@nomicfoundation/hardhat-verify@2.0.13(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(@nomicfoundation/ignition-core@0.15.10)(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2))': + '@nomicfoundation/hardhat-ignition-ethers@0.15.10(@nomicfoundation/hardhat-ethers@3.0.6(ethers@6.13.2)(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)))(@nomicfoundation/hardhat-ignition@0.15.10(@nomicfoundation/hardhat-verify@2.0.8(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)))(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)))(@nomicfoundation/ignition-core@0.15.13)(ethers@6.13.2)(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2))': dependencies: - '@nomicfoundation/hardhat-ethers': 3.0.8(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)) - '@nomicfoundation/hardhat-ignition': 0.15.10(@nomicfoundation/hardhat-verify@2.0.13(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)) - '@nomicfoundation/ignition-core': 0.15.10 - ethers: 6.13.5 - hardhat: 2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2) + '@nomicfoundation/hardhat-ethers': 3.0.6(ethers@6.13.2)(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)) + '@nomicfoundation/hardhat-ignition': 0.15.10(@nomicfoundation/hardhat-verify@2.0.8(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)))(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)) + '@nomicfoundation/ignition-core': 0.15.13 + ethers: 6.13.2 + hardhat: 2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2) - '@nomicfoundation/hardhat-ignition@0.15.10(@nomicfoundation/hardhat-verify@2.0.13(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2))': + '@nomicfoundation/hardhat-ignition@0.15.10(@nomicfoundation/hardhat-verify@2.0.8(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)))(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2))': dependencies: - '@nomicfoundation/hardhat-verify': 2.0.13(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)) - '@nomicfoundation/ignition-core': 0.15.10 - '@nomicfoundation/ignition-ui': 0.15.10 + '@nomicfoundation/hardhat-verify': 2.0.8(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)) + '@nomicfoundation/ignition-core': 0.15.13 + '@nomicfoundation/ignition-ui': 0.15.12 chalk: 4.1.2 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) fs-extra: 10.1.0 - hardhat: 2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2) + hardhat: 2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2) json5: 2.2.3 prompts: 2.4.2 transitivePeerDependencies: @@ -3018,54 +3210,54 @@ snapshots: - supports-color - utf-8-validate - '@nomicfoundation/hardhat-network-helpers@1.0.12(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2))': + '@nomicfoundation/hardhat-network-helpers@1.0.10(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2))': dependencies: ethereumjs-util: 7.1.5 - hardhat: 2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2) - - ? '@nomicfoundation/hardhat-toolbox@5.0.0(@nomicfoundation/hardhat-chai-matchers@2.0.8(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(chai@4.5.0)(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(@nomicfoundation/hardhat-ignition-ethers@0.15.10(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(@nomicfoundation/hardhat-ignition@0.15.10(@nomicfoundation/hardhat-verify@2.0.13(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(@nomicfoundation/ignition-core@0.15.10)(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(@nomicfoundation/hardhat-network-helpers@1.0.12(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(@nomicfoundation/hardhat-verify@2.0.13(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(@typechain/ethers-v6@0.5.1(ethers@6.13.5)(typechain@8.3.2(typescript@5.8.2))(typescript@5.8.2))(@typechain/hardhat@9.1.0(@typechain/ethers-v6@0.5.1(ethers@6.13.5)(typechain@8.3.2(typescript@5.8.2))(typescript@5.8.2))(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2))(typechain@8.3.2(typescript@5.8.2)))(@types/chai@4.3.20)(@types/mocha@10.0.10)(@types/node@20.17.24)(chai@4.5.0)(ethers@6.13.5)(hardhat-gas-reporter@1.0.10(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2))(solidity-coverage@0.8.14(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typechain@8.3.2(typescript@5.8.2))(typescript@5.8.2)' - : dependencies: - '@nomicfoundation/hardhat-chai-matchers': 2.0.8(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(chai@4.5.0)(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)) - '@nomicfoundation/hardhat-ethers': 3.0.8(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)) - '@nomicfoundation/hardhat-ignition-ethers': 0.15.10(@nomicfoundation/hardhat-ethers@3.0.8(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(@nomicfoundation/hardhat-ignition@0.15.10(@nomicfoundation/hardhat-verify@2.0.13(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)))(@nomicfoundation/ignition-core@0.15.10)(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)) - '@nomicfoundation/hardhat-network-helpers': 1.0.12(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)) - '@nomicfoundation/hardhat-verify': 2.0.13(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)) - '@typechain/ethers-v6': 0.5.1(ethers@6.13.5)(typechain@8.3.2(typescript@5.8.2))(typescript@5.8.2) - '@typechain/hardhat': 9.1.0(@typechain/ethers-v6@0.5.1(ethers@6.13.5)(typechain@8.3.2(typescript@5.8.2))(typescript@5.8.2))(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2))(typechain@8.3.2(typescript@5.8.2)) + hardhat: 2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2) + + '@nomicfoundation/hardhat-toolbox@5.0.0(32tvdyqhusnhk5bf77tetugxmm)': + dependencies: + '@nomicfoundation/hardhat-chai-matchers': 2.0.7(@nomicfoundation/hardhat-ethers@3.0.6(ethers@6.13.2)(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)))(chai@4.5.0)(ethers@6.13.2)(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)) + '@nomicfoundation/hardhat-ethers': 3.0.6(ethers@6.13.2)(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)) + '@nomicfoundation/hardhat-ignition-ethers': 0.15.10(@nomicfoundation/hardhat-ethers@3.0.6(ethers@6.13.2)(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)))(@nomicfoundation/hardhat-ignition@0.15.10(@nomicfoundation/hardhat-verify@2.0.8(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)))(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)))(@nomicfoundation/ignition-core@0.15.13)(ethers@6.13.2)(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)) + '@nomicfoundation/hardhat-network-helpers': 1.0.10(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)) + '@nomicfoundation/hardhat-verify': 2.0.8(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)) + '@typechain/ethers-v6': 0.5.1(ethers@6.13.2)(typechain@8.3.2(typescript@5.9.2))(typescript@5.9.2) + '@typechain/hardhat': 9.1.0(@typechain/ethers-v6@0.5.1(ethers@6.13.2)(typechain@8.3.2(typescript@5.9.2))(typescript@5.9.2))(ethers@6.13.2)(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2))(typechain@8.3.2(typescript@5.9.2)) '@types/chai': 4.3.20 '@types/mocha': 10.0.10 - '@types/node': 20.17.24 + '@types/node': 20.19.17 chai: 4.5.0 - ethers: 6.13.5 - hardhat: 2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2) - hardhat-gas-reporter: 1.0.10(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)) - solidity-coverage: 0.8.14(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)) - ts-node: 10.9.2(@types/node@20.17.24)(typescript@5.8.2) - typechain: 8.3.2(typescript@5.8.2) - typescript: 5.8.2 + ethers: 6.13.2 + hardhat: 2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2) + hardhat-gas-reporter: 1.0.10(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)) + solidity-coverage: 0.8.16(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)) + ts-node: 10.9.2(@types/node@20.19.17)(typescript@5.9.2) + typechain: 8.3.2(typescript@5.9.2) + typescript: 5.9.2 - '@nomicfoundation/hardhat-verify@2.0.13(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2))': + '@nomicfoundation/hardhat-verify@2.0.8(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2))': dependencies: '@ethersproject/abi': 5.8.0 '@ethersproject/address': 5.8.0 cbor: 8.1.0 - debug: 4.4.0(supports-color@8.1.1) - hardhat: 2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2) + chalk: 2.4.2 + debug: 4.4.3(supports-color@8.1.1) + hardhat: 2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2) lodash.clonedeep: 4.5.0 - picocolors: 1.1.1 semver: 6.3.1 table: 6.9.0 - undici: 5.28.5 + undici: 5.29.0 transitivePeerDependencies: - supports-color - '@nomicfoundation/ignition-core@0.15.10': + '@nomicfoundation/ignition-core@0.15.13': dependencies: '@ethersproject/address': 5.6.1 '@nomicfoundation/solidity-analyzer': 0.1.2 cbor: 9.0.2 - debug: 4.4.0(supports-color@8.1.1) - ethers: 6.13.5 + debug: 4.4.3(supports-color@8.1.1) + ethers: 6.15.0 fs-extra: 10.1.0 immer: 10.0.2 lodash: 4.17.21 @@ -3075,7 +3267,7 @@ snapshots: - supports-color - utf-8-validate - '@nomicfoundation/ignition-ui@0.15.10': {} + '@nomicfoundation/ignition-ui@0.15.12': {} '@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.2': optional: true @@ -3108,9 +3300,19 @@ snapshots: '@nomicfoundation/solidity-analyzer-linux-x64-musl': 0.1.2 '@nomicfoundation/solidity-analyzer-win32-x64-msvc': 0.1.2 - '@openzeppelin/contracts@5.2.0': {} + '@onchain-id/solidity@2.2.1': {} - '@pkgr/core@0.1.1': {} + '@openzeppelin/contracts-upgradeable@4.9.6': {} + + '@openzeppelin/contracts-upgradeable@5.4.0(@openzeppelin/contracts@5.4.0)': + dependencies: + '@openzeppelin/contracts': 5.4.0 + + '@openzeppelin/contracts@4.9.6': {} + + '@openzeppelin/contracts@5.4.0': {} + + '@pkgr/core@0.2.9': {} '@scure/base@1.1.9': {} @@ -3189,7 +3391,9 @@ snapshots: dependencies: antlr4ts: 0.5.0-alpha.4 - '@solidity-parser/parser@0.19.0': {} + '@solidity-parser/parser@0.20.2': {} + + '@tokenysolutions/t-rex@4.1.6(patch_hash=iry6mwuqzhz255vox72o2g6uvq)': {} '@tsconfig/node10@1.0.11': {} @@ -3199,29 +3403,37 @@ snapshots: '@tsconfig/node16@1.0.4': {} - '@typechain/ethers-v6@0.5.1(ethers@6.13.5)(typechain@8.3.2(typescript@5.8.2))(typescript@5.8.2)': + '@typechain/ethers-v6@0.5.1(ethers@6.13.2)(typechain@8.3.2(typescript@5.9.2))(typescript@5.9.2)': dependencies: - ethers: 6.13.5 + ethers: 6.13.2 lodash: 4.17.21 - ts-essentials: 7.0.3(typescript@5.8.2) - typechain: 8.3.2(typescript@5.8.2) - typescript: 5.8.2 + ts-essentials: 7.0.3(typescript@5.9.2) + typechain: 8.3.2(typescript@5.9.2) + typescript: 5.9.2 - '@typechain/hardhat@9.1.0(@typechain/ethers-v6@0.5.1(ethers@6.13.5)(typechain@8.3.2(typescript@5.8.2))(typescript@5.8.2))(ethers@6.13.5)(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2))(typechain@8.3.2(typescript@5.8.2))': + '@typechain/hardhat@9.1.0(@typechain/ethers-v6@0.5.1(ethers@6.13.2)(typechain@8.3.2(typescript@5.9.2))(typescript@5.9.2))(ethers@6.13.2)(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2))(typechain@8.3.2(typescript@5.9.2))': dependencies: - '@typechain/ethers-v6': 0.5.1(ethers@6.13.5)(typechain@8.3.2(typescript@5.8.2))(typescript@5.8.2) - ethers: 6.13.5 + '@typechain/ethers-v6': 0.5.1(ethers@6.13.2)(typechain@8.3.2(typescript@5.9.2))(typescript@5.9.2) + ethers: 6.13.2 fs-extra: 9.1.0 - hardhat: 2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2) - typechain: 8.3.2(typescript@5.8.2) + hardhat: 2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2) + typechain: 8.3.2(typescript@5.9.2) + + '@typechain/hardhat@9.1.0(@typechain/ethers-v6@0.5.1(ethers@6.13.2)(typechain@8.3.2(typescript@5.9.2))(typescript@5.9.2))(ethers@6.13.2)(hardhat@2.22.10(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2))(typescript@5.9.2))(typechain@8.3.2(typescript@5.9.2))': + dependencies: + '@typechain/ethers-v6': 0.5.1(ethers@6.13.2)(typechain@8.3.2(typescript@5.9.2))(typescript@5.9.2) + ethers: 6.13.2 + fs-extra: 9.1.0 + hardhat: 2.22.10(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2))(typescript@5.9.2) + typechain: 8.3.2(typescript@5.9.2) '@types/bn.js@4.11.6': dependencies: - '@types/node': 20.17.24 + '@types/node': 20.19.17 - '@types/bn.js@5.1.6': + '@types/bn.js@5.2.0': dependencies: - '@types/node': 20.17.24 + '@types/node': 20.19.17 '@types/chai-as-promised@7.1.8': dependencies: @@ -3231,24 +3443,26 @@ snapshots: '@types/concat-stream@1.6.1': dependencies: - '@types/node': 20.17.24 + '@types/node': 20.19.17 - '@types/estree@1.0.6': {} + '@types/estree@1.0.8': {} '@types/form-data@0.0.33': dependencies: - '@types/node': 20.17.24 + '@types/node': 20.19.17 '@types/glob@7.2.0': dependencies: - '@types/minimatch': 5.1.2 - '@types/node': 20.17.24 + '@types/minimatch': 6.0.0 + '@types/node': 20.19.17 '@types/json-schema@7.0.15': {} '@types/lru-cache@5.1.1': {} - '@types/minimatch@5.1.2': {} + '@types/minimatch@6.0.0': + dependencies: + minimatch: 10.0.3 '@types/mocha@10.0.10': {} @@ -3256,127 +3470,125 @@ snapshots: '@types/node@18.15.13': {} - '@types/node@20.17.24': + '@types/node@20.19.17': dependencies: - undici-types: 6.19.8 + undici-types: 6.21.0 '@types/node@22.7.5': dependencies: undici-types: 6.19.8 + '@types/node@24.5.2': + dependencies: + undici-types: 7.12.0 + optional: true + '@types/node@8.10.66': {} '@types/pbkdf2@3.1.2': dependencies: - '@types/node': 20.17.24 + '@types/node': 20.19.17 '@types/prettier@2.7.3': {} - '@types/qs@6.9.18': {} + '@types/qs@6.14.0': {} '@types/secp256k1@4.0.6': dependencies: - '@types/node': 20.17.24 - - '@types/semver@7.5.8': {} + '@types/node': 20.19.17 - '@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@9.22.0)(typescript@5.8.2))(eslint@9.22.0)(typescript@5.8.2)': + '@typescript-eslint/eslint-plugin@8.0.0(@typescript-eslint/parser@8.0.0(eslint@9.36.0)(typescript@5.9.2))(eslint@9.36.0)(typescript@5.9.2)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 6.21.0(eslint@9.22.0)(typescript@5.8.2) - '@typescript-eslint/scope-manager': 6.21.0 - '@typescript-eslint/type-utils': 6.21.0(eslint@9.22.0)(typescript@5.8.2) - '@typescript-eslint/utils': 6.21.0(eslint@9.22.0)(typescript@5.8.2) - '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.4.0(supports-color@8.1.1) - eslint: 9.22.0 + '@typescript-eslint/parser': 8.0.0(eslint@9.36.0)(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.0.0 + '@typescript-eslint/type-utils': 8.0.0(eslint@9.36.0)(typescript@5.9.2) + '@typescript-eslint/utils': 8.0.0(eslint@9.36.0)(typescript@5.9.2) + '@typescript-eslint/visitor-keys': 8.0.0 + eslint: 9.36.0 graphemer: 1.4.0 ignore: 5.3.2 natural-compare: 1.4.0 - semver: 7.7.1 - ts-api-utils: 1.4.3(typescript@5.8.2) + ts-api-utils: 1.4.3(typescript@5.9.2) optionalDependencies: - typescript: 5.8.2 + typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@6.21.0(eslint@9.22.0)(typescript@5.8.2)': + '@typescript-eslint/parser@8.0.0(eslint@9.36.0)(typescript@5.9.2)': dependencies: - '@typescript-eslint/scope-manager': 6.21.0 - '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.8.2) - '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.4.0(supports-color@8.1.1) - eslint: 9.22.0 + '@typescript-eslint/scope-manager': 8.0.0 + '@typescript-eslint/types': 8.0.0 + '@typescript-eslint/typescript-estree': 8.0.0(typescript@5.9.2) + '@typescript-eslint/visitor-keys': 8.0.0 + debug: 4.4.3(supports-color@8.1.1) + eslint: 9.36.0 optionalDependencies: - typescript: 5.8.2 + typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@6.21.0': + '@typescript-eslint/scope-manager@8.0.0': dependencies: - '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/visitor-keys': 6.21.0 + '@typescript-eslint/types': 8.0.0 + '@typescript-eslint/visitor-keys': 8.0.0 - '@typescript-eslint/type-utils@6.21.0(eslint@9.22.0)(typescript@5.8.2)': + '@typescript-eslint/type-utils@8.0.0(eslint@9.36.0)(typescript@5.9.2)': dependencies: - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.8.2) - '@typescript-eslint/utils': 6.21.0(eslint@9.22.0)(typescript@5.8.2) - debug: 4.4.0(supports-color@8.1.1) - eslint: 9.22.0 - ts-api-utils: 1.4.3(typescript@5.8.2) + '@typescript-eslint/typescript-estree': 8.0.0(typescript@5.9.2) + '@typescript-eslint/utils': 8.0.0(eslint@9.36.0)(typescript@5.9.2) + debug: 4.4.3(supports-color@8.1.1) + ts-api-utils: 1.4.3(typescript@5.9.2) optionalDependencies: - typescript: 5.8.2 + typescript: 5.9.2 transitivePeerDependencies: + - eslint - supports-color - '@typescript-eslint/types@6.21.0': {} + '@typescript-eslint/types@8.0.0': {} - '@typescript-eslint/typescript-estree@6.21.0(typescript@5.8.2)': + '@typescript-eslint/typescript-estree@8.0.0(typescript@5.9.2)': dependencies: - '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.4.0(supports-color@8.1.1) + '@typescript-eslint/types': 8.0.0 + '@typescript-eslint/visitor-keys': 8.0.0 + debug: 4.4.3(supports-color@8.1.1) globby: 11.1.0 is-glob: 4.0.3 - minimatch: 9.0.3 - semver: 7.7.1 - ts-api-utils: 1.4.3(typescript@5.8.2) + minimatch: 9.0.5 + semver: 7.7.2 + ts-api-utils: 1.4.3(typescript@5.9.2) optionalDependencies: - typescript: 5.8.2 + typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@6.21.0(eslint@9.22.0)(typescript@5.8.2)': + '@typescript-eslint/utils@8.0.0(eslint@9.36.0)(typescript@5.9.2)': dependencies: - '@eslint-community/eslint-utils': 4.5.0(eslint@9.22.0) - '@types/json-schema': 7.0.15 - '@types/semver': 7.5.8 - '@typescript-eslint/scope-manager': 6.21.0 - '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.8.2) - eslint: 9.22.0 - semver: 7.7.1 + '@eslint-community/eslint-utils': 4.9.0(eslint@9.36.0) + '@typescript-eslint/scope-manager': 8.0.0 + '@typescript-eslint/types': 8.0.0 + '@typescript-eslint/typescript-estree': 8.0.0(typescript@5.9.2) + eslint: 9.36.0 transitivePeerDependencies: - supports-color - typescript - '@typescript-eslint/visitor-keys@6.21.0': + '@typescript-eslint/visitor-keys@8.0.0': dependencies: - '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/types': 8.0.0 eslint-visitor-keys: 3.4.3 abbrev@1.0.9: {} - acorn-jsx@5.3.2(acorn@8.14.1): + acorn-jsx@5.3.2(acorn@8.15.0): dependencies: - acorn: 8.14.1 + acorn: 8.15.0 acorn-walk@8.3.4: dependencies: - acorn: 8.14.1 + acorn: 8.15.0 - acorn@8.14.1: {} + acorn@8.15.0: {} adm-zip@0.4.16: {} @@ -3386,7 +3598,7 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -3405,7 +3617,7 @@ snapshots: ajv@8.17.1: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.0.6 + fast-uri: 3.1.0 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -3469,10 +3681,14 @@ snapshots: at-least-node@1.0.0: {} - axios@1.8.3: + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.1.0 + + axios@1.12.2: dependencies: - follow-redirects: 1.15.9(debug@4.4.0) - form-data: 4.0.2 + follow-redirects: 1.15.11(debug@4.4.3) + form-data: 4.0.4 proxy-from-env: 1.1.0 transitivePeerDependencies: - debug @@ -3493,7 +3709,7 @@ snapshots: bn.js@4.12.1: {} - bn.js@5.2.1: {} + bn.js@5.2.2: {} boxen@5.1.2: dependencies: @@ -3506,12 +3722,12 @@ snapshots: widest-line: 3.1.0 wrap-ansi: 7.0.0 - brace-expansion@1.1.11: + brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@2.0.1: + brace-expansion@2.0.2: dependencies: balanced-match: 1.0.2 @@ -3553,6 +3769,13 @@ snapshots: es-errors: 1.3.0 function-bind: 1.1.2 + call-bind@1.0.8: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + call-bound@1.0.4: dependencies: call-bind-apply-helpers: 1.0.2 @@ -3616,10 +3839,6 @@ snapshots: optionalDependencies: fsevents: 2.3.3 - chokidar@4.0.3: - dependencies: - readdirp: 4.1.2 - ci-info@2.0.0: {} cipher-base@1.0.6: @@ -3698,17 +3917,17 @@ snapshots: cipher-base: 1.0.6 inherits: 2.0.4 md5.js: 1.3.5 - ripemd160: 2.0.2 - sha.js: 2.4.11 + ripemd160: 2.0.3 + sha.js: 2.4.12 create-hmac@1.1.7: dependencies: cipher-base: 1.0.6 create-hash: 1.2.0 inherits: 2.0.4 - ripemd160: 2.0.2 + ripemd160: 2.0.3 safe-buffer: 5.2.1 - sha.js: 2.4.11 + sha.js: 2.4.12 create-require@1.1.1: {} @@ -3726,7 +3945,7 @@ snapshots: dependencies: ms: 2.1.3 - debug@4.4.0(supports-color@8.1.1): + debug@4.4.3(supports-color@8.1.1): dependencies: ms: 2.1.3 optionalDependencies: @@ -3742,6 +3961,12 @@ snapshots: deep-is@0.1.4: {} + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + delayed-stream@1.0.0: {} depd@2.0.0: {} @@ -3758,7 +3983,7 @@ snapshots: dependencies: path-type: 4.0.0 - dotenv@16.4.7: {} + dotenv@16.6.1: {} dunder-proto@1.0.1: dependencies: @@ -3815,51 +4040,51 @@ snapshots: optionalDependencies: source-map: 0.2.0 - eslint-config-prettier@9.1.0(eslint@9.22.0): + eslint-config-prettier@9.1.2(eslint@9.36.0): dependencies: - eslint: 9.22.0 + eslint: 9.36.0 - eslint-plugin-prettier@5.2.3(eslint-config-prettier@9.1.0(eslint@9.22.0))(eslint@9.22.0)(prettier@3.5.3): + eslint-plugin-prettier@5.5.4(eslint-config-prettier@9.1.2(eslint@9.36.0))(eslint@9.36.0)(prettier@3.6.2): dependencies: - eslint: 9.22.0 - prettier: 3.5.3 + eslint: 9.36.0 + prettier: 3.6.2 prettier-linter-helpers: 1.0.0 - synckit: 0.9.2 + synckit: 0.11.11 optionalDependencies: - eslint-config-prettier: 9.1.0(eslint@9.22.0) + eslint-config-prettier: 9.1.2(eslint@9.36.0) - eslint-scope@8.3.0: + eslint-scope@8.4.0: dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 eslint-visitor-keys@3.4.3: {} - eslint-visitor-keys@4.2.0: {} + eslint-visitor-keys@4.2.1: {} - eslint@9.22.0: + eslint@9.36.0: dependencies: - '@eslint-community/eslint-utils': 4.5.0(eslint@9.22.0) + '@eslint-community/eslint-utils': 4.9.0(eslint@9.36.0) '@eslint-community/regexpp': 4.12.1 - '@eslint/config-array': 0.19.2 - '@eslint/config-helpers': 0.1.0 - '@eslint/core': 0.12.0 - '@eslint/eslintrc': 3.3.0 - '@eslint/js': 9.22.0 - '@eslint/plugin-kit': 0.2.7 - '@humanfs/node': 0.16.6 + '@eslint/config-array': 0.21.0 + '@eslint/config-helpers': 0.3.1 + '@eslint/core': 0.15.2 + '@eslint/eslintrc': 3.3.1 + '@eslint/js': 9.36.0 + '@eslint/plugin-kit': 0.3.5 + '@humanfs/node': 0.16.7 '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.4.2 - '@types/estree': 1.0.6 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 '@types/json-schema': 7.0.15 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) escape-string-regexp: 4.0.0 - eslint-scope: 8.3.0 - eslint-visitor-keys: 4.2.0 - espree: 10.3.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 esquery: 1.6.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 @@ -3877,11 +4102,11 @@ snapshots: transitivePeerDependencies: - supports-color - espree@10.3.0: + espree@10.4.0: dependencies: - acorn: 8.14.1 - acorn-jsx: 5.3.2(acorn@8.14.1) - eslint-visitor-keys: 4.2.0 + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 esprima@2.7.3: {} @@ -3904,7 +4129,7 @@ snapshots: eth-gas-reporter@0.2.27: dependencies: '@solidity-parser/parser': 0.14.5 - axios: 1.8.3 + axios: 1.12.2 cli-table3: 0.5.1 colors: 1.4.0 ethereum-cryptography: 1.2.0 @@ -3923,7 +4148,7 @@ snapshots: ethereum-bloom-filters@1.2.0: dependencies: - '@noble/hashes': 1.7.1 + '@noble/hashes': 1.8.0 ethereum-cryptography@0.1.3: dependencies: @@ -3936,7 +4161,7 @@ snapshots: create-hmac: 1.1.7 hash.js: 1.1.7 keccak: 3.0.4 - pbkdf2: 3.1.2 + pbkdf2: 3.1.4 randombytes: 2.1.0 safe-buffer: 5.2.1 scrypt-js: 3.0.1 @@ -3974,8 +4199,8 @@ snapshots: ethereumjs-util@7.1.5: dependencies: - '@types/bn.js': 5.1.6 - bn.js: 5.2.1 + '@types/bn.js': 5.2.0 + bn.js: 5.2.2 create-hash: 1.2.0 ethereum-cryptography: 0.1.3 rlp: 2.2.7 @@ -4029,7 +4254,7 @@ snapshots: - bufferutil - utf-8-validate - ethers@6.13.5: + ethers@6.15.0: dependencies: '@adraffy/ens-normalize': 1.10.1 '@noble/curves': 1.2.0 @@ -4073,16 +4298,12 @@ snapshots: fast-levenshtein@2.0.6: {} - fast-uri@3.0.6: {} + fast-uri@3.1.0: {} fastq@1.19.1: dependencies: reusify: 1.1.0 - fdir@6.4.3(picomatch@4.0.2): - optionalDependencies: - picomatch: 4.0.2 - file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -4095,6 +4316,10 @@ snapshots: dependencies: array-back: 3.1.0 + find-up@2.1.0: + dependencies: + locate-path: 2.0.0 + find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -4109,23 +4334,29 @@ snapshots: flatted@3.3.3: {} - follow-redirects@1.15.9(debug@4.4.0): + follow-redirects@1.15.11(debug@4.4.3): optionalDependencies: - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) + + for-each@0.3.5: + dependencies: + is-callable: 1.2.7 - form-data@2.5.3: + form-data@2.5.5: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 es-set-tostringtag: 2.1.0 + hasown: 2.0.2 mime-types: 2.1.35 safe-buffer: 5.2.1 - form-data@4.0.2: + form-data@4.0.4: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 es-set-tostringtag: 2.1.0 + hasown: 2.0.2 mime-types: 2.1.35 fp-ts@1.19.3: {} @@ -4133,7 +4364,7 @@ snapshots: fs-extra@10.1.0: dependencies: graceful-fs: 4.2.11 - jsonfile: 6.1.0 + jsonfile: 6.2.0 universalify: 2.0.1 fs-extra@7.0.1: @@ -4152,7 +4383,7 @@ snapshots: dependencies: at-least-node: 1.0.0 graceful-fs: 4.2.11 - jsonfile: 6.1.0 + jsonfile: 6.2.0 universalify: 2.0.1 fs-readdir-recursive@1.1.0: {} @@ -4218,6 +4449,15 @@ snapshots: once: 1.4.0 path-is-absolute: 1.0.1 + glob@7.2.0: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + glob@7.2.3: dependencies: fs.realpath: 1.0.0 @@ -4247,7 +4487,7 @@ snapshots: globals@14.0.0: {} - globals@16.0.0: {} + globals@16.4.0: {} globby@10.0.2: dependencies: @@ -4284,11 +4524,11 @@ snapshots: optionalDependencies: uglify-js: 3.19.3 - hardhat-gas-reporter@1.0.10(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)): + hardhat-gas-reporter@1.0.10(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)): dependencies: array-uniq: 1.0.3 eth-gas-reporter: 0.2.27 - hardhat: 2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2) + hardhat: 2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2) sha1: 1.1.1 transitivePeerDependencies: - '@codechecks/client' @@ -4296,55 +4536,108 @@ snapshots: - debug - utf-8-validate - hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2): + hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2): dependencies: '@ethersproject/abi': 5.8.0 '@metamask/eth-sig-util': 4.0.1 - '@nomicfoundation/edr': 0.8.0 + '@nomicfoundation/edr': 0.5.2 '@nomicfoundation/ethereumjs-common': 4.0.4 '@nomicfoundation/ethereumjs-tx': 5.0.4 '@nomicfoundation/ethereumjs-util': 9.0.4 '@nomicfoundation/solidity-analyzer': 0.1.2 '@sentry/node': 5.30.0 - '@types/bn.js': 5.1.6 + '@types/bn.js': 5.2.0 '@types/lru-cache': 5.1.1 adm-zip: 0.4.16 aggregate-error: 3.1.0 ansi-escapes: 4.3.2 boxen: 5.1.2 - chokidar: 4.0.3 + chalk: 2.4.2 + chokidar: 3.6.0 ci-info: 2.0.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) enquirer: 2.4.1 env-paths: 2.2.1 ethereum-cryptography: 1.2.0 ethereumjs-abi: 0.6.8 - find-up: 5.0.0 + find-up: 2.1.0 fp-ts: 1.19.3 fs-extra: 7.0.1 + glob: 7.2.0 immutable: 4.3.7 io-ts: 1.10.4 - json-stream-stringify: 3.1.6 keccak: 3.0.4 lodash: 4.17.21 mnemonist: 0.38.5 mocha: 10.8.2 p-map: 4.0.0 - picocolors: 1.1.1 raw-body: 2.5.2 resolve: 1.17.0 semver: 6.3.1 - solc: 0.8.26(debug@4.4.0) + solc: 0.8.26(debug@4.4.3) source-map-support: 0.5.21 stacktrace-parser: 0.1.11 - tinyglobby: 0.2.12 tsort: 0.0.1 - undici: 5.28.5 + undici: 5.29.0 uuid: 8.3.2 ws: 7.5.10 optionalDependencies: - ts-node: 10.9.2(@types/node@20.17.24)(typescript@5.8.2) - typescript: 5.8.2 + ts-node: 10.9.2(@types/node@20.19.17)(typescript@5.9.2) + typescript: 5.9.2 + transitivePeerDependencies: + - bufferutil + - c-kzg + - supports-color + - utf-8-validate + + hardhat@2.22.10(ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2))(typescript@5.9.2): + dependencies: + '@ethersproject/abi': 5.8.0 + '@metamask/eth-sig-util': 4.0.1 + '@nomicfoundation/edr': 0.5.2 + '@nomicfoundation/ethereumjs-common': 4.0.4 + '@nomicfoundation/ethereumjs-tx': 5.0.4 + '@nomicfoundation/ethereumjs-util': 9.0.4 + '@nomicfoundation/solidity-analyzer': 0.1.2 + '@sentry/node': 5.30.0 + '@types/bn.js': 5.2.0 + '@types/lru-cache': 5.1.1 + adm-zip: 0.4.16 + aggregate-error: 3.1.0 + ansi-escapes: 4.3.2 + boxen: 5.1.2 + chalk: 2.4.2 + chokidar: 3.6.0 + ci-info: 2.0.0 + debug: 4.4.3(supports-color@8.1.1) + enquirer: 2.4.1 + env-paths: 2.2.1 + ethereum-cryptography: 1.2.0 + ethereumjs-abi: 0.6.8 + find-up: 2.1.0 + fp-ts: 1.19.3 + fs-extra: 7.0.1 + glob: 7.2.0 + immutable: 4.3.7 + io-ts: 1.10.4 + keccak: 3.0.4 + lodash: 4.17.21 + mnemonist: 0.38.5 + mocha: 10.8.2 + p-map: 4.0.0 + raw-body: 2.5.2 + resolve: 1.17.0 + semver: 6.3.1 + solc: 0.8.26(debug@4.4.3) + source-map-support: 0.5.21 + stacktrace-parser: 0.1.11 + tsort: 0.0.1 + undici: 5.29.0 + uuid: 8.3.2 + ws: 7.5.10 + optionalDependencies: + ts-node: 10.9.2(@types/node@24.5.2)(typescript@5.9.2) + typescript: 5.9.2 transitivePeerDependencies: - bufferutil - c-kzg @@ -4357,17 +4650,22 @@ snapshots: has-flag@4.0.0: {} + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + has-symbols@1.1.0: {} has-tostringtag@1.0.2: dependencies: has-symbols: 1.1.0 - hash-base@3.1.0: + hash-base@3.1.2: dependencies: inherits: 2.0.4 - readable-stream: 3.6.2 + readable-stream: 2.3.8 safe-buffer: 5.2.1 + to-buffer: 1.2.1 hash.js@1.1.7: dependencies: @@ -4410,7 +4708,7 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) transitivePeerDependencies: - supports-color @@ -4452,6 +4750,8 @@ snapshots: dependencies: binary-extensions: 2.3.0 + is-callable@1.2.7: {} + is-core-module@2.16.1: dependencies: hasown: 2.0.2 @@ -4472,10 +4772,16 @@ snapshots: is-plain-obj@2.1.0: {} + is-typed-array@1.1.15: + dependencies: + which-typed-array: 1.1.19 + is-unicode-supported@0.1.0: {} isarray@1.0.0: {} + isarray@2.0.5: {} + isexe@2.0.0: {} js-sha3@0.8.0: {} @@ -4497,8 +4803,6 @@ snapshots: json-stable-stringify-without-jsonify@1.0.1: {} - json-stream-stringify@3.1.6: {} - json-stringify-safe@5.0.1: {} json5@2.2.3: {} @@ -4507,7 +4811,7 @@ snapshots: optionalDependencies: graceful-fs: 4.2.11 - jsonfile@6.1.0: + jsonfile@6.2.0: dependencies: universalify: 2.0.1 optionalDependencies: @@ -4539,6 +4843,11 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + locate-path@2.0.0: + dependencies: + p-locate: 2.0.0 + path-exists: 3.0.0 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 @@ -4574,7 +4883,7 @@ snapshots: md5.js@1.3.5: dependencies: - hash-base: 3.1.0 + hash-base: 3.1.2 inherits: 2.0.4 safe-buffer: 5.2.1 @@ -4599,17 +4908,21 @@ snapshots: minimalistic-crypto-utils@1.0.1: {} + minimatch@10.0.3: + dependencies: + '@isaacs/brace-expansion': 5.0.0 + minimatch@3.1.2: dependencies: - brace-expansion: 1.1.11 + brace-expansion: 1.1.12 minimatch@5.1.6: dependencies: - brace-expansion: 2.0.1 + brace-expansion: 2.0.2 - minimatch@9.0.3: + minimatch@9.0.5: dependencies: - brace-expansion: 2.0.1 + brace-expansion: 2.0.2 minimist@1.2.8: {} @@ -4628,7 +4941,7 @@ snapshots: ansi-colors: 4.1.3 browser-stdout: 1.3.1 chokidar: 3.6.0 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) diff: 5.2.0 escape-string-regexp: 4.0.0 find-up: 5.0.0 @@ -4715,10 +5028,18 @@ snapshots: os-tmpdir@1.0.2: {} + p-limit@1.3.0: + dependencies: + p-try: 1.0.0 + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 + p-locate@2.0.0: + dependencies: + p-limit: 1.3.0 + p-locate@5.0.0: dependencies: p-limit: 3.1.0 @@ -4727,12 +5048,16 @@ snapshots: dependencies: aggregate-error: 3.1.0 + p-try@1.0.0: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 parse-cache-control@1.0.1: {} + path-exists@3.0.0: {} + path-exists@4.0.0: {} path-is-absolute@1.0.1: {} @@ -4745,22 +5070,23 @@ snapshots: pathval@1.1.1: {} - pbkdf2@3.1.2: + pbkdf2@3.1.4: dependencies: create-hash: 1.2.0 create-hmac: 1.1.7 - ripemd160: 2.0.2 + ripemd160: 2.0.3 safe-buffer: 5.2.1 - sha.js: 2.4.11 + sha.js: 2.4.12 + to-buffer: 1.2.1 picocolors@1.1.1: {} picomatch@2.3.1: {} - picomatch@4.0.2: {} - pify@4.0.1: {} + possible-typed-array-names@1.1.0: {} + prelude-ls@1.1.2: {} prelude-ls@1.2.1: {} @@ -4771,7 +5097,7 @@ snapshots: prettier@2.8.8: {} - prettier@3.5.3: {} + prettier@3.6.2: {} process-nextick-args@2.0.1: {} @@ -4825,8 +5151,6 @@ snapshots: dependencies: picomatch: 2.3.1 - readdirp@4.1.2: {} - rechoir@0.6.2: dependencies: resolve: 1.22.10 @@ -4867,14 +5191,14 @@ snapshots: reusify@1.1.0: {} - ripemd160@2.0.2: + ripemd160@2.0.3: dependencies: - hash-base: 3.1.0 + hash-base: 3.1.2 inherits: 2.0.4 rlp@2.2.7: dependencies: - bn.js: 5.2.1 + bn.js: 5.2.2 run-parallel@1.2.0: dependencies: @@ -4915,20 +5239,30 @@ snapshots: semver@6.3.1: {} - semver@7.7.1: {} + semver@7.7.2: {} serialize-javascript@6.0.2: dependencies: randombytes: 2.1.0 + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + setimmediate@1.0.5: {} setprototypeof@1.2.0: {} - sha.js@2.4.11: + sha.js@2.4.12: dependencies: inherits: 2.0.4 safe-buffer: 5.2.1 + to-buffer: 1.2.1 sha1@1.1.1: dependencies: @@ -4985,11 +5319,11 @@ snapshots: astral-regex: 2.0.0 is-fullwidth-code-point: 3.0.0 - solc@0.8.26(debug@4.4.0): + solc@0.8.26(debug@4.4.3): dependencies: command-exists: 1.2.9 commander: 8.3.0 - follow-redirects: 1.15.9(debug@4.4.0) + follow-redirects: 1.15.11(debug@4.4.3) js-sha3: 0.8.0 memorystream: 0.3.1 semver: 5.7.2 @@ -4997,10 +5331,10 @@ snapshots: transitivePeerDependencies: - debug - solidity-coverage@0.8.14(hardhat@2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2)): + solidity-coverage@0.8.16(hardhat@2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2)): dependencies: '@ethersproject/abi': 5.8.0 - '@solidity-parser/parser': 0.19.0 + '@solidity-parser/parser': 0.20.2 chalk: 2.4.2 death: 1.1.0 difflib: 0.2.4 @@ -5008,7 +5342,7 @@ snapshots: ghost-testrpc: 0.0.2 global-modules: 2.0.0 globby: 10.0.2 - hardhat: 2.22.19(ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2))(typescript@5.8.2) + hardhat: 2.22.10(ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2))(typescript@5.9.2) jsonschema: 1.5.0 lodash: 4.17.21 mocha: 10.8.2 @@ -5016,7 +5350,7 @@ snapshots: pify: 4.0.1 recursive-readdir: 2.2.3 sc-istanbul: 0.4.6 - semver: 7.7.1 + semver: 7.7.2 shelljs: 0.8.5 web3-utils: 1.10.4 @@ -5107,10 +5441,9 @@ snapshots: dependencies: get-port: 3.2.0 - synckit@0.9.2: + synckit@0.11.11: dependencies: - '@pkgr/core': 0.1.1 - tslib: 2.8.1 + '@pkgr/core': 0.2.9 table-layout@1.0.2: dependencies: @@ -5132,10 +5465,10 @@ snapshots: '@types/concat-stream': 1.6.1 '@types/form-data': 0.0.33 '@types/node': 8.10.66 - '@types/qs': 6.9.18 + '@types/qs': 6.14.0 caseless: 0.12.0 concat-stream: 1.6.2 - form-data: 2.5.3 + form-data: 2.5.5 http-basic: 8.1.3 http-response-object: 3.0.2 promise: 8.3.0 @@ -5145,24 +5478,25 @@ snapshots: dependencies: readable-stream: 3.6.2 - tinyglobby@0.2.12: - dependencies: - fdir: 6.4.3(picomatch@4.0.2) - picomatch: 4.0.2 - tmp@0.0.33: dependencies: os-tmpdir: 1.0.2 + to-buffer@1.2.1: + dependencies: + isarray: 2.0.5 + safe-buffer: 5.2.1 + typed-array-buffer: 1.0.3 + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 toidentifier@1.0.1: {} - ts-api-utils@1.4.3(typescript@5.8.2): + ts-api-utils@1.4.3(typescript@5.9.2): dependencies: - typescript: 5.8.2 + typescript: 5.9.2 ts-command-line-args@2.5.1: dependencies: @@ -5171,36 +5505,53 @@ snapshots: command-line-usage: 6.1.3 string-format: 2.0.0 - ts-essentials@7.0.3(typescript@5.8.2): + ts-essentials@7.0.3(typescript@5.9.2): dependencies: - typescript: 5.8.2 + typescript: 5.9.2 - ts-node@10.9.2(@types/node@20.17.24)(typescript@5.8.2): + ts-node@10.9.2(@types/node@20.19.17)(typescript@5.9.2): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 20.17.24 - acorn: 8.14.1 + '@types/node': 20.19.17 + acorn: 8.15.0 acorn-walk: 8.3.4 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.8.2 + typescript: 5.9.2 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 + ts-node@10.9.2(@types/node@24.5.2)(typescript@5.9.2): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 24.5.2 + acorn: 8.15.0 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.9.2 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + optional: true + tslib@1.14.1: {} tslib@2.4.0: {} tslib@2.7.0: {} - tslib@2.8.1: {} - tsort@0.0.1: {} tweetnacl-util@0.15.1: {} @@ -5223,10 +5574,10 @@ snapshots: type-fest@0.7.1: {} - typechain@8.3.2(typescript@5.8.2): + typechain@8.3.2(typescript@5.9.2): dependencies: '@types/prettier': 2.7.3 - debug: 4.4.0(supports-color@8.1.1) + debug: 4.4.3(supports-color@8.1.1) fs-extra: 7.0.1 glob: 7.1.7 js-sha3: 0.8.0 @@ -5234,14 +5585,20 @@ snapshots: mkdirp: 1.0.4 prettier: 2.8.8 ts-command-line-args: 2.5.1 - ts-essentials: 7.0.3(typescript@5.8.2) - typescript: 5.8.2 + ts-essentials: 7.0.3(typescript@5.9.2) + typescript: 5.9.2 transitivePeerDependencies: - supports-color + typed-array-buffer@1.0.3: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + is-typed-array: 1.1.15 + typedarray@0.0.6: {} - typescript@5.8.2: {} + typescript@5.9.2: {} typical@4.0.0: {} @@ -5252,7 +5609,12 @@ snapshots: undici-types@6.19.8: {} - undici@5.28.5: + undici-types@6.21.0: {} + + undici-types@7.12.0: + optional: true + + undici@5.29.0: dependencies: '@fastify/busboy': 2.1.1 @@ -5277,7 +5639,7 @@ snapshots: web3-utils@1.10.4: dependencies: '@ethereumjs/util': 8.1.0 - bn.js: 5.2.1 + bn.js: 5.2.2 ethereum-bloom-filters: 1.2.0 ethereum-cryptography: 2.2.1 ethjs-unit: 0.1.6 @@ -5285,6 +5647,16 @@ snapshots: randombytes: 2.1.0 utf8: 3.0.0 + which-typed-array@1.1.19: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.8 + call-bound: 1.0.4 + for-each: 0.3.5 + get-proto: 1.0.1 + gopd: 1.2.0 + has-tostringtag: 1.0.2 + which@1.3.1: dependencies: isexe: 2.0.0 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..4340350 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - 'packages/*' \ No newline at end of file diff --git a/scripts/deploy-suite.ts b/scripts/deploy-suite.ts new file mode 100644 index 0000000..1fb0a73 --- /dev/null +++ b/scripts/deploy-suite.ts @@ -0,0 +1,68 @@ +import fs from 'fs' +import { main } from './fixtures/deploy-full-suite.fixture' +import { exportAccounts } from './utils' + +const exportPrivateKeys = process.env.EXPORT_PRIVATE_KEYS === 'true' + +;(async () => { + const result = await main({ + // suiteFilePath: 'SDSuiteDeployment.json', + // skipClaimIssuer: true, + // skipIdentities: false, + }) + + if (result) { + const content = JSON.stringify( + { + suite: { + claimIssuerContract: await result.suite.claimIssuerContract?.getAddress(), + claimTopicsRegistry: await result.suite.claimTopicsRegistry.getAddress(), + trustedIssuersRegistry: await result.suite.trustedIssuersRegistry.getAddress(), + identityRegistryStorage: await result.suite.identityRegistryStorage.getAddress(), + defaultCompliance: await result.suite.defaultCompliance.getAddress(), + identityRegistry: await result.suite.identityRegistry.getAddress(), + tokenOID: await result.suite.tokenOID.getAddress(), + token: await result.suite.token.getAddress(), + }, + authorities: { + identityImplementationAuthority: await result.authorities.identityImplementationAuthority.getAddress(), + trexImplementationAuthority: await result.authorities.trexImplementationAuthority.getAddress(), + }, + factories: { + identityFactory: await result.factories.identityFactory.getAddress(), + trexFactory: await result.factories.trexFactory.getAddress(), + }, + implementations: { + identityImplementation: await result.implementations.identityImplementation.getAddress(), + claimTopicsRegistryImplementation: + await result.implementations.claimTopicsRegistryImplementation.getAddress(), + trustedIssuersRegistryImplementation: + await result.implementations.trustedIssuersRegistryImplementation.getAddress(), + identityRegistryStorageImplementation: + await result.implementations.identityRegistryStorageImplementation.getAddress(), + identityRegistryImplementation: await result.implementations.identityRegistryImplementation.getAddress(), + modularComplianceImplementation: await result.implementations.modularComplianceImplementation.getAddress(), + tokenImplementation: await result.implementations.tokenImplementation.getAddress(), + }, + identities: result.identities + ? { + aliceIdentity: await result.identities.aliceIdentity.getAddress(), + bobIdentity: await result.identities.bobIdentity.getAddress(), + charlieIdentity: await result.identities.charlieIdentity.getAddress(), + } + : undefined, + accounts: exportAccounts( + result.accounts as Record, + exportPrivateKeys, + ), + }, + null, + 2, + ) + + if (!fs.existsSync('out')) { + fs.mkdirSync('out') + } + fs.writeFileSync('out/DeploymentOutput.json', content) + } +})() diff --git a/scripts/fixtures/deploy-basic-suite.ts b/scripts/fixtures/deploy-basic-suite.ts new file mode 100644 index 0000000..aca375f --- /dev/null +++ b/scripts/fixtures/deploy-basic-suite.ts @@ -0,0 +1,224 @@ +import { ethers } from 'hardhat' +import pc from 'picocolors' +import OnchainID from '@onchain-id/solidity' +import { UCEF3643Contracts } from '@appliedblockchain/ucef-3643' +import { + ClaimTopicsRegistry, + IdFactory, + IdentityRegistry, + IdentityRegistryStorage, + ModularCompliance, + Token, + TREXImplementationAuthority, + TrustedIssuersRegistry, + TREXFactory, + Identity, +} from '@appliedblockchain/ucef-3643/types' +import TREX from '@tokenysolutions/t-rex' +import { deployContractWithAbi, deployIdentityProxy, waitTx, Signers } from '../utils' + +export async function deployBasicSuite(signers: Signers) { + const { + deployer, + tokenIssuer, + tokenAgent, + tokenAdmin, + claimIssuer, + aliceWallet, + bobWallet, + charlieWallet, + davidWallet, + anotherWallet, + } = signers + + // Deploy implementations + console.log(pc.yellow('2/15 Deploying implementations...')) + console.log(pc.gray('ClaimTopicsRegistry')) + const claimTopicsRegistryImplementation = await deployContractWithAbi( + TREX.contracts.ClaimTopicsRegistry, + deployer, + ) + console.log(pc.gray('TrustedIssuersRegistry')) + const trustedIssuersRegistryImplementation = await deployContractWithAbi( + TREX.contracts.TrustedIssuersRegistry, + deployer, + ) + console.log(pc.gray('IdentityRegistryStorage')) + const identityRegistryStorageImplementation = await deployContractWithAbi( + TREX.contracts.IdentityRegistryStorage, + deployer, + ) + console.log(pc.gray('IdentityRegistry')) + const identityRegistryImplementation = await deployContractWithAbi( + TREX.contracts.IdentityRegistry, + deployer, + ) + console.log(pc.gray('ModularCompliance')) + const modularComplianceImplementation = await deployContractWithAbi( + TREX.contracts.ModularCompliance, + deployer, + ) + console.log(pc.gray('Token')) + const tokenImplementation = await deployContractWithAbi(UCEF3643Contracts.UCEF3643, deployer) + console.log(pc.gray('Identity')) + const identityImplementation = await deployContractWithAbi(OnchainID.contracts.Identity, deployer, [ + await deployer.getAddress(), + true, + ]) + + console.log(pc.gray('IdentityImplementationAuthority')) + const identityImplementationAuthority = await deployContractWithAbi( + OnchainID.contracts.ImplementationAuthority, + deployer, + [await identityImplementation.getAddress()], + ) + const identityImplementationAuthorityAddress = await identityImplementationAuthority.getAddress() + + console.log(pc.gray('IdentityFactory')) + const identityFactory = await deployContractWithAbi(OnchainID.contracts.Factory, deployer, [ + identityImplementationAuthorityAddress, + ]) + + console.log(pc.gray('TREXImplementationAuthority')) + const trexImplementationAuthority = await deployContractWithAbi( + TREX.contracts.TREXImplementationAuthority, + deployer, + [true, ethers.ZeroAddress, ethers.ZeroAddress], + ) + + const versionStruct = { + major: 4, + minor: 0, + patch: 0, + } + const contractsStruct = { + tokenImplementation: await tokenImplementation.getAddress(), + ctrImplementation: await claimTopicsRegistryImplementation.getAddress(), + irImplementation: await identityRegistryImplementation.getAddress(), + irsImplementation: await identityRegistryStorageImplementation.getAddress(), + tirImplementation: await trustedIssuersRegistryImplementation.getAddress(), + mcImplementation: await modularComplianceImplementation.getAddress(), + } + + await waitTx(await trexImplementationAuthority.connect(deployer).addAndUseTREXVersion(versionStruct, contractsStruct)) + + console.log(pc.yellow('3/15 Deploying factory...')) + const trexFactory = await deployContractWithAbi(TREX.contracts.TREXFactory, deployer, [ + await trexImplementationAuthority.getAddress(), + await identityFactory.getAddress(), + ]) + await waitTx(await identityFactory.connect(deployer).addTokenFactory(await trexFactory.getAddress())) + + const trexImplementationAuthorityAddress = await trexImplementationAuthority.getAddress() + + console.log(pc.yellow('4/15 Deploying Registry Proxies...')) + console.log(pc.gray('ClaimTopicsRegistry')) + const claimTopicsRegistry = await deployContractWithAbi( + TREX.contracts.ClaimTopicsRegistryProxy, + deployer, + [trexImplementationAuthorityAddress], + TREX.contracts.ClaimTopicsRegistry, + ) + console.log(pc.gray('TrustedIssuersRegistry')) + const trustedIssuersRegistry = await deployContractWithAbi( + TREX.contracts.TrustedIssuersRegistryProxy, + deployer, + [trexImplementationAuthorityAddress], + TREX.contracts.TrustedIssuersRegistry, + ) + console.log(pc.gray('IdentityRegistryStorage')) + const identityRegistryStorage = await deployContractWithAbi( + TREX.contracts.IdentityRegistryStorageProxy, + deployer, + [trexImplementationAuthorityAddress], + TREX.contracts.IdentityRegistryStorage, + ) + console.log(pc.gray('DefaultCompliance')) + const defaultCompliance = await deployContractWithAbi(TREX.contracts.ModularCompliance, deployer) + console.log(pc.gray('IdentityRegistry')) + const identityRegistry = await deployContractWithAbi( + TREX.contracts.IdentityRegistryProxy, + deployer, + [ + trexImplementationAuthorityAddress, + await trustedIssuersRegistry.getAddress(), + await claimTopicsRegistry.getAddress(), + await identityRegistryStorage.getAddress(), + ], + TREX.contracts.IdentityRegistry, + ) + + console.log(pc.yellow('5/15 Deploying Token Proxy...')) + const tokenOID = await deployIdentityProxy( + identityImplementationAuthorityAddress, + await tokenIssuer.getAddress(), + deployer, + ) + const tokenName = 'TREXDINO' + const tokenSymbol = 'TREX' + const tokenDecimals = 0n + const token = await deployContractWithAbi( + TREX.contracts.TokenProxy, + deployer, + [ + await trexImplementationAuthority.getAddress(), + await identityRegistry.getAddress(), + await defaultCompliance.getAddress(), + tokenName, + tokenSymbol, + tokenDecimals, + await tokenOID.getAddress(), + ], + TREX.contracts.Token, + ) + + console.log(pc.yellow('6/15 Binding Identity Registry...')) + await waitTx( + await identityRegistryStorage.connect(deployer).bindIdentityRegistry(await identityRegistry.getAddress()), + ) + + await waitTx(await token.connect(deployer).addAgent(await tokenAgent.getAddress())) + + console.log(pc.green('Basic suite fixture deployed successfully!')) + + return { + accounts: { + deployer, + tokenIssuer, + tokenAgent, + tokenAdmin, + claimIssuer, + aliceWallet, + bobWallet, + charlieWallet, + davidWallet, + anotherWallet, + }, + suite: { + claimTopicsRegistry, + trustedIssuersRegistry, + identityRegistryStorage, + defaultCompliance, + identityRegistry, + tokenOID, + token, + }, + authorities: { + trexImplementationAuthority, + identityImplementationAuthority, + }, + factories: { + trexFactory, + identityFactory, + }, + implementations: { + identityImplementation, + claimTopicsRegistryImplementation, + trustedIssuersRegistryImplementation, + identityRegistryStorageImplementation, + identityRegistryImplementation, + modularComplianceImplementation, + tokenImplementation, + }, + } +} diff --git a/scripts/fixtures/deploy-claim-issuer.ts b/scripts/fixtures/deploy-claim-issuer.ts new file mode 100644 index 0000000..7483442 --- /dev/null +++ b/scripts/fixtures/deploy-claim-issuer.ts @@ -0,0 +1,46 @@ +import { ethers } from 'hardhat' +import pc from 'picocolors' +import OnchainID from '@onchain-id/solidity' +import { ClaimIssuer } from '@appliedblockchain/ucef-3643/types' +import { ImportedSuite, deployContractWithAbi, waitTx } from '../utils' + +export async function deployClaimIssuer(data: ImportedSuite) { + console.log(pc.green('Deploying claim issuer, identities and claims...')) + + const { claimTopicsRegistry, trustedIssuersRegistry } = data.suite + const { deployer } = data.accounts + + const claimIssuerSigningKey = ethers.Wallet.createRandom() + data.accounts.claimIssuerSigningKey = claimIssuerSigningKey + + console.log(pc.yellow('7/15 Adding Claim Topic...')) + const claimTopics = [ethers.id('CLAIM_TOPIC')] + if ((await claimTopicsRegistry.getClaimTopics()).length === 0) { + await waitTx(await claimTopicsRegistry.connect(deployer).addClaimTopic(claimTopics[0])) + } + + const claimIssuerContract = await deployContractWithAbi(OnchainID.contracts.ClaimIssuer, deployer, [ + await deployer.getAddress(), + ]) + data.suite.claimIssuerContract = claimIssuerContract + + console.log(pc.yellow('8/15 Adding Claim Issuer Key...')) + await claimIssuerContract + .connect(deployer) + .addKey( + ethers.keccak256(ethers.AbiCoder.defaultAbiCoder().encode(['address'], [claimIssuerSigningKey.address])), + 3, + 1, + ) + + console.log(pc.yellow('9/15 Adding Trusted Issuer...')) + await waitTx( + await trustedIssuersRegistry + .connect(deployer) + .addTrustedIssuer(await claimIssuerContract.getAddress(), claimTopics), + ) + + console.log(pc.green('Claim issuer deployed successfully!')) + + return data +} diff --git a/scripts/fixtures/deploy-full-suite.fixture.ts b/scripts/fixtures/deploy-full-suite.fixture.ts new file mode 100644 index 0000000..b92193b --- /dev/null +++ b/scripts/fixtures/deploy-full-suite.fixture.ts @@ -0,0 +1,67 @@ +/** + * @title TREX Deploy Full Suite Fixture + * @dev Script imported and adapted from TokenySolutions/T-REX GitHub repository + * https://github.com/TokenySolutions/T-REX/blob/main/test/fixtures/deploy-full-suite.fixture.ts + */ + +import { ethers } from 'hardhat' +import pc from 'picocolors' +import { ImportedSuite, importSuite, createRandomWallet, Signers } from '../utils' +import { deployBasicSuite } from './deploy-basic-suite' +import { deployClaimIssuer } from './deploy-claim-issuer' +import { deployIdentities } from './deploy-identities' + +async function getSigners(): Promise { + const [ + deployer, + tokenIssuer, + tokenAgent, + tokenAdmin, + claimIssuer, + aliceWallet, + bobWallet, + charlieWallet, + davidWallet, + anotherWallet, + ] = await ethers.getSigners() + + return { + deployer: deployer || createRandomWallet(), + tokenIssuer: tokenIssuer || createRandomWallet(), + tokenAgent: tokenAgent || createRandomWallet(), + tokenAdmin: tokenAdmin || createRandomWallet(), + claimIssuer: claimIssuer || createRandomWallet(), + aliceWallet: aliceWallet || createRandomWallet(), + bobWallet: bobWallet || createRandomWallet(), + charlieWallet: charlieWallet || createRandomWallet(), + davidWallet: davidWallet || createRandomWallet(), + anotherWallet: anotherWallet || createRandomWallet(), + } +} + +export async function main({ + suiteFilePath, + skipClaimIssuer, + skipIdentities, +}: { + suiteFilePath?: string + skipClaimIssuer?: boolean + skipIdentities?: boolean +} = {}) { + let suite: ImportedSuite + + if (suiteFilePath) { + console.log(pc.green('Importing suite from file...')) + suite = await importSuite(suiteFilePath) + } else { + console.log(pc.green('Deploying full suite fixture...')) + console.log(pc.yellow('1/15 Getting signers...')) + const signers = await getSigners() + suite = (await deployBasicSuite(signers)) as unknown as ImportedSuite + } + + !skipClaimIssuer && (await deployClaimIssuer(suite)) + !skipIdentities && (await deployIdentities(suite)) + + return suite +} diff --git a/scripts/fixtures/deploy-identities.ts b/scripts/fixtures/deploy-identities.ts new file mode 100644 index 0000000..0661269 --- /dev/null +++ b/scripts/fixtures/deploy-identities.ts @@ -0,0 +1,134 @@ +import { ethers } from 'hardhat' +import pc from 'picocolors' +import { ImportedSuite, deployIdentityProxy, waitTx, ExtendedAccounts } from '../utils' + +export async function deployIdentities(data: ImportedSuite) { + console.log(pc.green('Deploying identities and claims...')) + const { token, identityRegistry, claimIssuerContract } = data.suite + const { identityImplementationAuthority } = data.authorities + const { deployer, aliceWallet, bobWallet, charlieWallet, tokenAgent } = data.accounts as ExtendedAccounts + const claimTopics = [ethers.id('CLAIM_TOPIC')] + + const aliceActionKey = ethers.Wallet.createRandom() + data.accounts.aliceActionKey = aliceActionKey + const claimIssuerSigningKey = data.accounts.claimIssuerSigningKey || ethers.Wallet.createRandom() + + const identityImplementationAuthorityAddress = await identityImplementationAuthority.getAddress() + + console.log(pc.yellow('10/15 Deploying Identities...')) + const aliceIdentity = await deployIdentityProxy( + identityImplementationAuthorityAddress, + await aliceWallet.getAddress(), + deployer, + ) + + await waitTx( + await aliceIdentity + .connect(aliceWallet) + .addKey(ethers.keccak256(ethers.AbiCoder.defaultAbiCoder().encode(['address'], [aliceActionKey.address])), 2, 1), + ) + const aliceIdentityAddress = await aliceIdentity.getAddress() + + const bobIdentity = await deployIdentityProxy( + identityImplementationAuthorityAddress, + await bobWallet.getAddress(), + deployer, + ) + const bobIdentityAddress = await bobIdentity.getAddress() + + const charlieIdentity = await deployIdentityProxy( + identityImplementationAuthorityAddress, + await charlieWallet.getAddress(), + deployer, + ) + + await waitTx(await identityRegistry.connect(deployer).addAgent(await tokenAgent.getAddress())) + await waitTx(await identityRegistry.connect(deployer).addAgent(await token.getAddress())) + + console.log(pc.yellow('11/15 Batch Registering Identities...')) + await waitTx( + await identityRegistry + .connect(tokenAgent) + .batchRegisterIdentity( + [await aliceWallet.getAddress(), await bobWallet.getAddress()], + [aliceIdentityAddress, bobIdentityAddress], + [42, 666], + ), + ) + + console.log(pc.yellow('12/15 Adding Claim for Alice...')) + const claimForAlice = { + data: ethers.hexlify(ethers.toUtf8Bytes('Some claim public data.')), + issuer: await claimIssuerContract!.getAddress(), + topic: claimTopics[0], + scheme: 1, + identity: aliceIdentityAddress, + signature: '', + } + claimForAlice.signature = await claimIssuerSigningKey.signMessage( + ethers.getBytes( + ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode( + ['address', 'uint256', 'bytes'], + [claimForAlice.identity, claimForAlice.topic, claimForAlice.data], + ), + ), + ), + ) + + await waitTx( + await aliceIdentity + .connect(aliceWallet) + .addClaim( + claimForAlice.topic, + claimForAlice.scheme, + claimForAlice.issuer, + claimForAlice.signature, + claimForAlice.data, + '', + ), + ) + + console.log(pc.yellow('13/15 Adding Claim for Bob...')) + const claimForBob = { + data: ethers.hexlify(ethers.toUtf8Bytes('Some claim public data.')), + issuer: await claimIssuerContract!.getAddress(), + topic: claimTopics[0], + scheme: 1, + identity: bobIdentityAddress, + signature: '', + } + claimForBob.signature = await claimIssuerSigningKey.signMessage( + ethers.getBytes( + ethers.keccak256( + ethers.AbiCoder.defaultAbiCoder().encode( + ['address', 'uint256', 'bytes'], + [claimForBob.identity, claimForBob.topic, claimForBob.data], + ), + ), + ), + ) + + await waitTx( + await bobIdentity + .connect(bobWallet) + .addClaim(claimForBob.topic, claimForBob.scheme, claimForBob.issuer, claimForBob.signature, claimForBob.data, ''), + ) + + console.log(pc.yellow('14/15 Minting tokens...')) + await waitTx(await token.connect(tokenAgent).mint(await aliceWallet.getAddress(), 1000)) + await waitTx(await token.connect(tokenAgent).mint(await bobWallet.getAddress(), 500)) + + console.log(pc.yellow('15/15 Unpausing token...')) + await waitTx(await token.connect(tokenAgent).unpause()) + + data.identities = { + aliceIdentity, + bobIdentity, + charlieIdentity, + } + + console.log(pc.green('Claim issuer, identities and claims deployed successfully!')) + + return data +} diff --git a/scripts/utils/deploy.ts b/scripts/utils/deploy.ts new file mode 100644 index 0000000..a36536b --- /dev/null +++ b/scripts/utils/deploy.ts @@ -0,0 +1,66 @@ +import { BaseContract, ContractTransactionResponse, Signer } from 'ethers' +import { ethers, network } from 'hardhat' +import { NetworkName } from '@appliedblockchain/silentdatarollup-core' +import { SilentDataRollupProvider } from '@appliedblockchain/silentdatarollup-ethers-provider' +import OnchainID from '@onchain-id/solidity' +import { Identity } from '@appliedblockchain/ucef-3643' + +export async function deployContract( + name: string, + signer: Signer, + args: any[] = [], + contractName = name, +) { + const factory = await ethers.getContractFactory(name, signer) + const contract = await factory.deploy(...args) + + await contract.waitForDeployment() + + return ethers.getContractAt(contractName, await contract.getAddress(), signer) as unknown as Promise +} + +export async function deployContractWithAbi( + artifacts: { abi: any; bytecode: any; contractName: string }, + signer: Signer, + args: any[] = [], + returnArtifacts?: { abi: any; bytecode: any; contractName: string }, +) { + const { abi, bytecode } = artifacts + const factory = new ethers.ContractFactory(abi, bytecode, signer) + const contract = await factory.deploy(...args) + + await contract.waitForDeployment() + + return ethers.getContractAt(returnArtifacts?.abi || abi, await contract.getAddress(), signer) as unknown as Promise +} + +export async function deployIdentityProxy(implementationAuthority: string, managementKey: string, signer: Signer) { + return deployContractWithAbi( + OnchainID.contracts.IdentityProxy, + signer, + [implementationAuthority, managementKey], + OnchainID.contracts.Identity, + ) +} + +export async function waitTx(tx: ContractTransactionResponse) { + return tx.wait() +} + +export function createRandomWallet() { + let wallet = ethers.Wallet.createRandom() + if (network.name === 'silentdata') { + const url = (network.config as any).url as string + const provider = new SilentDataRollupProvider({ + rpcUrl: url, + network: NetworkName.TESTNET, + chainId: network.config.chainId, + privateKey: wallet.privateKey, + }) + wallet = wallet.connect(provider) + } else { + wallet = wallet.connect(ethers.provider) + } + + return wallet +} diff --git a/scripts/utils/export-accounts.ts b/scripts/utils/export-accounts.ts new file mode 100644 index 0000000..e458d14 --- /dev/null +++ b/scripts/utils/export-accounts.ts @@ -0,0 +1,15 @@ +export function exportAccounts( + accounts: Record, + exportPrivateKey = false, +) { + return Object.entries(accounts) + .filter(([_, account]) => account.address) + .map(([name, account]) => { + return { + [name]: { + address: account.address, + ...(exportPrivateKey && { privateKey: account.privateKey }), + }, + } + }) +} diff --git a/scripts/utils/import-suite.ts b/scripts/utils/import-suite.ts new file mode 100644 index 0000000..1686419 --- /dev/null +++ b/scripts/utils/import-suite.ts @@ -0,0 +1,201 @@ +import { Wallet, Signer, BaseContract } from 'ethers' +import { ethers, network } from 'hardhat' +import { NetworkName } from '@appliedblockchain/silentdatarollup-core' +import { SilentDataRollupProvider } from '@appliedblockchain/silentdatarollup-ethers-provider' +import { + ClaimTopicsRegistry, + TrustedIssuersRegistry, + IdentityRegistryStorage, + DefaultCompliance, + IdentityRegistry, + Token, + TREXImplementationAuthority, + TREXFactory, + IdFactory, + ImplementationAuthority, + ClaimIssuer, + Identity, +} from '@appliedblockchain/ucef-3643/types' + +interface Suite { + claimIssuerContract?: ClaimIssuer + claimTopicsRegistry: ClaimTopicsRegistry + trustedIssuersRegistry: TrustedIssuersRegistry + identityRegistryStorage: IdentityRegistryStorage + defaultCompliance: DefaultCompliance + identityRegistry: IdentityRegistry + tokenOID: BaseContract // Identity contract + token: Token +} + +interface Authorities { + identityImplementationAuthority: ImplementationAuthority + trexImplementationAuthority: TREXImplementationAuthority +} + +interface Factories { + identityFactory: IdFactory + trexFactory: TREXFactory +} + +interface Implementations { + identityImplementation: BaseContract // Identity contract + claimTopicsRegistryImplementation: ClaimTopicsRegistry + trustedIssuersRegistryImplementation: TrustedIssuersRegistry + identityRegistryStorageImplementation: IdentityRegistryStorage + identityRegistryImplementation: IdentityRegistry + modularComplianceImplementation: BaseContract // ModularCompliance contract + tokenImplementation: Token +} + +interface Identities { + aliceIdentity: Identity + bobIdentity: Identity + charlieIdentity: Identity +} + +export interface ImportedSuite { + accounts: Record + suite: Suite + authorities: Authorities + factories: Factories + implementations: Implementations + identities?: Identities +} + +function getContractFactory(name: string) { + return ethers.getContractFactory(name) as unknown as Promise +} + +async function getSignersFromAccounts(accounts: any): Promise> { + const signers: Record = {} + for (const account of accounts) { + const [name, details] = Object.entries(account)[0] as [string, { address: string; privateKey?: string }] + if (details.privateKey) { + const url = (network.config as any).url as string + const provider = new SilentDataRollupProvider({ + rpcUrl: url, + network: NetworkName.TESTNET, + chainId: network.config.chainId, + privateKey: details.privateKey, + }) + signers[name] = new ethers.Wallet(details.privateKey, provider) + } else { + signers[name] = await ethers.getSigner(details.address) + } + } + + return signers +} + +/** + * Import a suite from a JSON file and return the suite object with signers and contracts loaded + */ +export async function importSuite(filePath: string): Promise { + const fs = require('fs') + const path = require('path') + const { ethers } = require('hardhat') + + // Read the suite deployment JSON file + const suiteJson = JSON.parse(fs.readFileSync(filePath, 'utf8')) + + // Get contract factories + const [ + ClaimTopicsRegistry, + TrustedIssuersRegistry, + IdentityRegistryStorage, + DefaultCompliance, + IdentityRegistry, + Token, + TREXImplementationAuthority, + TREXFactory, + IdFactory, + ImplementationAuthority, + ClaimIssuer, + Identity, + ] = await Promise.all([ + getContractFactory('ClaimTopicsRegistry'), + getContractFactory('TrustedIssuersRegistry'), + getContractFactory('IdentityRegistryStorage'), + getContractFactory('DefaultCompliance'), + getContractFactory('IdentityRegistry'), + getContractFactory('UCEF3643'), + getContractFactory('TREXImplementationAuthority'), + getContractFactory('TREXFactory'), + getContractFactory('IdFactory'), + getContractFactory('ImplementationAuthority'), + getContractFactory('ClaimIssuer'), + getContractFactory('Identity'), + ]) + + // Get signers from accounts + const signers = await getSignersFromAccounts(suiteJson.accounts) + + const hasClaimIssuer = !!suiteJson.suite.claimIssuerContract + + // Load contracts + const suite: Suite = { + claimIssuerContract: hasClaimIssuer ? await ClaimIssuer.attach(suiteJson.suite.claimIssuerContract) as ClaimIssuer : undefined, + claimTopicsRegistry: await ClaimTopicsRegistry.attach(suiteJson.suite.claimTopicsRegistry) as ClaimTopicsRegistry, + trustedIssuersRegistry: await TrustedIssuersRegistry.attach(suiteJson.suite.trustedIssuersRegistry) as TrustedIssuersRegistry, + identityRegistryStorage: await IdentityRegistryStorage.attach(suiteJson.suite.identityRegistryStorage) as IdentityRegistryStorage, + defaultCompliance: await DefaultCompliance.attach(suiteJson.suite.defaultCompliance) as DefaultCompliance, + identityRegistry: await IdentityRegistry.attach(suiteJson.suite.identityRegistry) as IdentityRegistry, + tokenOID: await ethers.getContractAt('Identity', suiteJson.suite.tokenOID), + token: await Token.attach(suiteJson.suite.token) as Token, + } + + const authorities: Authorities = { + identityImplementationAuthority: await ImplementationAuthority.attach( + suiteJson.authorities.identityImplementationAuthority, + ) as ImplementationAuthority, + trexImplementationAuthority: await TREXImplementationAuthority.attach( + suiteJson.authorities.trexImplementationAuthority, + ) as TREXImplementationAuthority, + } + + const factories: Factories = { + identityFactory: await IdFactory.attach(suiteJson.factories.identityFactory) as IdFactory, + trexFactory: await TREXFactory.attach(suiteJson.factories.trexFactory) as TREXFactory, + } + + const implementations: Implementations = { + identityImplementation: await ethers.getContractAt('Identity', suiteJson.implementations.identityImplementation), + claimTopicsRegistryImplementation: await ClaimTopicsRegistry.attach( + suiteJson.implementations.claimTopicsRegistryImplementation, + ) as ClaimTopicsRegistry, + trustedIssuersRegistryImplementation: await TrustedIssuersRegistry.attach( + suiteJson.implementations.trustedIssuersRegistryImplementation, + ) as TrustedIssuersRegistry, + identityRegistryStorageImplementation: await IdentityRegistryStorage.attach( + suiteJson.implementations.identityRegistryStorageImplementation, + ) as IdentityRegistryStorage, + identityRegistryImplementation: await IdentityRegistry.attach( + suiteJson.implementations.identityRegistryImplementation, + ) as IdentityRegistry, + modularComplianceImplementation: await ethers.getContractAt( + 'ModularCompliance', + suiteJson.implementations.modularComplianceImplementation, + ), + tokenImplementation: await Token.attach(suiteJson.implementations.tokenImplementation) as Token, + } + + const hasIdentities = !!suiteJson.identities + let identities: Identities | undefined + if (hasIdentities) { + identities = { + aliceIdentity: await Identity.attach(suiteJson.identities.aliceIdentity) as Identity, + bobIdentity: await Identity.attach(suiteJson.identities.bobIdentity) as Identity, + charlieIdentity: await Identity.attach(suiteJson.identities.charlieIdentity) as Identity, + } + } + + return { + accounts: signers, + suite, + authorities, + factories, + implementations, + identities, + } +} diff --git a/scripts/utils/index.ts b/scripts/utils/index.ts new file mode 100644 index 0000000..aefbd9d --- /dev/null +++ b/scripts/utils/index.ts @@ -0,0 +1,4 @@ +export * from './deploy' +export * from './import-suite' +export * from './export-accounts' +export * from './types' diff --git a/scripts/utils/types.ts b/scripts/utils/types.ts new file mode 100644 index 0000000..63cab50 --- /dev/null +++ b/scripts/utils/types.ts @@ -0,0 +1,24 @@ +import { Signer, Wallet } from 'ethers' + +export interface Signers { + deployer: Signer + tokenIssuer: Signer + tokenAgent: Signer + tokenAdmin: Signer + claimIssuer: Signer + aliceWallet: Signer + bobWallet: Signer + charlieWallet: Signer + davidWallet: Signer + anotherWallet: Signer +} + +export interface ExtendedAccounts extends Record { + deployer: Wallet | Signer + aliceWallet: Wallet | Signer + bobWallet: Wallet | Signer + charlieWallet: Wallet | Signer + tokenAgent: Wallet | Signer + claimIssuerSigningKey?: Wallet + aliceActionKey?: Wallet +} \ No newline at end of file diff --git a/test/UCEF3643.test.ts b/test/UCEF3643.test.ts new file mode 100644 index 0000000..e1f4dff --- /dev/null +++ b/test/UCEF3643.test.ts @@ -0,0 +1,639 @@ +import { Signer } from 'ethers' +import { expect } from 'chai' +import { ethers } from 'hardhat' +import { UCEF3643, UCEF3643Contracts } from '@appliedblockchain/ucef-3643' +import MockTokenImplementation from '@appliedblockchain/ucef-3643/artifacts/contracts/mocks/MockNewTokenImplementation.sol/MockNewTokenImplementation.json' +import { MockCompliance, MockIdentityRegistry, MockTrexImplementationAuthority } from '../typechain-types' +import { deployToken3643 } from './fixtures/deploy-3643' + +describe('UCEF3643', function () { + let token: UCEF3643 + let owner: Signer + let ownerAddress: string + let addr1: Signer + let addr1Address: string + let addr2: Signer + let addr2Address: string + let agent: Signer + let mockIdentityRegistry: MockIdentityRegistry + let mockCompliance: MockCompliance + let trexIAuthority: MockTrexImplementationAuthority + + beforeEach(async function () { + // Get signers + ;[owner, addr1, addr2, agent] = await ethers.getSigners() + ownerAddress = await owner.getAddress() + addr1Address = await addr1.getAddress() + addr2Address = await addr2.getAddress() + + // Deploy UCEF3643 token + const { + token: token_, + mockIdentityRegistry: mockIdentityRegistry_, + mockCompliance: mockCompliance_, + trexIAuthority: trexIAuthority_, + } = await deployToken3643({ + agent, + name: 'Test Token', + symbol: 'TEST', + decimals: 18, + onchainID: ethers.ZeroAddress, + }) + + token = token_ + mockIdentityRegistry = mockIdentityRegistry_ + mockCompliance = mockCompliance_ + trexIAuthority = trexIAuthority_ + }) + + describe('Deployment', function () { + it('Should set the right owner', async function () { + expect(await token.owner()).to.equal(ownerAddress) + }) + + it('Should set the right name and symbol', async function () { + expect(await token.name()).to.equal('Test Token') + expect(await token.symbol()).to.equal('TEST') + }) + }) + + describe('Initialization', function () { + let newToken: UCEF3643 + + beforeEach(async function () { + // Deploy a new token for testing init + const tokenFactory = await ethers.getContractFactory( + UCEF3643Contracts.UCEF3643.abi, + UCEF3643Contracts.UCEF3643.bytecode, + owner, + ) + newToken = (await tokenFactory.deploy()) as unknown as UCEF3643 + await newToken.waitForDeployment() + }) + + it('Should update token implementation', async () => { + const newTokenFactory = await ethers.getContractFactory( + MockTokenImplementation.abi, + MockTokenImplementation.bytecode, + ) + const mockNewToken = (await newTokenFactory.deploy()) as unknown as UCEF3643 + await mockNewToken.waitForDeployment() + + const currentTokenAddress = await token.getAddress() + + // Update token implementation + await trexIAuthority.updateTokenImplementation(await mockNewToken.getAddress()) + + // Should retain the same token address + expect(await token.getAddress()).to.equal(currentTokenAddress) + + // Token storage is within proxy contract which should not change + // Should retain the identity registry of the token + expect(await token.identityRegistry()).to.equal(await mockIdentityRegistry.getAddress()) + // Should retain the same compliance + expect(await token.compliance()).to.equal(await mockCompliance.getAddress()) + // Should retain the same name and symbol + expect(await token.name()).to.equal('Test Token') + expect(await token.symbol()).to.equal('TEST') + + // Expect allowance method to be updated + const allowance = await token.allowance(ownerAddress, addr1Address) + expect(allowance).to.equal(99900) + }) + + it('Should initialize with valid parameters', async function () { + await newToken.init( + await mockIdentityRegistry.getAddress(), + await mockCompliance.getAddress(), + 'New Token', + 'NEW', + 18, + ethers.ZeroAddress, + ) + + expect(await newToken.name()).to.equal('New Token') + expect(await newToken.symbol()).to.equal('NEW') + expect(await newToken.decimals()).to.equal(18) + expect(await newToken.onchainID()).to.equal(ethers.ZeroAddress) + expect(await newToken.owner()).to.equal(ownerAddress) + expect(await newToken.identityRegistry()).to.equal(await mockIdentityRegistry.getAddress()) + expect(await newToken.compliance()).to.equal(await mockCompliance.getAddress()) + }) + + it('Should revert when initializing with zero address for identity registry', async function () { + await expect( + newToken.init( + ethers.ZeroAddress, + await mockCompliance.getAddress(), + 'New Token', + 'NEW', + 18, + ethers.ZeroAddress, + ), + ).to.be.revertedWith('invalid argument - zero address') + }) + + it('Should revert when initializing with zero address for compliance', async function () { + await expect( + newToken.init( + await mockIdentityRegistry.getAddress(), + ethers.ZeroAddress, + 'New Token', + 'NEW', + 18, + ethers.ZeroAddress, + ), + ).to.be.revertedWith('invalid argument - zero address') + }) + + it('Should revert when initializing with empty name', async function () { + await expect( + newToken.init( + await mockIdentityRegistry.getAddress(), + await mockCompliance.getAddress(), + '', + 'NEW', + 18, + ethers.ZeroAddress, + ), + ).to.be.revertedWith('invalid argument - empty string') + }) + + it('Should revert when initializing with empty symbol', async function () { + await expect( + newToken.init( + await mockIdentityRegistry.getAddress(), + await mockCompliance.getAddress(), + 'New Token', + '', + 18, + ethers.ZeroAddress, + ), + ).to.be.revertedWith('invalid argument - empty string') + }) + + it('Should revert when initializing with invalid decimals', async function () { + await expect( + newToken.init( + await mockIdentityRegistry.getAddress(), + await mockCompliance.getAddress(), + 'New Token', + 'NEW', + 19, // Invalid decimals + ethers.ZeroAddress, + ), + ).to.be.revertedWith('decimals between 0 and 18') + }) + + it('Should revert when trying to initialize twice', async function () { + await newToken.init( + await mockIdentityRegistry.getAddress(), + await mockCompliance.getAddress(), + 'New Token', + 'NEW', + 18, + ethers.ZeroAddress, + ) + + await expect( + newToken.init( + await mockIdentityRegistry.getAddress(), + await mockCompliance.getAddress(), + 'New Token', + 'NEW', + 18, + ethers.ZeroAddress, + ), + ).to.be.revertedWith('Initializable: contract is already initialized') + }) + }) + + describe('Balance Authorization', function () { + it('Should return balance if user is the owner of the account', async function () { + expect(await token.connect(addr1).balanceOf(addr1Address)).to.equal(0) + expect(await token.connect(owner).balanceOf(ownerAddress)).to.equal(0) + expect(await token.connect(addr2).balanceOf(addr2Address)).to.equal(0) + }) + + it('Should revert if user tries to access balance of another user', async function () { + await expect(token.connect(addr2).balanceOf(addr1Address)).to.be.revertedWith('Unauthorized balance access') + }) + + it('Should return balance if user is checking his own identity balance', async function () { + expect(await token.connect(addr1).balanceOf('0x26291175Fa0Ea3C8583fEdEB56805eA68289b105')).to.equal(0) + }) + }) + + describe('Token Transfers', function () { + beforeEach(async function () { + // Register and verify addr1 identity + await mockIdentityRegistry.registerIdentity(addr1Address, 1, true) + await mockIdentityRegistry.setVerified(addr1Address, true) + + // Set up mock to allow transfers + await mockCompliance.setCanTransfer(addr1Address, true) + + // Mint some tokens to addr1 + await token.connect(agent).mint(addr1Address, ethers.parseEther('1000')) + // Set up mock to allow transfers + await mockIdentityRegistry.setVerified(addr2Address, true) + }) + + it('Should transfer tokens between accounts', async function () { + await token.connect(addr1).transfer(addr2Address, ethers.parseEther('100')) + expect(await token.connect(addr2).balanceOf(addr2Address)).to.equal(ethers.parseEther('100')) + }) + + it('Should fail if sender address is frozen', async function () { + await token.connect(agent).setAddressFrozen(addr1Address, true) + await expect(token.connect(addr1).transfer(addr2Address, ethers.parseEther('100'))).to.be.revertedWith( + 'wallet is frozen', + ) + }) + + it('Should fail if sender is transferring frozen tokens', async function () { + expect(await token.connect(agent).freezePartialTokens(addr1Address, ethers.parseEther('1000'))) + // Should emit TokensFrozen event with zero amount + .to.emit(token, 'TokensFrozen') + .withArgs(addr1Address, 0n) + await expect(token.connect(addr1).transfer(addr2Address, ethers.parseEther('100'))).to.be.revertedWith( + 'Insufficient Balance', + ) + + // Unfreeze tokens + await expect(token.connect(agent).unfreezePartialTokens(addr1Address, ethers.parseEther('1000'))) + .to.emit(token, 'TokensUnfrozen') + .withArgs(addr1Address, 0) + await token.connect(addr1).transfer(addr2Address, ethers.parseEther('100')) + expect(await token.connect(addr2).balanceOf(addr2Address)).to.equal(ethers.parseEther('100')) + }) + + it('Should respect per-address transfer compliance', async function () { + // Initially addr1 should be able to transfer + await token.connect(addr1).transfer(addr2Address, ethers.parseEther('50')) + expect(await token.connect(addr2).balanceOf(addr2Address)).to.equal(ethers.parseEther('50')) + + // Disable transfers for addr1 + await mockCompliance.setCanTransfer(addr1Address, false) + await expect(token.connect(addr1).transfer(addr2Address, ethers.parseEther('100'))).to.be.revertedWith( + 'Transfer not possible', + ) + + // Enable transfers for addr1 again + await mockCompliance.setCanTransfer(addr1Address, true) + await token.connect(addr1).transfer(addr2Address, ethers.parseEther('100')) + expect(await token.connect(addr2).balanceOf(addr2Address)).to.equal(ethers.parseEther('150')) + }) + + it('Should respect per-address identity verification', async function () { + // Initially addr1 should be able to transfer + await token.connect(addr1).transfer(addr2Address, ethers.parseEther('50')) + expect(await token.connect(addr2).balanceOf(addr2Address)).to.equal(ethers.parseEther('50')) + + // Set addr2 identity to unverified + await mockIdentityRegistry.setVerified(addr2Address, false) + await expect(token.connect(addr1).transfer(addr2Address, ethers.parseEther('100'))).to.be.revertedWith( + 'Transfer not possible', + ) + + // Restore addr1 identity verification + await mockIdentityRegistry.setVerified(addr2Address, true) + await token.connect(addr1).transfer(addr2Address, ethers.parseEther('100')) + expect(await token.connect(addr2).balanceOf(addr2Address)).to.equal(ethers.parseEther('150')) + }) + + it('Should not allow transfer if token is paused', async function () { + await token.connect(agent).pause() + await expect(token.connect(addr1).transfer(addr2Address, ethers.parseEther('100'))).to.be.revertedWith( + 'Pausable: paused', + ) + }) + }) + + describe('Forced Transfers', function () { + beforeEach(async function () { + // Register and verify addr1 identity + await mockIdentityRegistry.registerIdentity(addr1Address, 1, true) + await mockIdentityRegistry.setVerified(addr1Address, true) + + // Set up mock to allow transfers + await mockCompliance.setCanTransfer(addr1Address, true) + + await token.connect(agent).mint(addr1Address, ethers.parseEther('1000')) + await mockIdentityRegistry.setVerified(addr2Address, true) + }) + + it('Should allow agent to force transfer tokens', async function () { + await token.connect(agent).forcedTransfer(addr1Address, addr2Address, ethers.parseEther('100')) + expect(await token.connect(addr2).balanceOf(addr2Address)).to.equal(ethers.parseEther('100')) + }) + + it('Should revert if sender is not agent', async function () { + await expect( + token.connect(addr1).forcedTransfer(addr1Address, addr2Address, ethers.parseEther('100')), + ).to.be.revertedWith('AgentRole: caller does not have the Agent role') + }) + + it('Should revert if not enough balance', async function () { + await expect( + token.connect(agent).forcedTransfer(addr1Address, addr2Address, ethers.parseEther('1001')), + ).to.be.revertedWith('sender balance too low') + }) + + it('Should allow agent to force transfer if tokens are not frozen', async function () { + await token.connect(agent).freezePartialTokens(addr1Address, ethers.parseEther('500')) + await expect(token.connect(agent).forcedTransfer(addr1Address, addr2Address, ethers.parseEther('100'))) + // Should not emit TokensUnfrozen event + .not.to.emit(token, 'TokensUnfrozen') + expect(await token.connect(addr2).balanceOf(addr2Address)).to.equal(ethers.parseEther('100')) + }) + + it('Should allow agent to force transfer if tokens are frozen but to account is verified', async function () { + await mockIdentityRegistry.setVerified(addr2Address, true) + await token.connect(agent).freezePartialTokens(addr1Address, ethers.parseEther('500')) + await expect(token.connect(agent).forcedTransfer(addr1Address, addr2Address, ethers.parseEther('600'))) + // Should emit TokensUnfrozen event with zero amount + .to.emit(token, 'TokensUnfrozen') + .withArgs(addr1Address, 0) + expect(await token.connect(addr2).balanceOf(addr2Address)).to.equal(ethers.parseEther('600')) + }) + + it('Should revert to force transfer if to account is not verified', async function () { + await mockIdentityRegistry.setVerified(addr2Address, false) + await token.connect(agent).freezePartialTokens(addr1Address, ethers.parseEther('500')) + + // Should revert transferring more than available tokens + await expect( + token.connect(agent).forcedTransfer(addr1Address, addr2Address, ethers.parseEther('600')), + ).to.be.revertedWith('Transfer not possible') + + // Should revert transferring less than available tokens + await expect( + token.connect(agent).forcedTransfer(addr1Address, addr2Address, ethers.parseEther('100')), + ).to.be.revertedWith('Transfer not possible') + }) + + it('Should force transfer if token is paused', async function () { + await token.connect(agent).pause() + await token.connect(agent).forcedTransfer(addr1Address, addr2Address, ethers.parseEther('100')) + expect(await token.connect(addr2).balanceOf(addr2Address)).to.equal(ethers.parseEther('100')) + }) + }) + + describe('Token Burning', function () { + beforeEach(async function () { + // Register and verify addr1 identity + await mockIdentityRegistry.registerIdentity(addr1Address, 1, true) + await mockIdentityRegistry.setVerified(addr1Address, true) + + // Set up mock to allow address 1 to transfer / burn tokens + await mockCompliance.setCanTransfer(addr1Address, true) + + await token.connect(agent).mint(addr1Address, ethers.parseEther('1000')) + }) + + it('Should burn tokens', async function () { + await token.connect(agent).burn(addr1Address, ethers.parseEther('500')) + expect(await token.connect(addr1).balanceOf(addr1Address)).to.equal(ethers.parseEther('500')) + }) + + it('Should revert if sender is not agent', async function () { + await expect(token.connect(addr1).burn(addr1Address, ethers.parseEther('500'))).to.be.revertedWith( + 'AgentRole: caller does not have the Agent role', + ) + }) + + it('Should revert if not enough balance', async function () { + await expect(token.connect(agent).burn(addr1Address, ethers.parseEther('1001'))).to.be.revertedWith( + 'cannot burn more than balance', + ) + }) + + it('Should burn tokens even though they are frozen', async function () { + await token.connect(agent).freezePartialTokens(addr1Address, ethers.parseEther('500')) + expect(await token.connect(agent).burn(addr1Address, ethers.parseEther('600'))) + // Should emit TokensUnfrozen event with zero amount + .to.emit(token, 'TokensUnfrozen') + .withArgs(addr1Address, 0) + expect(await token.connect(addr1).balanceOf(addr1Address)).to.equal(ethers.parseEther('400')) + }) + }) + + describe('Token Minting', function () { + beforeEach(async function () { + // Register and verify addr1 identity + await mockIdentityRegistry.registerIdentity(addr1Address, 1, true) + + // Set up mock to allow address 1 to transfer / burn tokens + await mockCompliance.setCanTransfer(addr1Address, true) + }) + + it('Should mint tokens', async function () { + await token.connect(agent).mint(addr1Address, ethers.parseEther('1000')) + expect(await token.connect(addr1).balanceOf(addr1Address)).to.equal(ethers.parseEther('1000')) + }) + + it('Should revert if sender is not agent', async function () { + await expect(token.connect(addr1).mint(addr1Address, ethers.parseEther('1000'))).to.be.revertedWith( + 'AgentRole: caller does not have the Agent role', + ) + }) + + it('Should revert if to address is not verified', async function () { + await mockIdentityRegistry.setVerified(addr1Address, false) + await expect(token.connect(agent).mint(addr1Address, ethers.parseEther('1000'))).to.be.revertedWith( + 'Identity is not verified.', + ) + }) + + it('Should revert if mint is disabled by compliance', async function () { + await mockCompliance.setCanTransfer(ethers.ZeroAddress, false) + await expect(token.connect(agent).mint(addr1Address, ethers.parseEther('1000'))).to.be.revertedWith( + 'Compliance not followed', + ) + }) + }) + + describe('Allowances', function () { + const ALLOWANCE_AMOUNT = ethers.parseEther('100') + + beforeEach(async function () { + // Register and verify identities + await mockIdentityRegistry.registerIdentity(addr1Address, 1, true) + await mockIdentityRegistry.registerIdentity(addr2Address, 1, true) + + // Set up mock to allow transfers + await mockCompliance.setCanTransfer(addr1Address, true) + await mockCompliance.setCanTransfer(addr2Address, true) + + // Mint tokens to addr1 for testing + await token.connect(agent).mint(addr1Address, ethers.parseEther('1000')) + }) + + describe('Access Control', function () { + beforeEach(async function () { + // Set up an allowance for testing + await token.connect(addr1).approve(addr2Address, ALLOWANCE_AMOUNT) + }) + + it('Should allow owner to view their own allowance', async function () { + const allowance = await token.connect(addr1).allowance(addr1Address, addr2Address) + expect(allowance).to.equal(ALLOWANCE_AMOUNT) + }) + + it('Should allow spender to view their allowance', async function () { + const allowance = await token.connect(addr2).allowance(addr1Address, addr2Address) + expect(allowance).to.equal(ALLOWANCE_AMOUNT) + }) + + it('Should revert when unauthorized third party tries to view allowance', async function () { + await expect(token.connect(addr2).allowance(addr1Address, ownerAddress)).to.be.revertedWith( + 'Unauthorized allowance access', + ) + }) + }) + + describe('Setting Allowances', function () { + it('Should set and get allowance correctly when called by owner', async function () { + await token.connect(addr1).approve(addr2Address, ALLOWANCE_AMOUNT) + const allowance = await token.connect(addr1).allowance(addr1Address, addr2Address) + expect(allowance).to.equal(ALLOWANCE_AMOUNT) + }) + + it('Should emit Approval event when setting allowance', async function () { + await expect(token.connect(addr1).approve(addr2Address, ALLOWANCE_AMOUNT)) + .to.emit(token, 'Approval') + .withArgs(ethers.ZeroAddress, ethers.ZeroAddress, 0n) + }) + + it('Should not allow setting allowance for zero address spender', async function () { + await expect(token.connect(addr1).approve(ethers.ZeroAddress, ALLOWANCE_AMOUNT)).to.be.revertedWith( + 'ERC20: approve to the zero address', + ) + }) + + it('Should allow changing allowance', async function () { + // Set initial allowance + await token.connect(addr1).approve(addr2Address, ALLOWANCE_AMOUNT) + + // Change allowance + const newAllowance = ALLOWANCE_AMOUNT * 2n + await token.connect(addr1).approve(addr2Address, newAllowance) + + const allowance = await token.connect(addr1).allowance(addr1Address, addr2Address) + expect(allowance).to.equal(newAllowance) + }) + + it('Should increase allowance', async function () { + // Set initial allowance + await token.connect(addr1).approve(addr2Address, ALLOWANCE_AMOUNT) + + // Increase allowance + await token.connect(addr1).increaseAllowance(addr2Address, ALLOWANCE_AMOUNT) + + const allowance = await token.connect(addr1).allowance(addr1Address, addr2Address) + expect(allowance).to.equal(ALLOWANCE_AMOUNT * 2n) + }) + + it('Should decrease allowance', async function () { + // Set initial allowance + await token.connect(addr1).approve(addr2Address, ALLOWANCE_AMOUNT) + + // Decrease allowance + await token.connect(addr1).decreaseAllowance(addr2Address, ALLOWANCE_AMOUNT) + + const allowance = await token.connect(addr1).allowance(addr1Address, addr2Address) + expect(allowance).to.equal(0n) + }) + }) + + describe('Using Allowances', function () { + beforeEach(async function () { + // Set up allowance for testing + await token.connect(addr1).approve(addr2Address, ALLOWANCE_AMOUNT) + }) + + it('Should allow spender to transfer allowed amount', async function () { + // addr2 transfers tokens from addr1 to themselves + await token.connect(addr2).transferFrom(addr1Address, addr2Address, ALLOWANCE_AMOUNT) + + // Check balances + expect(await token.connect(addr1).balanceOf(addr1Address)).to.equal(ethers.parseEther('900')) + expect(await token.connect(addr2).balanceOf(addr2Address)).to.equal(ALLOWANCE_AMOUNT) + + // Check allowance is reduced + const finalAllowance = await token.connect(addr2).allowance(addr1Address, addr2Address) + expect(finalAllowance).to.equal(0) + }) + + // This test is not valid for ERC-3643 (v4.1.6) implementation since arithmetic operation overflows + // it('Should not allow spender to transfer more than allowed amount', async function () { + // const exceedAmount = ALLOWANCE_AMOUNT + 1n + // await expect(token.connect(addr2).transferFrom(addr1Address, addr2Address, exceedAmount)).to.be.revertedWith( + // 'ERC20: insufficient allowance', + // ) + // }) + + it('Should revert if account is frozen', async function () { + await token.connect(agent).setAddressFrozen(addr1Address, true) + await expect( + token.connect(addr2).transferFrom(addr1Address, addr2Address, ALLOWANCE_AMOUNT), + ).to.be.revertedWith('wallet is frozen') + }) + + it('Should revert if to account is frozen', async function () { + await token.connect(agent).setAddressFrozen(addr2Address, true) + await expect( + token.connect(addr2).transferFrom(addr1Address, addr2Address, ALLOWANCE_AMOUNT), + ).to.be.revertedWith('wallet is frozen') + }) + + it('Should revert if to account is not verified', async function () { + await mockIdentityRegistry.setVerified(addr2Address, false) + await expect( + token.connect(addr2).transferFrom(addr1Address, addr2Address, ALLOWANCE_AMOUNT), + ).to.be.revertedWith('Transfer not possible') + }) + + it('Should revert if rejected by compliance', async function () { + await mockCompliance.setCanTransfer(addr1Address, false) + await expect( + token.connect(addr2).transferFrom(addr1Address, addr2Address, ALLOWANCE_AMOUNT), + ).to.be.revertedWith('Transfer not possible') + }) + + it('Should handle infinite allowance correctly', async function () { + const infiniteAllowance = ethers.MaxUint256 + + // Set infinite allowance + await token.connect(addr1).approve(addr2Address, infiniteAllowance) + + // Perform a transfer + const transferAmount = ALLOWANCE_AMOUNT + await token.connect(addr2).transferFrom(addr1Address, addr2Address, transferAmount) + + // Check that allowance remains infinite + const allowance = await token.connect(addr2).allowance(addr1Address, addr2Address) + expect(allowance).to.equal(infiniteAllowance - transferAmount) + }) + + it('Should fail when trying to transfer with expired allowance', async function () { + // Use up the allowance + await token.connect(addr2).transferFrom(addr1Address, addr2Address, ALLOWANCE_AMOUNT) + + // This test is not valid for ERC-3643 (v4.1.6) implementation since arithmetic operation overflows + // Try to transfer again + // await expect(token.connect(addr2).transferFrom(addr1Address, addr2Address, 1n)).to.be.revertedWith( + // 'ERC20: insufficient allowance', + // ) + }) + + it('Should not allow transfer if token is paused', async function () { + await token.connect(agent).pause() + await expect( + token.connect(addr2).transferFrom(addr1Address, addr2Address, ALLOWANCE_AMOUNT), + ).to.be.revertedWith('Pausable: paused') + }) + }) + }) +}) diff --git a/test/fixtures/deploy-3643.ts b/test/fixtures/deploy-3643.ts new file mode 100644 index 0000000..1381616 --- /dev/null +++ b/test/fixtures/deploy-3643.ts @@ -0,0 +1,77 @@ +import { ethers } from 'hardhat' +import { UCEF3643Contracts, UCEF3643 } from '@appliedblockchain/ucef-3643' +import TREX from '@tokenysolutions/t-rex' +import { MockIdentityRegistry, MockCompliance, MockTrexImplementationAuthority } from '../../typechain-types' +import { Signer } from 'ethers' + +export async function deployToken3643({ + agent, + name, + symbol, + decimals, + onchainID, +}: { + agent: Signer + name: string + symbol: string + decimals: number + onchainID: string +}) { + const agentAddress = await agent.getAddress() + // Deploy mock contracts + const MockIdentityRegistry = await ethers.getContractFactory('MockIdentityRegistry') + const mockIdentityRegistry = (await MockIdentityRegistry.deploy()) as unknown as MockIdentityRegistry + await mockIdentityRegistry.waitForDeployment() + + const MockCompliance = await ethers.getContractFactory('MockCompliance') + const mockCompliance = (await MockCompliance.deploy()) as unknown as MockCompliance + await mockCompliance.waitForDeployment() + + // Deploy UCEF3643 + const tokenFactory = await ethers.getContractFactory( + UCEF3643Contracts.UCEF3643.abi, + UCEF3643Contracts.UCEF3643.bytecode, + ) + const token = (await tokenFactory.deploy()) as unknown as UCEF3643 + await token.waitForDeployment() + + // Deploy TrexIAuthority + const TrexIAuthority = await ethers.getContractFactory('MockTrexImplementationAuthority') + const trexIAuthority = (await TrexIAuthority.deploy( + await token.getAddress(), + )) as unknown as MockTrexImplementationAuthority + await trexIAuthority.waitForDeployment() + + // Deploy UCEF3643 with proxy + const TokenProxy = await ethers.getContractFactory(TREX.contracts.TokenProxy.abi, TREX.contracts.TokenProxy.bytecode) + const tokenProxy_ = (await TokenProxy.deploy( + await trexIAuthority.getAddress(), + await mockIdentityRegistry.getAddress(), + await mockCompliance.getAddress(), + name, + symbol, + decimals, + onchainID, + )) as unknown as UCEF3643 + await tokenProxy_.waitForDeployment() + + const tokenProxy = (await ethers.getContractAt( + UCEF3643Contracts.UCEF3643.abi, + await tokenProxy_.getAddress(), + )) as unknown as UCEF3643 + + // Register and verify agent identity + await mockIdentityRegistry.registerIdentity(agentAddress, 1, true) + await mockIdentityRegistry.setVerified(agentAddress, true) + + // Grant agent role to our test agent + await tokenProxy.addAgent(agentAddress) + + // Set up mock to allow minting + await mockCompliance.setCanTransfer(ethers.ZeroAddress, true) + + // Unpause the token + await tokenProxy.connect(agent).unpause() + + return { token: tokenProxy, mockIdentityRegistry, mockCompliance, trexIAuthority } +}