From 785f106df0a9ae7bd26cf862f52313e29fa9dbf2 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Mon, 23 Dec 2024 12:11:29 +0300 Subject: [PATCH] feat: NFT and FT upgradeable using OpenZeppelin's UUPS (#6) --- contracts/nft/.gitignore | 2 + contracts/nft/contracts/evm/UniversalNFT.sol | 123 ++++++-- contracts/nft/contracts/example/Connected.sol | 18 -- .../nft/contracts/example/EVMUniversalNFT.sol | 6 + contracts/nft/contracts/example/Universal.sol | 19 -- .../example/ZetaChainUniversalNFT.sol | 6 + .../{Events.sol => UniversalNFTEvents.sol} | 2 +- .../nft/contracts/zetachain/UniversalNFT.sol | 138 +++++++-- contracts/nft/hardhat.config.ts | 24 +- contracts/nft/package.json | 11 +- contracts/nft/scripts/localnet.sh | 24 +- contracts/nft/scripts/testnet.sh | 15 +- contracts/nft/tasks/deploy.ts | 28 +- contracts/nft/tasks/index.ts | 5 + contracts/nft/tasks/mint.ts | 57 +++- ...iversalSetConnected.ts => setConnected.ts} | 21 +- ...nnectedSetUniversal.ts => setUniversal.ts} | 21 +- contracts/nft/tasks/transfer.ts | 42 +-- contracts/nft/yarn.lock | 291 ++++++++++++++++-- .../token/contracts/evm/UniversalToken.sol | 85 ++++- .../token/contracts/example/Connected.sol | 18 -- .../contracts/example/EVMUniversalToken.sol | 6 + .../token/contracts/example/Universal.sol | 19 -- .../example/ZetaChainUniversalToken.sol | 6 + .../{Events.sol => UniversalTokenEvents.sol} | 2 +- .../contracts/zetachain/UniversalToken.sol | 116 +++++-- contracts/token/hardhat.config.ts | 23 +- contracts/token/package.json | 3 +- contracts/token/scripts/localnet.sh | 24 +- contracts/token/tasks/deploy.ts | 31 +- contracts/token/tasks/index.ts | 5 + contracts/token/tasks/mint.ts | 24 +- ...iversalSetConnected.ts => setConnected.ts} | 22 +- ...nnectedSetUniversal.ts => setUniversal.ts} | 18 +- contracts/token/tasks/transfer.ts | 44 +-- contracts/token/yarn.lock | 230 +++++++++++++- 36 files changed, 1177 insertions(+), 352 deletions(-) delete mode 100644 contracts/nft/contracts/example/Connected.sol create mode 100644 contracts/nft/contracts/example/EVMUniversalNFT.sol delete mode 100644 contracts/nft/contracts/example/Universal.sol create mode 100644 contracts/nft/contracts/example/ZetaChainUniversalNFT.sol rename contracts/nft/contracts/shared/{Events.sol => UniversalNFTEvents.sol} (96%) create mode 100644 contracts/nft/tasks/index.ts rename contracts/nft/tasks/{universalSetConnected.ts => setConnected.ts} (71%) rename contracts/nft/tasks/{connectedSetUniversal.ts => setUniversal.ts} (67%) delete mode 100644 contracts/token/contracts/example/Connected.sol create mode 100644 contracts/token/contracts/example/EVMUniversalToken.sol delete mode 100644 contracts/token/contracts/example/Universal.sol create mode 100644 contracts/token/contracts/example/ZetaChainUniversalToken.sol rename contracts/token/contracts/shared/{Events.sol => UniversalTokenEvents.sol} (95%) create mode 100644 contracts/token/tasks/index.ts rename contracts/token/tasks/{universalSetConnected.ts => setConnected.ts} (71%) rename contracts/token/tasks/{connectedSetUniversal.ts => setUniversal.ts} (70%) diff --git a/contracts/nft/.gitignore b/contracts/nft/.gitignore index 34db758..17920e2 100644 --- a/contracts/nft/.gitignore +++ b/contracts/nft/.gitignore @@ -17,3 +17,5 @@ cache_forge access_token localnet.json + +.openzeppelin \ No newline at end of file diff --git a/contracts/nft/contracts/evm/UniversalNFT.sol b/contracts/nft/contracts/evm/UniversalNFT.sol index a07d694..9fa8868 100644 --- a/contracts/nft/contracts/evm/UniversalNFT.sol +++ b/contracts/nft/contracts/evm/UniversalNFT.sol @@ -2,50 +2,84 @@ pragma solidity 0.8.26; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; -import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; -import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; -import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol"; -import "@openzeppelin/contracts/access/Ownable2Step.sol"; import "@zetachain/protocol-contracts/contracts/evm/GatewayEVM.sol"; import {RevertContext} from "@zetachain/protocol-contracts/contracts/Revert.sol"; -import "../shared/Events.sol"; - -abstract contract UniversalNFT is - ERC721, - ERC721Enumerable, - ERC721URIStorage, - Ownable2Step, - Events +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; +import {ERC721EnumerableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol"; +import {ERC721URIStorageUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol"; +import {ERC721BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; +import {ERC721PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721PausableUpgradeable.sol"; + +import "../shared/UniversalNFTEvents.sol"; + +contract UniversalNFT is + Initializable, + ERC721Upgradeable, + ERC721URIStorageUpgradeable, + ERC721EnumerableUpgradeable, + ERC721PausableUpgradeable, + OwnableUpgradeable, + ERC721BurnableUpgradeable, + UUPSUpgradeable, + UniversalNFTEvents { - GatewayEVM public immutable gateway; + GatewayEVM public gateway; uint256 private _nextTokenId; address public universal; - uint256 public immutable gasLimitAmount; + uint256 public gasLimitAmount; error InvalidAddress(); error Unauthorized(); error InvalidGasLimit(); error GasTokenTransferFailed(); - function setUniversal(address contractAddress) external onlyOwner { - if (contractAddress == address(0)) revert InvalidAddress(); - universal = contractAddress; - emit SetUniversal(contractAddress); - } - modifier onlyGateway() { if (msg.sender != address(gateway)) revert Unauthorized(); _; } - constructor(address payable gatewayAddress, uint256 gas) { + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize( + address initialOwner, + string memory name, + string memory symbol, + address payable gatewayAddress, + uint256 gas + ) public initializer { + __ERC721_init(name, symbol); + __ERC721Enumerable_init(); + __ERC721URIStorage_init(); + __Ownable_init(initialOwner); + __ERC721Burnable_init(); + __UUPSUpgradeable_init(); if (gatewayAddress == address(0)) revert InvalidAddress(); if (gas == 0) revert InvalidGasLimit(); gasLimitAmount = gas; gateway = GatewayEVM(gatewayAddress); } - function safeMint(address to, string memory uri) public onlyOwner { + function setGasLimit(uint256 gas) external onlyOwner { + if (gas == 0) revert InvalidGasLimit(); + gasLimitAmount = gas; + } + + function setUniversal(address contractAddress) external onlyOwner { + if (contractAddress == address(0)) revert InvalidAddress(); + universal = contractAddress; + emit SetUniversal(contractAddress); + } + + function safeMint( + address to, + string memory uri + ) public whenNotPaused onlyOwner { uint256 hash = uint256( keccak256( abi.encodePacked(address(this), block.number, _nextTokenId++) @@ -63,7 +97,7 @@ abstract contract UniversalNFT is uint256 tokenId, address receiver, address destination - ) external payable { + ) external payable whenNotPaused { if (receiver == address(0)) revert InvalidAddress(); string memory uri = tokenURI(tokenId); @@ -134,30 +168,39 @@ abstract contract UniversalNFT is emit TokenTransferReverted(sender, tokenId, uri); } - receive() external payable {} - - fallback() external payable {} - // The following functions are overrides required by Solidity. function _update( address to, uint256 tokenId, address auth - ) internal override(ERC721, ERC721Enumerable) returns (address) { + ) + internal + override( + ERC721Upgradeable, + ERC721EnumerableUpgradeable, + ERC721PausableUpgradeable + ) + returns (address) + { return super._update(to, tokenId, auth); } function _increaseBalance( address account, uint128 value - ) internal override(ERC721, ERC721Enumerable) { + ) internal override(ERC721Upgradeable, ERC721EnumerableUpgradeable) { super._increaseBalance(account, value); } function tokenURI( uint256 tokenId - ) public view override(ERC721, ERC721URIStorage) returns (string memory) { + ) + public + view + override(ERC721Upgradeable, ERC721URIStorageUpgradeable) + returns (string memory) + { return super.tokenURI(tokenId); } @@ -166,9 +209,27 @@ abstract contract UniversalNFT is ) public view - override(ERC721, ERC721Enumerable, ERC721URIStorage) + override( + ERC721Upgradeable, + ERC721EnumerableUpgradeable, + ERC721URIStorageUpgradeable + ) returns (bool) { return super.supportsInterface(interfaceId); } + + function _authorizeUpgrade( + address newImplementation + ) internal override onlyOwner {} + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + receive() external payable {} } diff --git a/contracts/nft/contracts/example/Connected.sol b/contracts/nft/contracts/example/Connected.sol deleted file mode 100644 index bd5f92c..0000000 --- a/contracts/nft/contracts/example/Connected.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.26; - -import "../evm/UniversalNFT.sol"; - -contract Connected is UniversalNFT { - constructor( - address payable gatewayAddress, - address owner, - string memory name, - string memory symbol, - uint256 gasLimit - ) - UniversalNFT(gatewayAddress, gasLimit) - Ownable(owner) - ERC721(name, symbol) - {} -} diff --git a/contracts/nft/contracts/example/EVMUniversalNFT.sol b/contracts/nft/contracts/example/EVMUniversalNFT.sol new file mode 100644 index 0000000..9e625ae --- /dev/null +++ b/contracts/nft/contracts/example/EVMUniversalNFT.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import "../evm/UniversalNFT.sol"; + +contract EVMUniversalNFT is UniversalNFT {} diff --git a/contracts/nft/contracts/example/Universal.sol b/contracts/nft/contracts/example/Universal.sol deleted file mode 100644 index 11ff979..0000000 --- a/contracts/nft/contracts/example/Universal.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.26; - -import "../zetachain/UniversalNFT.sol"; - -contract Universal is UniversalNFT { - constructor( - address payable gatewayAddress, - address owner, - string memory name, - string memory symbol, - uint256 gasLimit, - address uniswapRouter - ) - UniversalNFT(gatewayAddress, gasLimit, uniswapRouter) - Ownable(owner) - ERC721(name, symbol) - {} -} diff --git a/contracts/nft/contracts/example/ZetaChainUniversalNFT.sol b/contracts/nft/contracts/example/ZetaChainUniversalNFT.sol new file mode 100644 index 0000000..3b5db25 --- /dev/null +++ b/contracts/nft/contracts/example/ZetaChainUniversalNFT.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.26; + +import "../zetachain/UniversalNFT.sol"; + +contract ZetaChainUniversalNFT is UniversalNFT {} diff --git a/contracts/nft/contracts/shared/Events.sol b/contracts/nft/contracts/shared/UniversalNFTEvents.sol similarity index 96% rename from contracts/nft/contracts/shared/Events.sol rename to contracts/nft/contracts/shared/UniversalNFTEvents.sol index eff1581..79747b2 100644 --- a/contracts/nft/contracts/shared/Events.sol +++ b/contracts/nft/contracts/shared/UniversalNFTEvents.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.26; -contract Events { +contract UniversalNFTEvents { event SetUniversal(address indexed universalAddress); event SetConnected(address indexed zrc20, address contractAddress); event TokenMinted(address indexed to, uint256 indexed tokenId, string uri); diff --git a/contracts/nft/contracts/zetachain/UniversalNFT.sol b/contracts/nft/contracts/zetachain/UniversalNFT.sol index 181f031..7b3e142 100644 --- a/contracts/nft/contracts/zetachain/UniversalNFT.sol +++ b/contracts/nft/contracts/zetachain/UniversalNFT.sol @@ -1,38 +1,48 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.26; -import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; -import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; -import "@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; -import "@openzeppelin/contracts/token/ERC721/extensions/ERC721Burnable.sol"; -import "@openzeppelin/contracts/access/Ownable2Step.sol"; import {RevertContext, RevertOptions} from "@zetachain/protocol-contracts/contracts/Revert.sol"; import "@zetachain/protocol-contracts/contracts/zevm/interfaces/UniversalContract.sol"; import "@zetachain/protocol-contracts/contracts/zevm/interfaces/IGatewayZEVM.sol"; +import "@zetachain/protocol-contracts/contracts/zevm/interfaces/IWZETA.sol"; import "@zetachain/protocol-contracts/contracts/zevm/GatewayZEVM.sol"; import {SwapHelperLib} from "@zetachain/toolkit/contracts/SwapHelperLib.sol"; import {SystemContract} from "@zetachain/toolkit/contracts/SystemContract.sol"; -import "../shared/Events.sol"; +import {ERC721Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol"; +import {ERC721BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol"; +import {ERC721EnumerableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol"; +import {ERC721PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721PausableUpgradeable.sol"; +import {ERC721URIStorageUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; -abstract contract UniversalNFT is - ERC721, - ERC721Enumerable, - ERC721URIStorage, - Ownable2Step, +import "../shared/UniversalNFTEvents.sol"; + +contract UniversalNFT is + Initializable, + ERC721Upgradeable, + ERC721URIStorageUpgradeable, + ERC721EnumerableUpgradeable, + ERC721PausableUpgradeable, + OwnableUpgradeable, + ERC721BurnableUpgradeable, UniversalContract, - Events + UUPSUpgradeable, + UniversalNFTEvents { - GatewayZEVM public immutable gateway; - address public immutable uniswapRouter; + GatewayZEVM public gateway; + address public uniswapRouter; uint256 private _nextTokenId; bool public constant isUniversal = true; - uint256 public immutable gasLimitAmount; + uint256 public gasLimitAmount; error TransferFailed(); error Unauthorized(); error InvalidAddress(); error InvalidGasLimit(); error ApproveFailed(); + error ZeroMsgValue(); mapping(address => address) public connected; @@ -41,11 +51,25 @@ abstract contract UniversalNFT is _; } - constructor( + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize( + address initialOwner, + string memory name, + string memory symbol, address payable gatewayAddress, uint256 gas, address uniswapRouterAddress - ) { + ) public initializer { + __ERC721_init(name, symbol); + __ERC721Enumerable_init(); + __ERC721URIStorage_init(); + __Ownable_init(initialOwner); + __ERC721Burnable_init(); + __UUPSUpgradeable_init(); if (gatewayAddress == address(0) || uniswapRouterAddress == address(0)) revert InvalidAddress(); if (gas == 0) revert InvalidGasLimit(); @@ -54,6 +78,11 @@ abstract contract UniversalNFT is gasLimitAmount = gas; } + function setGasLimit(uint256 gas) external onlyOwner { + if (gas == 0) revert InvalidGasLimit(); + gasLimitAmount = gas; + } + function setConnected( address zrc20, address contractAddress @@ -66,7 +95,8 @@ abstract contract UniversalNFT is uint256 tokenId, address receiver, address destination - ) public { + ) public payable whenNotPaused { + if (msg.value == 0) revert ZeroMsgValue(); if (receiver == address(0)) revert InvalidAddress(); string memory uri = tokenURI(tokenId); _burn(tokenId); @@ -74,12 +104,28 @@ abstract contract UniversalNFT is (address gasZRC20, uint256 gasFee) = IZRC20(destination) .withdrawGasFeeWithGasLimit(gasLimitAmount); if (destination != gasZRC20) revert InvalidAddress(); - if ( - !IZRC20(destination).transferFrom(msg.sender, address(this), gasFee) - ) revert TransferFailed(); - if (!IZRC20(destination).approve(address(gateway), gasFee)) { - revert ApproveFailed(); + + address WZETA = gateway.zetaToken(); + + IWETH9(WZETA).deposit{value: msg.value}(); + IWETH9(WZETA).approve(uniswapRouter, msg.value); + + uint256 out = SwapHelperLib.swapTokensForExactTokens( + uniswapRouter, + WZETA, + gasFee, + gasZRC20, + msg.value + ); + + uint256 remaining = msg.value - out; + + if (remaining > 0) { + IWETH9(WZETA).withdraw(remaining); + (bool success, ) = msg.sender.call{value: remaining}(""); + if (!success) revert TransferFailed(); } + bytes memory message = abi.encode( receiver, tokenId, @@ -87,7 +133,6 @@ abstract contract UniversalNFT is 0, msg.sender ); - CallOptions memory callOptions = CallOptions(gasLimitAmount, false); RevertOptions memory revertOptions = RevertOptions( @@ -98,6 +143,7 @@ abstract contract UniversalNFT is gasLimitAmount ); + IZRC20(gasZRC20).approve(address(gateway), gasFee); gateway.call( abi.encodePacked(connected[destination]), destination, @@ -109,7 +155,10 @@ abstract contract UniversalNFT is emit TokenTransfer(receiver, destination, tokenId, uri); } - function safeMint(address to, string memory uri) public onlyOwner { + function safeMint( + address to, + string memory uri + ) public onlyOwner whenNotPaused { uint256 hash = uint256( keccak256( abi.encodePacked(address(this), block.number, _nextTokenId++) @@ -193,20 +242,33 @@ abstract contract UniversalNFT is address to, uint256 tokenId, address auth - ) internal override(ERC721, ERC721Enumerable) returns (address) { + ) + internal + override( + ERC721Upgradeable, + ERC721EnumerableUpgradeable, + ERC721PausableUpgradeable + ) + returns (address) + { return super._update(to, tokenId, auth); } function _increaseBalance( address account, uint128 value - ) internal override(ERC721, ERC721Enumerable) { + ) internal override(ERC721Upgradeable, ERC721EnumerableUpgradeable) { super._increaseBalance(account, value); } function tokenURI( uint256 tokenId - ) public view override(ERC721, ERC721URIStorage) returns (string memory) { + ) + public + view + override(ERC721Upgradeable, ERC721URIStorageUpgradeable) + returns (string memory) + { return super.tokenURI(tokenId); } @@ -215,9 +277,27 @@ abstract contract UniversalNFT is ) public view - override(ERC721, ERC721Enumerable, ERC721URIStorage) + override( + ERC721Upgradeable, + ERC721EnumerableUpgradeable, + ERC721URIStorageUpgradeable + ) returns (bool) { return super.supportsInterface(interfaceId); } + + function _authorizeUpgrade( + address newImplementation + ) internal override onlyOwner {} + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + receive() external payable {} } diff --git a/contracts/nft/hardhat.config.ts b/contracts/nft/hardhat.config.ts index 38cc713..8a5cadd 100644 --- a/contracts/nft/hardhat.config.ts +++ b/contracts/nft/hardhat.config.ts @@ -1,9 +1,4 @@ -import "./tasks/deploy"; -import "./tasks/deploy"; -import "./tasks/mint"; -import "./tasks/transfer"; -import "./tasks/universalSetConnected"; -import "./tasks/connectedSetUniversal"; +import "./tasks"; import "@zetachain/localnet/tasks"; import "@nomicfoundation/hardhat-toolbox"; import "@zetachain/toolkit/tasks"; @@ -11,11 +6,26 @@ import "@zetachain/toolkit/tasks"; import { getHardhatConfigNetworks } from "@zetachain/networks"; import { HardhatUserConfig } from "hardhat/config"; +import "@nomiclabs/hardhat-ethers"; +import "@openzeppelin/hardhat-upgrades"; + const config: HardhatUserConfig = { networks: { ...getHardhatConfigNetworks(), }, - solidity: "0.8.26", + solidity: { + compilers: [ + { + settings: { + optimizer: { + enabled: true, + runs: 1000, + }, + }, + version: "0.8.26", + }, + ], + }, }; export default config; diff --git a/contracts/nft/package.json b/contracts/nft/package.json index 84fec51..a857c28 100644 --- a/contracts/nft/package.json +++ b/contracts/nft/package.json @@ -15,16 +15,20 @@ "@ethersproject/abi": "^5.4.7", "@ethersproject/providers": "^5.4.7", "@nomicfoundation/hardhat-chai-matchers": "^1.0.0", + "@nomicfoundation/hardhat-ethers": "^3.0.8", "@nomicfoundation/hardhat-foundry": "^1.1.2", "@nomicfoundation/hardhat-network-helpers": "^1.0.0", "@nomicfoundation/hardhat-toolbox": "^2.0.0", - "@nomiclabs/hardhat-ethers": "^2.0.0", + "@nomicfoundation/hardhat-verify": "^2.0.12", + "@nomiclabs/hardhat-ethers": "^2.2.3", "@nomiclabs/hardhat-etherscan": "^3.0.0", + "@openzeppelin/hardhat-upgrades": "1.28.0", "@typechain/ethers-v5": "^10.1.0", "@typechain/hardhat": "^6.1.2", "@types/chai": "^4.2.0", "@types/mocha": ">=9.1.0", "@types/node": ">=12.0.0", + "@types/validator": "^13.12.2", "@typescript-eslint/eslint-plugin": "^5.59.9", "@typescript-eslint/parser": "^5.59.9", "@zetachain/localnet": "4.0.0-rc6", @@ -53,9 +57,12 @@ "packageManager": "yarn@1.22.21+sha1.1959a18351b811cdeedbd484a8f86c3cc3bbaf72", "dependencies": { "@coral-xyz/anchor": "0.30.0", + "@openzeppelin/contracts": "^5.1.0", + "@openzeppelin/contracts-upgradeable": "^5.1.0", "@solana-developers/helpers": "^2.4.0", "@solana/spl-memo": "^0.2.5", "@solana/web3.js": "^1.95.2", - "@zetachain/protocol-contracts": "11.0.0-rc3" + "@zetachain/protocol-contracts": "11.0.0-rc3", + "validator": "^13.12.0" } } diff --git a/contracts/nft/scripts/localnet.sh b/contracts/nft/scripts/localnet.sh index e546d97..731b2c4 100755 --- a/contracts/nft/scripts/localnet.sh +++ b/contracts/nft/scripts/localnet.sh @@ -2,6 +2,8 @@ set -e set -x +set -o pipefail + if [ "$1" = "start" ]; then npx hardhat localnet --exit-on-error & sleep 10; fi function balance() { @@ -27,46 +29,46 @@ GATEWAY_BNB=$(jq -r '.addresses[] | select(.type=="gatewayEVM" and .chain=="bnb" UNISWAP_ROUTER=$(jq -r '.addresses[] | select(.type=="uniswapRouterInstance" and .chain=="zetachain") | .address' localnet.json) SENDER=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 -CONTRACT_ZETACHAIN=$(npx hardhat deploy --network localhost --gateway "$GATEWAY_ZETACHAIN" --uniswap-router "$UNISWAP_ROUTER" --json | jq -r '.contractAddress') +CONTRACT_ZETACHAIN=$(npx hardhat nft:deploy --network localhost --name ZetaChainUniversalNFT --gateway "$GATEWAY_ZETACHAIN" --uniswap-router "$UNISWAP_ROUTER" --json | jq -r '.contractAddress') echo -e "\nšŸš€ Deployed NFT contract on ZetaChain: $CONTRACT_ZETACHAIN" -CONTRACT_ETHEREUM=$(npx hardhat deploy --name Connected --json --network localhost --gateway "$GATEWAY_ETHEREUM" | jq -r '.contractAddress') +CONTRACT_ETHEREUM=$(npx hardhat nft:deploy --name EVMUniversalNFT --json --network localhost --gateway "$GATEWAY_ETHEREUM" | jq -r '.contractAddress') echo -e "šŸš€ Deployed NFT contract on Ethereum: $CONTRACT_ETHEREUM" -CONTRACT_BNB=$(npx hardhat deploy --name Connected --json --network localhost --gas-limit 1000000 --gateway "$GATEWAY_BNB" | jq -r '.contractAddress') +CONTRACT_BNB=$(npx hardhat nft:deploy --name EVMUniversalNFT --json --network localhost --gas-limit 1000000 --gateway "$GATEWAY_BNB" | jq -r '.contractAddress') echo -e "šŸš€ Deployed NFT contract on BNB chain: $CONTRACT_BNB" echo -e "\nšŸ“® User Address: $SENDER" echo -e "\nšŸ”— Setting universal and connected contracts..." -npx hardhat connected-set-universal --network localhost --contract "$CONTRACT_ETHEREUM" --universal "$CONTRACT_ZETACHAIN" --json &>/dev/null -npx hardhat connected-set-universal --network localhost --contract "$CONTRACT_BNB" --universal "$CONTRACT_ZETACHAIN" --json &>/dev/null -npx hardhat universal-set-connected --network localhost --contract "$CONTRACT_ZETACHAIN" --connected "$CONTRACT_ETHEREUM" --zrc20 "$ZRC20_ETHEREUM" --json &>/dev/null -npx hardhat universal-set-connected --network localhost --contract "$CONTRACT_ZETACHAIN" --connected "$CONTRACT_BNB" --zrc20 "$ZRC20_BNB" --json &>/dev/null +npx hardhat nft:set-universal --network localhost --contract "$CONTRACT_ETHEREUM" --universal "$CONTRACT_ZETACHAIN" --json +npx hardhat nft:set-universal --network localhost --contract "$CONTRACT_BNB" --universal "$CONTRACT_ZETACHAIN" --json &>/dev/null +npx hardhat nft:set-connected --network localhost --contract "$CONTRACT_ZETACHAIN" --connected "$CONTRACT_ETHEREUM" --zrc20 "$ZRC20_ETHEREUM" --json &>/dev/null +npx hardhat nft:set-connected --network localhost --contract "$CONTRACT_ZETACHAIN" --connected "$CONTRACT_BNB" --zrc20 "$ZRC20_BNB" --json &>/dev/null npx hardhat localnet-check balance -NFT_ID=$(npx hardhat mint --network localhost --json --contract "$CONTRACT_ZETACHAIN" --token-uri https://example.com/nft/metadata/1 | jq -r '.tokenId') +NFT_ID=$(npx hardhat nft:mint --network localhost --json --contract "$CONTRACT_ZETACHAIN" --token-uri https://example.com/nft/metadata/1 | jq -r '.tokenId') echo -e "\nMinted NFT with ID: $NFT_ID on ZetaChain." npx hardhat localnet-check balance echo -e "\nTransferring NFT: ZetaChain ā†’ Ethereum..." -npx hardhat transfer --network localhost --json --token-id "$NFT_ID" --from "$CONTRACT_ZETACHAIN" --to "$ZRC20_ETHEREUM" +npx hardhat nft:transfer --network localhost --json --token-id "$NFT_ID" --from "$CONTRACT_ZETACHAIN" --to "$ZRC20_ETHEREUM" --gas-amount 1 npx hardhat localnet-check balance echo -e "\nTransferring NFT: Ethereum ā†’ BNB..." -npx hardhat transfer --network localhost --json --token-id "$NFT_ID" --from "$CONTRACT_ETHEREUM" --to "$ZRC20_BNB" --gas-amount 0.1 +npx hardhat nft:transfer --network localhost --json --token-id "$NFT_ID" --from "$CONTRACT_ETHEREUM" --to "$ZRC20_BNB" --gas-amount 1 npx hardhat localnet-check balance echo -e "\nTransferring NFT: BNB ā†’ ZetaChain..." -npx hardhat transfer --network localhost --json --token-id "$NFT_ID" --from "$CONTRACT_BNB" +npx hardhat nft:transfer --network localhost --json --token-id "$NFT_ID" --from "$CONTRACT_BNB" npx hardhat localnet-check balance diff --git a/contracts/nft/scripts/testnet.sh b/contracts/nft/scripts/testnet.sh index efea409..3d84d93 100755 --- a/contracts/nft/scripts/testnet.sh +++ b/contracts/nft/scripts/testnet.sh @@ -2,20 +2,21 @@ set -e set -x +set -o pipefail npx hardhat compile --force --quiet -UNIVERSAL=$(npx hardhat deploy --name Universal --network zeta_testnet --gateway 0x6c533f7fe93fae114d0954697069df33c9b74fd7 --uniswap-router 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --gas-limit 500000 --json | jq -r '.contractAddress') -CONNECTED_BASE=$(npx hardhat deploy --name Connected --network base_sepolia --gateway 0x0c487a766110c85d301d96e33579c5b317fa4995 --gas-limit 500000 --json | jq -r '.contractAddress') -CONNECTED_BNB=$(npx hardhat deploy --name Connected --network bsc_testnet --gateway 0x0c487a766110c85d301d96e33579c5b317fa4995 --gas-limit 500000 --json | jq -r '.contractAddress') +UNIVERSAL=$(npx hardhat deploy --name ZetaChainUniversalNFT --network zeta_testnet --gateway 0x6c533f7fe93fae114d0954697069df33c9b74fd7 --uniswap-router 0x2ca7d64A7EFE2D62A725E2B35Cf7230D6677FfEe --gas-limit 500000 --json | jq -r '.contractAddress') +CONNECTED_BASE=$(npx hardhat deploy --name EVMUniversalNFT --network base_sepolia --gateway 0x0c487a766110c85d301d96e33579c5b317fa4995 --gas-limit 500000 --json | jq -r '.contractAddress') +CONNECTED_BNB=$(npx hardhat deploy --name EVMUniversalNFT --network bsc_testnet --gateway 0x0c487a766110c85d301d96e33579c5b317fa4995 --gas-limit 500000 --json | jq -r '.contractAddress') ZRC20_BASE=0x236b0DE675cC8F46AE186897fCCeFe3370C9eDeD ZRC20_BNB=0xd97B1de3619ed2c6BEb3860147E30cA8A7dC9891 -npx hardhat connected-set-counterparty --network base_sepolia --contract "$CONNECTED_BASE" --counterparty "$UNIVERSAL" --json +npx hardhat connected-set-universal --network base_sepolia --contract "$CONNECTED_BASE" --universal "$UNIVERSAL" --json -npx hardhat connected-set-counterparty --network bsc_testnet --contract "$CONNECTED_BNB" --counterparty "$UNIVERSAL" --json +npx hardhat connected-set-universal --network bsc_testnet --contract "$CONNECTED_BNB" --universal "$UNIVERSAL" --json -npx hardhat universal-set-counterparty --network zeta_testnet --contract "$UNIVERSAL" --counterparty "$CONNECTED_BASE" --zrc20 "$ZRC20_BASE" --json +npx hardhat universal-set-connected --network zeta_testnet --contract "$UNIVERSAL" --connected "$CONNECTED_BASE" --zrc20 "$ZRC20_BASE" --json -npx hardhat universal-set-counterparty --network zeta_testnet --contract "$UNIVERSAL" --counterparty "$CONNECTED_BNB" --zrc20 "$ZRC20_BNB" --json \ No newline at end of file +npx hardhat universal-set-connected --network zeta_testnet --contract "$UNIVERSAL" --connected "$CONNECTED_BNB" --zrc20 "$ZRC20_BNB" --json \ No newline at end of file diff --git a/contracts/nft/tasks/deploy.ts b/contracts/nft/tasks/deploy.ts index 845098d..a64109f 100644 --- a/contracts/nft/tasks/deploy.ts +++ b/contracts/nft/tasks/deploy.ts @@ -2,6 +2,7 @@ import { task, types } from "hardhat/config"; import { HardhatRuntimeEnvironment } from "hardhat/types"; const main = async (args: any, hre: HardhatRuntimeEnvironment) => { + const { isAddress } = hre.ethers.utils; const network = hre.network.name; const [signer] = await hre.ethers.getSigners(); @@ -11,21 +12,23 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { ); } + if ( + !isAddress(args.gateway) || + (args.uniswapRouter && !isAddress(args.uniswapRouter)) + ) { + throw new Error("Invalid Ethereum address provided."); + } + const factory: any = await hre.ethers.getContractFactory(args.name); - const contract = await factory.deploy( - args.gateway, + const contract = await hre.upgrades.deployProxy(factory, [ signer.address, args.tokenName, args.tokenSymbol, + args.gateway, args.gasLimit, ...(args.uniswapRouter ? [args.uniswapRouter] : []), - { - gasPrice: args.deployGasPrice, - } - ); - - await contract.deployed(); + ]); if (args.json) { console.log( @@ -33,17 +36,16 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { contractAddress: contract.address, deployer: signer.address, network: network, - transactionHash: contract.deployTransaction.hash, }) ); } else { console.log(`šŸš€ Successfully deployed "${args.name}" contract on ${network}. -šŸ“œ Contract address: ${contract.address} -šŸ”— Transaction hash: ${contract.deployTransaction.hash}`); +šŸ“œ Contract address: ${contract.target} +`); } }; -task("deploy", "Deploy the NFT contract", main) +export const nftDeploy = task("nft:deploy", "Deploy the NFT contract", main) .addFlag("json", "Output the result in JSON format") .addOptionalParam("tokenName", "NFT name", "Universal NFT") .addOptionalParam("tokenSymbol", "NFT symbol", "UNFT") @@ -51,7 +53,7 @@ task("deploy", "Deploy the NFT contract", main) .addOptionalParam( "gasLimit", "Gas limit for the transaction", - 1000000, + 10000000, types.int ) .addOptionalParam( diff --git a/contracts/nft/tasks/index.ts b/contracts/nft/tasks/index.ts new file mode 100644 index 0000000..c6de558 --- /dev/null +++ b/contracts/nft/tasks/index.ts @@ -0,0 +1,5 @@ +export { nftSetUniversal } from "./setUniversal"; +export { nftMint } from "./mint"; +export { nftTransfer } from "./transfer"; +export { nftSetConnected } from "./setConnected"; +export { nftDeploy } from "./deploy"; diff --git a/contracts/nft/tasks/mint.ts b/contracts/nft/tasks/mint.ts index 7806e3d..4e55d6d 100644 --- a/contracts/nft/tasks/mint.ts +++ b/contracts/nft/tasks/mint.ts @@ -1,7 +1,10 @@ import { task } from "hardhat/config"; import { HardhatRuntimeEnvironment } from "hardhat/types"; +import isURL from "validator/lib/isURL"; const main = async (args: any, hre: HardhatRuntimeEnvironment) => { + const { isAddress } = hre.ethers.utils; + const [signer] = await hre.ethers.getSigners(); if (signer === undefined) { throw new Error( @@ -9,8 +12,27 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { ); } + if (!isAddress(args.contract)) { + throw new Error("Invalid Ethereum address provided."); + } + + const supportedProtocols = ["https", "ipfs"]; + + const isValidTokenUri = isURL(args.tokenUri, { + require_protocol: true, + protocols: supportedProtocols, + }); + + if (!isValidTokenUri) { + throw new Error( + `Invalid token URI: ${ + args.tokenUri + }. Supported protocols are: ${supportedProtocols.join(", ")}.` + ); + } + const contract = await hre.ethers.getContractAt( - args.name as "Universal" | "Connected", + args.name as "ZetaChainUniversalNFT" | "EVMUniversalNFT", args.contract ); @@ -19,11 +41,26 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { const tx = await contract.safeMint(recipient, args.tokenUri); const receipt = await tx.wait(); - const transferEvent = receipt.events?.find( - (event: any) => event.event === "Transfer" - ); + const transferEvent = receipt.logs + .map((log: any) => { + try { + return contract.interface.parseLog(log); + } catch { + return null; + } + }) + .find((parsedLog: any) => parsedLog?.name === "Transfer"); + + if (!transferEvent) { + throw new Error("Transfer event not found in transaction logs."); + } + const tokenId = transferEvent?.args?.tokenId; + if (!tokenId) { + throw new Error("Transfer event not found in transaction logs."); + } + if (args.json) { console.log( JSON.stringify({ @@ -31,24 +68,28 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { mintTransactionHash: tx.hash, recipient: recipient, tokenURI: args.tokenUri, - tokenId: tokenId?.toString(), + tokenId: tokenId.toString(), }) ); } else { console.log(`šŸš€ Successfully minted NFT. šŸ“œ Contract address: ${args.contract} šŸ‘¤ Recipient: ${recipient} -šŸ†” Token ID: ${tokenId?.toString()} +šŸ†” Token ID: ${tokenId.toString()} šŸ”— Transaction hash: ${tx.hash}`); } }; -task("mint", "Mint an NFT", main) +export const nftMint = task("nft:mint", "Mint an NFT", main) .addParam("contract", "The address of the deployed NFT contract") .addOptionalParam( "to", "The recipient address, defaults to the signer address" ) .addParam("tokenUri", "The metadata URI of the token") - .addOptionalParam("name", "The contract name to interact with", "Universal") + .addOptionalParam( + "name", + "The contract name to interact with", + "ZetaChainUniversalNFT" + ) .addFlag("json", "Output the result in JSON format"); diff --git a/contracts/nft/tasks/universalSetConnected.ts b/contracts/nft/tasks/setConnected.ts similarity index 71% rename from contracts/nft/tasks/universalSetConnected.ts rename to contracts/nft/tasks/setConnected.ts index 249bdb0..3916695 100644 --- a/contracts/nft/tasks/universalSetConnected.ts +++ b/contracts/nft/tasks/setConnected.ts @@ -1,8 +1,9 @@ import { task } from "hardhat/config"; import { HardhatRuntimeEnvironment } from "hardhat/types"; -import { Universal } from "@/typechain-types"; +import { ZetaChainUniversalNFT } from "@/typechain-types"; const main = async (args: any, hre: HardhatRuntimeEnvironment) => { + const { isAddress } = hre.ethers.utils; const [signer] = await hre.ethers.getSigners(); if (!signer) { throw new Error( @@ -10,8 +11,16 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { ); } - const contract: Universal = await hre.ethers.getContractAt( - "Universal", + if ( + !isAddress(args.contract) || + !isAddress(args.zrc20) || + !isAddress(args.connected) + ) { + throw new Error("Invalid Ethereum address provided."); + } + + const contract: ZetaChainUniversalNFT = await hre.ethers.getContractAt( + "ZetaChainUniversalNFT", args.contract ); @@ -35,7 +44,11 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { } }; -task("universal-set-connected", "Sets the connected contract address", main) +export const nftSetConnected = task( + "nft:set-connected", + "Sets the connected contract address", + main +) .addParam("contract", "The address of the deployed contract") .addParam("zrc20", "The ZRC20 address to link to the connected contract") .addParam("connected", "The address of the connected contract to set") diff --git a/contracts/nft/tasks/connectedSetUniversal.ts b/contracts/nft/tasks/setUniversal.ts similarity index 67% rename from contracts/nft/tasks/connectedSetUniversal.ts rename to contracts/nft/tasks/setUniversal.ts index fb28783..9a54073 100644 --- a/contracts/nft/tasks/connectedSetUniversal.ts +++ b/contracts/nft/tasks/setUniversal.ts @@ -1,8 +1,9 @@ import { task } from "hardhat/config"; import { HardhatRuntimeEnvironment } from "hardhat/types"; -import { Connected } from "@/typechain-types"; +import { EVMUniversalNFT } from "@/typechain-types"; const main = async (args: any, hre: HardhatRuntimeEnvironment) => { + const { isAddress } = hre.ethers.utils; const [signer] = await hre.ethers.getSigners(); if (!signer) { throw new Error( @@ -10,12 +11,18 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { ); } - const contract: Connected = await hre.ethers.getContractAt( - "Connected", + if (!isAddress(args.contract) || !isAddress(args.universal)) { + throw new Error("Invalid Ethereum address provided."); + } + + const contract: EVMUniversalNFT = await hre.ethers.getContractAt( + "EVMUniversalNFT", args.contract ); - const tx = await contract.setUniversal(args.universal); + const tx = await contract.setUniversal(args.universal, { + gasLimit: 1000000, + }); const receipt = await tx.wait(); if (args.json) { @@ -34,7 +41,11 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { } }; -task("connected-set-universal", "Sets the universal contract address", main) +export const nftSetUniversal = task( + "nft:set-universal", + "Sets the universal contract address", + main +) .addParam("contract", "The address of the deployed contract") .addParam("universal", "The address of the universal contract to set") .addFlag("json", "Output the result in JSON format"); diff --git a/contracts/nft/tasks/transfer.ts b/contracts/nft/tasks/transfer.ts index 1ecb9b5..cf062da 100644 --- a/contracts/nft/tasks/transfer.ts +++ b/contracts/nft/tasks/transfer.ts @@ -1,10 +1,16 @@ import { task, types } from "hardhat/config"; import { HardhatRuntimeEnvironment } from "hardhat/types"; -import ZRC20ABI from "@zetachain/protocol-contracts/abi/ZRC20.sol/ZRC20.json"; const main = async (args: any, hre: HardhatRuntimeEnvironment) => { const { ethers } = hre; const [signer] = await ethers.getSigners(); + + const { isAddress } = hre.ethers.utils; + + if (!isAddress(args.to) || !isAddress(args.revertAddress)) { + throw new Error("Invalid Ethereum address provided."); + } + const nftContract = await ethers.getContractAt("IERC721", args.from); const approveTx = await nftContract .connect(signer) @@ -15,28 +21,22 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { gasPrice: args.txOptionsGasPrice, gasLimit: args.txOptionsGasLimit, }; - let tx; - let contract; - try { - contract = await ethers.getContractAt("Universal", args.from); - await (contract as any).isUniversal(); - const gasLimit = hre.ethers.BigNumber.from(args.txOptionsGasLimit); - const zrc20 = new ethers.Contract(args.to, ZRC20ABI.abi, signer); - const [, gasFee] = await zrc20.withdrawGasFeeWithGasLimit(gasLimit); - const zrc20TransferTx = await zrc20.approve(args.from, gasFee, txOptions); - await zrc20TransferTx.wait(); - } catch (e) { - contract = await ethers.getContractAt("Connected", args.from); - } + const contract = await ethers.getContractAt( + "ZetaChainUniversalNFT", + args.from + ); const gasAmount = ethers.utils.parseUnits(args.gasAmount, 18); const receiver = args.receiver || signer.address; - tx = await contract.transferCrossChain(args.tokenId, receiver, args.to, { - value: gasAmount, - }); + const tx = await contract.transferCrossChain( + args.tokenId, + receiver, + args.to, + { ...txOptions, value: gasAmount } + ); await tx.wait(); if (args.json) { @@ -57,7 +57,11 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { } }; -task("transfer", "Transfer and lock an NFT", main) +export const nftTransfer = task( + "nft:transfer", + "Transfer and lock an NFT", + main +) .addOptionalParam("receiver", "The address to receive the NFT") .addParam("from", "The contract being transferred from") .addParam("tokenId", "The ID of the NFT to transfer") @@ -70,7 +74,7 @@ task("transfer", "Transfer and lock an NFT", main) .addOptionalParam( "txOptionsGasLimit", "The gas limit for the transaction", - 7000000, + 10000000, types.int ) .addFlag("callOnRevert", "Whether to call on revert") diff --git a/contracts/nft/yarn.lock b/contracts/nft/yarn.lock index c23f5fa..92a9705 100644 --- a/contracts/nft/yarn.lock +++ b/contracts/nft/yarn.lock @@ -7,6 +7,39 @@ resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069" integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw== +"@aws-crypto/sha256-js@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-js/-/sha256-js-1.2.2.tgz#02acd1a1fda92896fc5a28ec7c6e164644ea32fc" + integrity sha512-Nr1QJIbW/afYYGzYvrF70LtaHrIRtd4TNAglX8BvlfxJLZ45SAmueIKYl5tWoNBPzp65ymXGFK0Bb1vZUpuc9g== + dependencies: + "@aws-crypto/util" "^1.2.2" + "@aws-sdk/types" "^3.1.0" + tslib "^1.11.1" + +"@aws-crypto/util@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@aws-crypto/util/-/util-1.2.2.tgz#b28f7897730eb6538b21c18bd4de22d0ea09003c" + integrity sha512-H8PjG5WJ4wz0UXAFXeJjWCW1vkvIJ3qUUD+rGRwJ2/hj+xT58Qle2MTql/2MGzkU+1JLAFuR6aJpLAjHwhmwwg== + dependencies: + "@aws-sdk/types" "^3.1.0" + "@aws-sdk/util-utf8-browser" "^3.0.0" + tslib "^1.11.1" + +"@aws-sdk/types@^3.1.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.709.0.tgz#f8d7ab07e253d3ed0e3b360e09fc67c7430a73b9" + integrity sha512-ArtLTMxgjf13Kfu3gWH3Ez9Q5TkDdcRZUofpKH3pMGB/C6KAbeSCtIIDKfoRTUABzyGlPyCrZdnFjKyH+ypIpg== + dependencies: + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + +"@aws-sdk/util-utf8-browser@^3.0.0": + version "3.259.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz#3275a6f5eb334f96ca76635b961d3c50259fd9ff" + integrity sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw== + dependencies: + tslib "^2.3.1" + "@babel/runtime@^7.21.0", "@babel/runtime@^7.25.0": version "7.26.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.0.tgz#8600c2f595f277c60815256418b85356a65173c1" @@ -14,6 +47,11 @@ dependencies: regenerator-runtime "^0.14.0" +"@bytecodealliance/preview2-shim@0.17.0": + version "0.17.0" + resolved "https://registry.yarnpkg.com/@bytecodealliance/preview2-shim/-/preview2-shim-0.17.0.tgz#9bc1cadbb9f86c446c6f579d3431c08a06a6672e" + integrity sha512-JorcEwe4ud0x5BS/Ar2aQWOQoFzjq/7jcnxYXCvSMh0oRm0dQXzOA+hqLDBnOMks1LLBA7dmiLLsEBl09Yd6iQ== + "@coral-xyz/anchor-errors@^0.30.1": version "0.30.1" resolved "https://registry.yarnpkg.com/@coral-xyz/anchor-errors/-/anchor-errors-0.30.1.tgz#bdfd3a353131345244546876eb4afc0e125bec30" @@ -1681,6 +1719,14 @@ deep-eql "^4.0.1" ordinal "^1.0.3" +"@nomicfoundation/hardhat-ethers@^3.0.8": + version "3.0.8" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-ethers/-/hardhat-ethers-3.0.8.tgz#af078f566373abeb77e11cbe69fe3dd47f8bfc27" + integrity sha512-zhOZ4hdRORls31DTOqg+GmEZM0ujly8GGIuRY7t7szEk2zW/arY1qDug/py8AEktT00v5K+b6RvbVog+va51IA== + dependencies: + debug "^4.1.1" + lodash.isequal "^4.5.0" + "@nomicfoundation/hardhat-foundry@^1.1.2": version "1.1.3" resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-foundry/-/hardhat-foundry-1.1.3.tgz#1b4f63c128e80f04aae22385dc9078ab9072794d" @@ -1700,6 +1746,28 @@ resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-toolbox/-/hardhat-toolbox-2.0.2.tgz#ec95f23b53cb4e71a1a7091380fa223aad18f156" integrity sha512-vnN1AzxbvpSx9pfdRHbUzTRIXpMLPXnUlkW855VaDk6N1pwRaQ2gNzEmFAABk4lWf11E00PKwFd/q27HuwYrYg== +"@nomicfoundation/hardhat-verify@^2.0.12": + version "2.0.12" + resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-verify/-/hardhat-verify-2.0.12.tgz#480819a245a2db0b127e473c62079f7b4f16daa8" + integrity sha512-Lg3Nu7DCXASQRVI/YysjuAX2z8jwOCbS0w5tz2HalWGSTZThqA0v9N0v0psHbKNqzPJa8bNOeapIVSziyJTnAg== + dependencies: + "@ethersproject/abi" "^5.1.2" + "@ethersproject/address" "^5.0.2" + cbor "^8.1.0" + debug "^4.1.1" + lodash.clonedeep "^4.5.0" + picocolors "^1.1.0" + semver "^6.3.0" + table "^6.8.0" + undici "^5.14.0" + +"@nomicfoundation/slang@^0.18.3": + version "0.18.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/slang/-/slang-0.18.3.tgz#976b6c3820081cebf050afbea434038aac9313cc" + integrity sha512-YqAWgckqbHM0/CZxi9Nlf4hjk9wUNLC9ngWCWBiqMxPIZmzsVKYuChdlrfeBPQyvQQBoOhbx+7C1005kLVQDZQ== + dependencies: + "@bytecodealliance/preview2-shim" "0.17.0" + "@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.2": version "0.1.2" resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.2.tgz#3a9c3b20d51360b20affb8f753e756d553d49557" @@ -1748,7 +1816,7 @@ "@nomicfoundation/solidity-analyzer-linux-x64-musl" "0.1.2" "@nomicfoundation/solidity-analyzer-win32-x64-msvc" "0.1.2" -"@nomiclabs/hardhat-ethers@^2.0.0", "@nomiclabs/hardhat-ethers@^2.2.3": +"@nomiclabs/hardhat-ethers@^2.2.3": version "2.2.3" resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.2.3.tgz#b41053e360c31a32c2640c9a45ee981a7e603fe0" integrity sha512-YhzPdzb612X591FOe68q+qXVXGG2ANZRvDo0RRUtimev85rCrAlv/TLMEZw5c+kq9AbzocLTVX/h2jVIFPL9Xg== @@ -1769,16 +1837,66 @@ table "^6.8.0" undici "^5.14.0" -"@openzeppelin/contracts-upgradeable@^5.0.2": +"@openzeppelin/contracts-upgradeable@^5.0.2", "@openzeppelin/contracts-upgradeable@^5.1.0": version "5.1.0" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-5.1.0.tgz#4d37648b7402929c53e2ff6e45749ecff91eb2b6" integrity sha512-AIElwP5Ck+cslNE+Hkemf5SxjJoF4wBvvjxc27Rp+9jaPs/CLIaUBMYe1FNzhdiN0cYuwGRmYaRHmmntuiju4Q== -"@openzeppelin/contracts@^5.0.2": +"@openzeppelin/contracts@^5.0.2", "@openzeppelin/contracts@^5.1.0": version "5.1.0" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-5.1.0.tgz#4e61162f2a2bf414c4e10c45eca98ce5f1aadbd4" integrity sha512-p1ULhl7BXzjjbha5aqst+QMLY+4/LCWADXOCsmLHRM77AqiPjnd9vvUN9sosUfhL9JGKpZ0TjEGxgvnizmWGSA== +"@openzeppelin/defender-base-client@^1.46.0": + version "1.54.6" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-base-client/-/defender-base-client-1.54.6.tgz#b65a90dba49375ac1439d638832382344067a0b9" + integrity sha512-PTef+rMxkM5VQ7sLwLKSjp2DBakYQd661ZJiSRywx+q/nIpm3B/HYGcz5wPZCA5O/QcEP6TatXXDoeMwimbcnw== + dependencies: + amazon-cognito-identity-js "^6.0.1" + async-retry "^1.3.3" + axios "^1.4.0" + lodash "^4.17.19" + node-fetch "^2.6.0" + +"@openzeppelin/hardhat-upgrades@1.28.0": + version "1.28.0" + resolved "https://registry.yarnpkg.com/@openzeppelin/hardhat-upgrades/-/hardhat-upgrades-1.28.0.tgz#6361f313a8a879d8a08a5e395acf0933bc190950" + integrity sha512-7sb/Jf+X+uIufOBnmHR0FJVWuxEs2lpxjJnLNN6eCJCP8nD0v+Ot5lTOW2Qb/GFnh+fLvJtEkhkowz4ZQ57+zQ== + dependencies: + "@openzeppelin/defender-base-client" "^1.46.0" + "@openzeppelin/platform-deploy-client" "^0.8.0" + "@openzeppelin/upgrades-core" "^1.27.0" + chalk "^4.1.0" + debug "^4.1.1" + proper-lockfile "^4.1.1" + +"@openzeppelin/platform-deploy-client@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@openzeppelin/platform-deploy-client/-/platform-deploy-client-0.8.0.tgz#af6596275a19c283d6145f0128cc1247d18223c1" + integrity sha512-POx3AsnKwKSV/ZLOU/gheksj0Lq7Is1q2F3pKmcFjGZiibf+4kjGxr4eSMrT+2qgKYZQH1ZLQZ+SkbguD8fTvA== + dependencies: + "@ethersproject/abi" "^5.6.3" + "@openzeppelin/defender-base-client" "^1.46.0" + axios "^0.21.2" + lodash "^4.17.19" + node-fetch "^2.6.0" + +"@openzeppelin/upgrades-core@^1.27.0": + version "1.41.0" + resolved "https://registry.yarnpkg.com/@openzeppelin/upgrades-core/-/upgrades-core-1.41.0.tgz#3a5e044cf53acd50c392f3297e7c37e4ff8f8355" + integrity sha512-+oryinqZnxkiZvg7bWqWX4Ki/CNwVUZEqC6Elpi5PQoahpL3/6Sq9xjIozD5AiI2O61h8JHQ+A//5NtczyavJw== + dependencies: + "@nomicfoundation/slang" "^0.18.3" + cbor "^9.0.0" + chalk "^4.1.0" + compare-versions "^6.0.0" + debug "^4.1.1" + ethereumjs-util "^7.0.3" + minimatch "^9.0.5" + minimist "^1.2.7" + proper-lockfile "^4.1.1" + solidity-ast "^0.4.51" + "@rtsao/scc@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" @@ -1908,6 +2026,13 @@ resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== +"@smithy/types@^3.7.2": + version "3.7.2" + resolved "https://registry.yarnpkg.com/@smithy/types/-/types-3.7.2.tgz#05cb14840ada6f966de1bf9a9c7dd86027343e10" + integrity sha512-bNwBYYmN8Eh9RyjS1p2gW6MIhSO2rl7X9QeLM8iTdcGRP+eDiIWDt66c9IysCc22gefKszZv+ubV9qZc7hdESg== + dependencies: + tslib "^2.6.2" + "@solana-developers/helpers@^2.4.0": version "2.5.6" resolved "https://registry.yarnpkg.com/@solana-developers/helpers/-/helpers-2.5.6.tgz#2af7613ea6848ce087c0dec7cf38e6f172abcbd4" @@ -2213,9 +2338,9 @@ "@types/node" "*" "@types/node@*", "@types/node@>=12.0.0", "@types/node@^22.5.5": - version "22.10.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.1.tgz#41ffeee127b8975a05f8c4f83fb89bcb2987d766" - integrity sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ== + version "22.10.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.2.tgz#a485426e6d1fdafc7b0d4c7b24e2c78182ddabb9" + integrity sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ== dependencies: undici-types "~6.20.0" @@ -2237,9 +2362,9 @@ integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== "@types/node@^20.10.7", "@types/node@^20.4.2": - version "20.17.9" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.17.9.tgz#5f141d4b7ee125cdee5faefe28de095398865bab" - integrity sha512-0JOXkRyLanfGPE2QRCwgxhzlBAvaRdCNMcvbd7jFfpmD4eEXll7LRwy5ymJmyeZqk7Nh7eD2LeUyQ68BbndmXw== + version "20.17.10" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.17.10.tgz#3f7166190aece19a0d1d364d75c8b0b5778c1e18" + integrity sha512-/jrvh5h6NXhEauFFexRin69nA0uHJ5gwk4iDivp/DeoEua3uwCUto6PC86IpRITBOs4+6i2I56K5x5b6WYGXHA== dependencies: undici-types "~6.19.2" @@ -2282,6 +2407,11 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== +"@types/validator@^13.12.2": + version "13.12.2" + resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.12.2.tgz#760329e756e18a4aab82fc502b51ebdfebbe49f5" + integrity sha512-6SlHBzUW8Jhf3liqrGGXyTJSIFe4nqlJ5A5KaMZ2l/vbM3Wh3KSybots/wfWVzNLK4D1NZluDlSQIbIEPx6oyA== + "@types/wrap-ansi@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz#18b97a972f94f60a679fd5c796d96421b9abb9fd" @@ -2605,6 +2735,17 @@ ajv@^8.0.1: json-schema-traverse "^1.0.0" require-from-string "^2.0.2" +amazon-cognito-identity-js@^6.0.1: + version "6.3.12" + resolved "https://registry.yarnpkg.com/amazon-cognito-identity-js/-/amazon-cognito-identity-js-6.3.12.tgz#af73df033094ad4c679c19cf6122b90058021619" + integrity sha512-s7NKDZgx336cp+oDeUtB2ZzT8jWJp/v2LWuYl+LQtMEODe22RF1IJ4nRiDATp+rp1pTffCZcm44Quw4jx2bqNg== + dependencies: + "@aws-crypto/sha256-js" "1.2.2" + buffer "4.9.2" + fast-base64-decode "^1.0.0" + isomorphic-unfetch "^3.0.0" + js-cookie "^2.2.1" + amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" @@ -2794,6 +2935,13 @@ astral-regex@^2.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== +async-retry@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.3.tgz#0e7f36c04d8478e7a58bdbed80cedf977785f280" + integrity sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw== + dependencies: + retry "0.13.1" + async@1.x: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" @@ -2825,6 +2973,13 @@ axios@1.7.4: form-data "^4.0.0" proxy-from-env "^1.1.0" +axios@^0.21.2: + version "0.21.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" + integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== + dependencies: + follow-redirects "^1.14.0" + axios@^1.3.6, axios@^1.4.0, axios@^1.5.1, axios@^1.6.1: version "1.7.9" resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.9.tgz#d7d071380c132a24accda1b2cfc1535b79ec650a" @@ -2856,7 +3011,7 @@ base-x@^5.0.0: resolved "https://registry.yarnpkg.com/base-x/-/base-x-5.0.0.tgz#6d835ceae379130e1a4cb846a70ac4746f28ea9b" integrity sha512-sMW3VGSX1QWVFA6l8U62MLKz29rRfpTlYdCqLdpLo1/Yd4zZwSbnUaDfciIAowAqvq7YFnWq9hrhdg1KYgc1lQ== -base64-js@^1.3.0, base64-js@^1.3.1: +base64-js@^1.0.2, base64-js@^1.3.0, base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== @@ -3068,6 +3223,15 @@ buffer-xor@^1.0.3: resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== +buffer@4.9.2: + version "4.9.2" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" + integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + buffer@6.0.3, buffer@^6.0.3, buffer@~6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" @@ -3136,6 +3300,13 @@ cbor@^8.1.0: dependencies: nofilter "^3.1.0" +cbor@^9.0.0: + version "9.0.2" + resolved "https://registry.yarnpkg.com/cbor/-/cbor-9.0.2.tgz#536b4f2d544411e70ec2b19a2453f10f83cd9fdb" + integrity sha512-JPypkxsB10s9QOWwa6zwPzqE1Md3vqpPc+cai4sAecuCsRyAtAl/pMyhPlMbT/xtPnm2dznJZYRLui57qiRhaQ== + dependencies: + nofilter "^3.1.0" + chai-as-promised@^7.1.1: version "7.1.2" resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-7.1.2.tgz#70cd73b74afd519754161386421fb71832c6d041" @@ -3371,6 +3542,11 @@ commander@^8.1.0: resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== +compare-versions@^6.0.0: + version "6.1.1" + resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-6.1.1.tgz#7af3cc1099ba37d244b3145a9af5201b629148a9" + integrity sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -4160,7 +4336,7 @@ ethereumjs-util@^6.0.0, ethereumjs-util@^6.2.1: ethjs-util "0.1.6" rlp "^2.2.3" -ethereumjs-util@^7.1.4: +ethereumjs-util@^7.0.3, ethereumjs-util@^7.1.4: version "7.1.5" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181" integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== @@ -4340,6 +4516,11 @@ eyes@^0.1.8: resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" integrity sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ== +fast-base64-decode@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz#b434a0dd7d92b12b43f26819300d2dafb83ee418" + integrity sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q== + fast-deep-equal@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" @@ -4463,7 +4644,7 @@ flatted@^3.2.9: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.2.tgz#adba1448a9841bec72b42c532ea23dbbedef1a27" integrity sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA== -follow-redirects@^1.12.1, follow-redirects@^1.15.6: +follow-redirects@^1.12.1, follow-redirects@^1.14.0, follow-redirects@^1.15.6: version "1.15.9" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== @@ -4974,7 +5155,7 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -ieee754@^1.1.13, ieee754@^1.2.1: +ieee754@^1.1.13, ieee754@^1.1.4, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -5266,16 +5447,16 @@ is-weakset@^2.0.3: call-bind "^1.0.7" get-intrinsic "^1.2.4" +isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + isarray@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== - isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -5289,6 +5470,14 @@ isomorphic-fetch@^3.0.0: node-fetch "^2.6.1" whatwg-fetch "^3.4.1" +isomorphic-unfetch@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz#87341d5f4f7b63843d468438128cb087b7c3e98f" + integrity sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q== + dependencies: + node-fetch "^2.6.1" + unfetch "^4.2.0" + isomorphic-ws@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" @@ -5323,6 +5512,11 @@ joi@^17.11.0: "@sideway/formula" "^3.0.1" "@sideway/pinpoint" "^2.0.0" +js-cookie@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" + integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ== + js-sha3@0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" @@ -5490,6 +5684,16 @@ lodash.camelcase@^4.3.0: resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== +lodash.clonedeep@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ== + +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" @@ -5500,7 +5704,7 @@ lodash.truncate@^4.4.2: resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== -lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.21: +lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -5615,7 +5819,14 @@ minimatch@^5.0.1, minimatch@^5.1.6: dependencies: brace-expansion "^2.0.1" -minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@^1.2.8: +minimatch@^9.0.5: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@^1.2.7, minimist@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -5720,7 +5931,7 @@ node-emoji@^1.10.0: dependencies: lodash "^4.17.21" -node-fetch@^2.6.1, node-fetch@^2.6.12, node-fetch@^2.7.0: +node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.12, node-fetch@^2.7.0: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== @@ -6030,6 +6241,15 @@ promise@^8.0.0: dependencies: asap "~2.0.6" +proper-lockfile@^4.1.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f" + integrity sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA== + dependencies: + graceful-fs "^4.2.4" + retry "^0.12.0" + signal-exit "^3.0.2" + proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" @@ -6234,6 +6454,16 @@ restore-cursor@^3.1.0: onetime "^5.1.0" signal-exit "^3.0.2" +retry@0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== + reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" @@ -6520,6 +6750,11 @@ solc@0.8.26: semver "^5.5.0" tmp "0.0.33" +solidity-ast@^0.4.51: + version "0.4.59" + resolved "https://registry.yarnpkg.com/solidity-ast/-/solidity-ast-0.4.59.tgz#290a2815aef70a61092591ab3e991da080ae5931" + integrity sha512-I+CX0wrYUN9jDfYtcgWSe+OAowaXy8/1YQy7NS4ni5IBDmIYBq7ZzaP/7QqouLjzZapmQtvGLqCaYgoUWqBo5g== + solidity-coverage@^0.8.0: version "0.8.14" resolved "https://registry.yarnpkg.com/solidity-coverage/-/solidity-coverage-0.8.14.tgz#db9bfcc10e3bc369fc074b35b267d665bcc6ae2e" @@ -6918,12 +7153,12 @@ tslib@2.7.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== -tslib@^1.8.1, tslib@^1.9.3: +tslib@^1.11.1, tslib@^1.8.1, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.3, tslib@^2.1.0, tslib@^2.8.0: +tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.1, tslib@^2.6.2, tslib@^2.8.0: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== @@ -7112,6 +7347,11 @@ undici@^5.14.0: dependencies: "@fastify/busboy" "^2.0.0" +unfetch@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be" + integrity sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA== + universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" @@ -7169,6 +7409,11 @@ v8-compile-cache-lib@^3.0.1: resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== +validator@^13.12.0: + version "13.12.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-13.12.0.tgz#7d78e76ba85504da3fee4fd1922b385914d4b35f" + integrity sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg== + varuint-bitcoin@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/varuint-bitcoin/-/varuint-bitcoin-1.1.2.tgz#e76c138249d06138b480d4c5b40ef53693e24e92" diff --git a/contracts/token/contracts/evm/UniversalToken.sol b/contracts/token/contracts/evm/UniversalToken.sol index 22c39df..9608be5 100644 --- a/contracts/token/contracts/evm/UniversalToken.sol +++ b/contracts/token/contracts/evm/UniversalToken.sol @@ -1,16 +1,33 @@ // SPDX-License-Identifier: MIT pragma solidity 0.8.26; -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import "@openzeppelin/contracts/access/Ownable2Step.sol"; import "@zetachain/protocol-contracts/contracts/evm/GatewayEVM.sol"; import {RevertContext} from "@zetachain/protocol-contracts/contracts/Revert.sol"; -import "../shared/Events.sol"; +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {ERC20BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol"; +import {ERC20PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PausableUpgradeable.sol"; +import {ERC20PermitUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {ERC20BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol"; -abstract contract UniversalToken is ERC20, Ownable2Step, Events { - GatewayEVM public immutable gateway; +import "../shared/UniversalTokenEvents.sol"; + +contract UniversalToken is + Initializable, + ERC20Upgradeable, + ERC20BurnableUpgradeable, + ERC20PausableUpgradeable, + OwnableUpgradeable, + ERC20PermitUpgradeable, + UUPSUpgradeable, + UniversalTokenEvents +{ + GatewayEVM public gateway; address public universal; - uint256 public immutable gasLimitAmount; + uint256 public gasLimitAmount; error InvalidAddress(); error Unauthorized(); @@ -22,19 +39,39 @@ abstract contract UniversalToken is ERC20, Ownable2Step, Events { _; } - function setUniversal(address contractAddress) external onlyOwner { - if (contractAddress == address(0)) revert InvalidAddress(); - universal = contractAddress; - emit SetUniversal(contractAddress); + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); } - constructor(address payable gatewayAddress, uint256 gas) { + function initialize( + address initialOwner, + string memory name, + string memory symbol, + address payable gatewayAddress, + uint256 gas + ) public initializer { + __ERC20_init(name, symbol); + __ERC20Burnable_init(); + __Ownable_init(initialOwner); + __UUPSUpgradeable_init(); if (gatewayAddress == address(0)) revert InvalidAddress(); gasLimitAmount = gas; gateway = GatewayEVM(gatewayAddress); } - function mint(address to, uint256 amount) public onlyOwner { + function setGasLimit(uint256 gas) external onlyOwner { + if (gas == 0) revert InvalidGasLimit(); + gasLimitAmount = gas; + } + + function setUniversal(address contractAddress) external onlyOwner { + if (contractAddress == address(0)) revert InvalidAddress(); + universal = contractAddress; + emit SetUniversal(contractAddress); + } + + function mint(address to, uint256 amount) public onlyOwner whenNotPaused { _mint(to, amount); } @@ -42,7 +79,7 @@ abstract contract UniversalToken is ERC20, Ownable2Step, Events { address destination, address receiver, uint256 amount - ) external payable { + ) external payable whenNotPaused { if (receiver == address(0)) revert InvalidAddress(); _burn(msg.sender, amount); @@ -105,7 +142,25 @@ abstract contract UniversalToken is ERC20, Ownable2Step, Events { emit TokenTransferReverted(receiver, amount); } - receive() external payable {} + function _authorizeUpgrade( + address newImplementation + ) internal override onlyOwner {} + + function pause() public onlyOwner { + _pause(); + } - fallback() external payable {} + function unpause() public onlyOwner { + _unpause(); + } + + function _update( + address from, + address to, + uint256 value + ) internal override(ERC20Upgradeable, ERC20PausableUpgradeable) { + super._update(from, to, value); + } + + receive() external payable {} } diff --git a/contracts/token/contracts/example/Connected.sol b/contracts/token/contracts/example/Connected.sol deleted file mode 100644 index 4918dd1..0000000 --- a/contracts/token/contracts/example/Connected.sol +++ /dev/null @@ -1,18 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.26; - -import "../evm/UniversalToken.sol"; - -contract Connected is UniversalToken { - constructor( - address payable gatewayAddress, - address owner, - string memory name, - string memory symbol, - uint256 gasLimit - ) - UniversalToken(gatewayAddress, gasLimit) - Ownable(owner) - ERC20(name, symbol) - {} -} diff --git a/contracts/token/contracts/example/EVMUniversalToken.sol b/contracts/token/contracts/example/EVMUniversalToken.sol new file mode 100644 index 0000000..80ae7b5 --- /dev/null +++ b/contracts/token/contracts/example/EVMUniversalToken.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import "../evm/UniversalToken.sol"; + +contract EVMUniversalToken is UniversalToken {} diff --git a/contracts/token/contracts/example/Universal.sol b/contracts/token/contracts/example/Universal.sol deleted file mode 100644 index d61ac77..0000000 --- a/contracts/token/contracts/example/Universal.sol +++ /dev/null @@ -1,19 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity 0.8.26; - -import "../zetachain/UniversalToken.sol"; - -contract Universal is UniversalToken { - constructor( - address payable gatewayAddress, - address owner, - string memory name, - string memory symbol, - uint256 gasLimit, - address uniswapRouter - ) - UniversalToken(gatewayAddress, gasLimit, uniswapRouter) - Ownable(owner) - ERC20(name, symbol) - {} -} diff --git a/contracts/token/contracts/example/ZetaChainUniversalToken.sol b/contracts/token/contracts/example/ZetaChainUniversalToken.sol new file mode 100644 index 0000000..c9b9abd --- /dev/null +++ b/contracts/token/contracts/example/ZetaChainUniversalToken.sol @@ -0,0 +1,6 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.26; + +import "../zetachain/UniversalToken.sol"; + +contract ZetaChainUniversalToken is UniversalToken {} diff --git a/contracts/token/contracts/shared/Events.sol b/contracts/token/contracts/shared/UniversalTokenEvents.sol similarity index 95% rename from contracts/token/contracts/shared/Events.sol rename to contracts/token/contracts/shared/UniversalTokenEvents.sol index cebb4ad..dd7a5f1 100644 --- a/contracts/token/contracts/shared/Events.sol +++ b/contracts/token/contracts/shared/UniversalTokenEvents.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.26; -contract Events { +contract UniversalTokenEvents { event SetUniversal(address indexed universalAddress); event SetConnected(address indexed zrc20, address contractAddress); event TokenMinted(address indexed to, uint256 amount); diff --git a/contracts/token/contracts/zetachain/UniversalToken.sol b/contracts/token/contracts/zetachain/UniversalToken.sol index c358bc7..b5ed54f 100644 --- a/contracts/token/contracts/zetachain/UniversalToken.sol +++ b/contracts/token/contracts/zetachain/UniversalToken.sol @@ -1,33 +1,47 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.26; -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; -import "@openzeppelin/contracts/access/Ownable2Step.sol"; import {RevertContext, RevertOptions} from "@zetachain/protocol-contracts/contracts/Revert.sol"; import "@zetachain/protocol-contracts/contracts/zevm/interfaces/UniversalContract.sol"; import "@zetachain/protocol-contracts/contracts/zevm/interfaces/IGatewayZEVM.sol"; import "@zetachain/protocol-contracts/contracts/zevm/GatewayZEVM.sol"; import {SwapHelperLib} from "@zetachain/toolkit/contracts/SwapHelperLib.sol"; -import {SystemContract} from "@zetachain/toolkit/contracts/SystemContract.sol"; -import "../shared/Events.sol"; - -abstract contract UniversalToken is - ERC20, - Ownable2Step, +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol"; +import {ERC20BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol"; +import {ERC20PausableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PausableUpgradeable.sol"; +import {ERC20PermitUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20PermitUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts-upgradeable/proxy/utils/UUPSUpgradeable.sol"; +import {Initializable} from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; +import {ERC20BurnableUpgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/extensions/ERC20BurnableUpgradeable.sol"; + +import "../shared/UniversalTokenEvents.sol"; + +contract UniversalToken is + Initializable, + ERC20Upgradeable, + ERC20BurnableUpgradeable, + ERC20PausableUpgradeable, + OwnableUpgradeable, + ERC20PermitUpgradeable, + UUPSUpgradeable, UniversalContract, - Events + UniversalTokenEvents { - GatewayZEVM public immutable gateway; - address public immutable uniswapRouter; - uint256 private _nextTokenId; bool public constant isUniversal = true; - uint256 public immutable gasLimitAmount; + + GatewayZEVM public gateway; + address public uniswapRouter; + uint256 private _nextTokenId; + uint256 public gasLimitAmount; error TransferFailed(); error Unauthorized(); error InvalidAddress(); error InvalidGasLimit(); error ApproveFailed(); + error ZeroMsgValue(); mapping(address => address) public connected; @@ -36,11 +50,23 @@ abstract contract UniversalToken is _; } - constructor( + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize( + address initialOwner, + string memory name, + string memory symbol, address payable gatewayAddress, uint256 gas, address uniswapRouterAddress - ) { + ) public initializer { + __ERC20_init(name, symbol); + __ERC20Burnable_init(); + __Ownable_init(initialOwner); + __UUPSUpgradeable_init(); if (gatewayAddress == address(0) || uniswapRouterAddress == address(0)) revert InvalidAddress(); if (gas == 0) revert InvalidGasLimit(); @@ -49,6 +75,11 @@ abstract contract UniversalToken is gasLimitAmount = gas; } + function setGasLimit(uint256 gas) external onlyOwner { + if (gas == 0) revert InvalidGasLimit(); + gasLimitAmount = gas; + } + function setConnected( address zrc20, address contractAddress @@ -61,7 +92,8 @@ abstract contract UniversalToken is address destination, address receiver, uint256 amount - ) public { + ) public payable whenNotPaused { + if (msg.value == 0) revert ZeroMsgValue(); if (receiver == address(0)) revert InvalidAddress(); _burn(msg.sender, amount); @@ -69,12 +101,27 @@ abstract contract UniversalToken is .withdrawGasFeeWithGasLimit(gasLimitAmount); if (destination != gasZRC20) revert InvalidAddress(); - if ( - !IZRC20(destination).transferFrom(msg.sender, address(this), gasFee) - ) revert TransferFailed(); - if (!IZRC20(destination).approve(address(gateway), gasFee)) { - revert ApproveFailed(); + address WZETA = gateway.zetaToken(); + + IWETH9(WZETA).deposit{value: msg.value}(); + IWETH9(WZETA).approve(uniswapRouter, msg.value); + + uint256 out = SwapHelperLib.swapTokensForExactTokens( + uniswapRouter, + WZETA, + gasFee, + gasZRC20, + msg.value + ); + + uint256 remaining = msg.value - out; + + if (remaining > 0) { + IWETH9(WZETA).withdraw(remaining); + (bool success, ) = msg.sender.call{value: remaining}(""); + if (!success) revert TransferFailed(); } + bytes memory message = abi.encode(receiver, amount, 0, msg.sender); CallOptions memory callOptions = CallOptions(gasLimitAmount, false); @@ -87,6 +134,7 @@ abstract contract UniversalToken is gasLimitAmount ); + IZRC20(gasZRC20).approve(address(gateway), gasFee); gateway.call( abi.encodePacked(connected[destination]), destination, @@ -97,7 +145,7 @@ abstract contract UniversalToken is emit TokenTransfer(destination, receiver, amount); } - function mint(address to, uint256 amount) public onlyOwner { + function mint(address to, uint256 amount) public onlyOwner whenNotPaused { _mint(to, amount); } @@ -156,4 +204,28 @@ abstract contract UniversalToken is _mint(sender, amount); emit TokenTransferReverted(sender, amount); } + + function pause() public onlyOwner { + _pause(); + } + + function unpause() public onlyOwner { + _unpause(); + } + + function _authorizeUpgrade( + address newImplementation + ) internal override onlyOwner {} + + receive() external payable {} + + // The following functions are overrides required by Solidity. + + function _update( + address from, + address to, + uint256 value + ) internal override(ERC20Upgradeable, ERC20PausableUpgradeable) { + super._update(from, to, value); + } } diff --git a/contracts/token/hardhat.config.ts b/contracts/token/hardhat.config.ts index cb20229..8a5cadd 100644 --- a/contracts/token/hardhat.config.ts +++ b/contracts/token/hardhat.config.ts @@ -1,8 +1,4 @@ -import "./tasks/deploy"; -import "./tasks/mint"; -import "./tasks/transfer"; -import "./tasks/universalSetConnected"; -import "./tasks/connectedSetUniversal"; +import "./tasks"; import "@zetachain/localnet/tasks"; import "@nomicfoundation/hardhat-toolbox"; import "@zetachain/toolkit/tasks"; @@ -10,11 +6,26 @@ import "@zetachain/toolkit/tasks"; import { getHardhatConfigNetworks } from "@zetachain/networks"; import { HardhatUserConfig } from "hardhat/config"; +import "@nomiclabs/hardhat-ethers"; +import "@openzeppelin/hardhat-upgrades"; + const config: HardhatUserConfig = { networks: { ...getHardhatConfigNetworks(), }, - solidity: "0.8.26", + solidity: { + compilers: [ + { + settings: { + optimizer: { + enabled: true, + runs: 1000, + }, + }, + version: "0.8.26", + }, + ], + }, }; export default config; diff --git a/contracts/token/package.json b/contracts/token/package.json index 84fec51..3931749 100644 --- a/contracts/token/package.json +++ b/contracts/token/package.json @@ -21,6 +21,7 @@ "@nomiclabs/hardhat-ethers": "^2.0.0", "@nomiclabs/hardhat-etherscan": "^3.0.0", "@typechain/ethers-v5": "^10.1.0", + "@openzeppelin/hardhat-upgrades": "1.28.0", "@typechain/hardhat": "^6.1.2", "@types/chai": "^4.2.0", "@types/mocha": ">=9.1.0", @@ -58,4 +59,4 @@ "@solana/web3.js": "^1.95.2", "@zetachain/protocol-contracts": "11.0.0-rc3" } -} +} \ No newline at end of file diff --git a/contracts/token/scripts/localnet.sh b/contracts/token/scripts/localnet.sh index dc82554..88d878e 100755 --- a/contracts/token/scripts/localnet.sh +++ b/contracts/token/scripts/localnet.sh @@ -1,6 +1,8 @@ #!/bin/bash set -e +set -x +set -o pipefail if [ "$1" = "start" ]; then npx hardhat localnet --exit-on-error & sleep 10; fi @@ -27,46 +29,46 @@ GATEWAY_BNB=$(jq -r '.addresses[] | select(.type=="gatewayEVM" and .chain=="bnb" UNISWAP_ROUTER=$(jq -r '.addresses[] | select(.type=="uniswapRouterInstance" and .chain=="zetachain") | .address' localnet.json) SENDER=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 -CONTRACT_ZETACHAIN=$(npx hardhat deploy --network localhost --gateway "$GATEWAY_ZETACHAIN" --uniswap-router "$UNISWAP_ROUTER" --json | jq -r '.contractAddress') +CONTRACT_ZETACHAIN=$(npx hardhat token:deploy --name ZetaChainUniversalToken --network localhost --gateway "$GATEWAY_ZETACHAIN" --uniswap-router "$UNISWAP_ROUTER" --json | jq -r '.contractAddress') echo -e "\nšŸš€ Deployed contract on ZetaChain: $CONTRACT_ZETACHAIN" -CONTRACT_ETHEREUM=$(npx hardhat deploy --name Connected --json --network localhost --gateway "$GATEWAY_ETHEREUM" | jq -r '.contractAddress') +CONTRACT_ETHEREUM=$(npx hardhat token:deploy --name EVMUniversalToken --json --network localhost --gateway "$GATEWAY_ETHEREUM" | jq -r '.contractAddress') echo -e "šŸš€ Deployed contract on EVM chain: $CONTRACT_ETHEREUM" -CONTRACT_BNB=$(npx hardhat deploy --name Connected --json --network localhost --gateway "$GATEWAY_BNB" | jq -r '.contractAddress') +CONTRACT_BNB=$(npx hardhat token:deploy --name EVMUniversalToken --json --network localhost --gateway "$GATEWAY_BNB" | jq -r '.contractAddress') echo -e "šŸš€ Deployed contract on BNB chain: $CONTRACT_BNB" echo -e "\nšŸ“® User Address: $SENDER" echo -e "\nšŸ”— Setting universal and connected contracts..." -npx hardhat connected-set-universal --network localhost --contract "$CONTRACT_ETHEREUM" --universal "$CONTRACT_ZETACHAIN" --json &>/dev/null -npx hardhat connected-set-universal --network localhost --contract "$CONTRACT_BNB" --universal "$CONTRACT_ZETACHAIN" --json &>/dev/null -npx hardhat universal-set-connected --network localhost --contract "$CONTRACT_ZETACHAIN" --connected "$CONTRACT_ETHEREUM" --zrc20 "$ZRC20_ETHEREUM" --json &>/dev/null -npx hardhat universal-set-connected --network localhost --contract "$CONTRACT_ZETACHAIN" --connected "$CONTRACT_BNB" --zrc20 "$ZRC20_BNB" --json &>/dev/null +npx hardhat token:set-universal --network localhost --contract "$CONTRACT_ETHEREUM" --universal "$CONTRACT_ZETACHAIN" --json &>/dev/null +npx hardhat token:set-universal --network localhost --contract "$CONTRACT_BNB" --universal "$CONTRACT_ZETACHAIN" --json &>/dev/null +npx hardhat token:set-connected --network localhost --contract "$CONTRACT_ZETACHAIN" --connected "$CONTRACT_ETHEREUM" --zrc20 "$ZRC20_ETHEREUM" --json &>/dev/null +npx hardhat token:set-connected --network localhost --contract "$CONTRACT_ZETACHAIN" --connected "$CONTRACT_BNB" --zrc20 "$ZRC20_BNB" --json &>/dev/null npx hardhat localnet-check balance -TOKEN=$(npx hardhat mint --network localhost --json --contract "$CONTRACT_ZETACHAIN" --to "$SENDER" --amount 10 | jq -r '.contractAddress') +TOKEN=$(npx hardhat token:mint --network localhost --json --contract "$CONTRACT_ZETACHAIN" --to "$SENDER" --amount 10 | jq -r '.contractAddress') echo -e "\nMinted tokens: $TOKEN on ZetaChain." npx hardhat localnet-check balance echo -e "\nTransferring token: ZetaChain ā†’ Ethereum..." -npx hardhat transfer --network localhost --json --amount 10 --from "$CONTRACT_ZETACHAIN" --to "$ZRC20_ETHEREUM" +npx hardhat token:transfer --network localhost --json --amount 10 --from "$CONTRACT_ZETACHAIN" --to "$ZRC20_ETHEREUM" --gas-amount 1 npx hardhat localnet-check balance echo -e "\nTransferring token: Ethereum ā†’ BNB..." -npx hardhat transfer --network localhost --json --amount 10 --from "$CONTRACT_ETHEREUM" --to "$ZRC20_BNB" --gas-amount 1 +npx hardhat token:transfer --network localhost --json --amount 10 --from "$CONTRACT_ETHEREUM" --to "$ZRC20_BNB" --gas-amount 1 npx hardhat localnet-check balance echo -e "\nTransferring token: BNB ā†’ ZetaChain..." -npx hardhat transfer --network localhost --json --amount 10 --from "$CONTRACT_BNB" +npx hardhat token:transfer --network localhost --json --amount 10 --from "$CONTRACT_BNB" npx hardhat localnet-check balance diff --git a/contracts/token/tasks/deploy.ts b/contracts/token/tasks/deploy.ts index 28db1d8..a8725bb 100644 --- a/contracts/token/tasks/deploy.ts +++ b/contracts/token/tasks/deploy.ts @@ -2,6 +2,8 @@ import { task, types } from "hardhat/config"; import { HardhatRuntimeEnvironment } from "hardhat/types"; const main = async (args: any, hre: HardhatRuntimeEnvironment) => { + const { isAddress } = hre.ethers.utils; + const network = hre.network.name; const [signer] = await hre.ethers.getSigners(); @@ -11,16 +13,23 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { ); } + if ( + !isAddress(args.gateway) || + (args.uniswapRouter && !isAddress(args.uniswapRouter)) + ) { + throw new Error("Invalid Ethereum address provided."); + } + const factory: any = await hre.ethers.getContractFactory(args.name); - const contract = await factory.deploy( - args.gateway, + + const contract = await hre.upgrades.deployProxy(factory, [ signer.address, args.tokenName, args.tokenSymbol, + args.gateway, args.gasLimit, - ...(args.uniswapRouter ? [args.uniswapRouter] : []) - ); - await contract.deployed(); + ...(args.uniswapRouter ? [args.uniswapRouter] : []), + ]); if (args.json) { console.log( @@ -38,11 +47,19 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { } }; -task("deploy", "Deploy the NFT contract", main) +export const tokenDeploy = task( + "token:deploy", + "Deploy a universal token contract", + main +) .addFlag("json", "Output the result in JSON format") .addOptionalParam("tokenName", "Token name", "Universal Token") .addOptionalParam("tokenSymbol", "Token symbol", "UFT") - .addOptionalParam("name", "The contract name to deploy", "Universal") + .addOptionalParam( + "name", + "The contract name to deploy", + "ZetaChainUniversalToken" + ) .addOptionalParam( "gasLimit", "Gas limit for the transaction", diff --git a/contracts/token/tasks/index.ts b/contracts/token/tasks/index.ts new file mode 100644 index 0000000..152d929 --- /dev/null +++ b/contracts/token/tasks/index.ts @@ -0,0 +1,5 @@ +export { tokenSetUniversal } from "./setUniversal"; +export { tokenMint } from "./mint"; +export { tokenTransfer } from "./transfer"; +export { tokenSetConnected } from "./setConnected"; +export { tokenDeploy } from "./deploy"; diff --git a/contracts/token/tasks/mint.ts b/contracts/token/tasks/mint.ts index 3276974..93b870f 100644 --- a/contracts/token/tasks/mint.ts +++ b/contracts/token/tasks/mint.ts @@ -2,6 +2,8 @@ import { task } from "hardhat/config"; import { HardhatRuntimeEnvironment } from "hardhat/types"; const main = async (args: any, hre: HardhatRuntimeEnvironment) => { + const { isAddress } = hre.ethers.utils; + const [signer] = await hre.ethers.getSigners(); if (signer === undefined) { throw new Error( @@ -9,6 +11,10 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { ); } + if (!isAddress(args.contract)) { + throw new Error("Invalid Ethereum address provided."); + } + const contract: any = await hre.ethers.getContractAt( args.name, args.contract @@ -17,12 +23,7 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { const recipient = args.to || signer.address; const tx = await contract.mint(recipient, args.amount); - const receipt = await tx.wait(); - - const transferEvent = receipt.events?.find( - (event: any) => event.event === "Transfer" - ); - const tokenId = transferEvent?.args?.tokenId; + await tx.wait(); if (args.json) { console.log( @@ -30,25 +31,26 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { contractAddress: args.contract, mintTransactionHash: tx.hash, recipient: recipient, - tokenURI: args.tokenUri, - tokenId: tokenId?.toString(), }) ); } else { console.log(`šŸš€ Successfully minted NFT. šŸ“œ Contract address: ${args.contract} šŸ‘¤ Recipient: ${recipient} -šŸ†” Token ID: ${tokenId?.toString()} šŸ”— Transaction hash: ${tx.hash}`); } }; -task("mint", "Mint an NFT", main) +export const tokenMint = task("token:mint", "Mint a universal token", main) .addParam("contract", "The address of the deployed NFT contract") .addOptionalParam( "to", "The recipient address, defaults to the signer address" ) .addParam("amount", "The amount of tokens to mint") - .addOptionalParam("name", "The contract name to interact with", "Universal") + .addOptionalParam( + "name", + "The contract name to interact with", + "ZetaChainUniversalToken" + ) .addFlag("json", "Output the result in JSON format"); diff --git a/contracts/token/tasks/universalSetConnected.ts b/contracts/token/tasks/setConnected.ts similarity index 71% rename from contracts/token/tasks/universalSetConnected.ts rename to contracts/token/tasks/setConnected.ts index b8de726..0cd02fc 100644 --- a/contracts/token/tasks/universalSetConnected.ts +++ b/contracts/token/tasks/setConnected.ts @@ -1,8 +1,10 @@ import { task } from "hardhat/config"; import { HardhatRuntimeEnvironment } from "hardhat/types"; -import { Universal } from "../typechain-types"; +import { ZetaChainUniversalToken } from "../typechain-types"; const main = async (args: any, hre: HardhatRuntimeEnvironment) => { + const { isAddress } = hre.ethers.utils; + const [signer] = await hre.ethers.getSigners(); if (!signer) { throw new Error( @@ -10,8 +12,16 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { ); } - const contract: Universal = await hre.ethers.getContractAt( - "Universal", + if ( + !isAddress(args.contract) || + !isAddress(args.zrc20) || + !isAddress(args.connected) + ) { + throw new Error("Invalid Ethereum address provided."); + } + + const contract: ZetaChainUniversalToken = await hre.ethers.getContractAt( + "ZetaChainUniversalToken", args.contract ); @@ -35,7 +45,11 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { } }; -task("universal-set-connected", "Sets the connected contract address", main) +export const tokenSetConnected = task( + "token:set-connected", + "Sets the connected contract address", + main +) .addParam("contract", "The address of the deployed contract") .addParam("zrc20", "The ZRC20 address to link to the connected contract") .addParam("connected", "The address of the connected contract to set") diff --git a/contracts/token/tasks/connectedSetUniversal.ts b/contracts/token/tasks/setUniversal.ts similarity index 70% rename from contracts/token/tasks/connectedSetUniversal.ts rename to contracts/token/tasks/setUniversal.ts index 0e5a2c4..ef24531 100644 --- a/contracts/token/tasks/connectedSetUniversal.ts +++ b/contracts/token/tasks/setUniversal.ts @@ -1,8 +1,10 @@ import { task } from "hardhat/config"; import { HardhatRuntimeEnvironment } from "hardhat/types"; -import { Connected } from "../typechain-types"; +import { EVMUniversalToken } from "../typechain-types"; const main = async (args: any, hre: HardhatRuntimeEnvironment) => { + const { isAddress } = hre.ethers.utils; + const [signer] = await hre.ethers.getSigners(); if (!signer) { throw new Error( @@ -10,8 +12,12 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { ); } - const contract: Connected = await hre.ethers.getContractAt( - "Connected", + if (!isAddress(args.contract) || !isAddress(args.universal)) { + throw new Error("Invalid Ethereum address provided."); + } + + const contract: EVMUniversalToken = await hre.ethers.getContractAt( + "EVMUniversalToken", args.contract ); @@ -32,7 +38,11 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { } }; -task("connected-set-universal", "Sets the universal contract address", main) +export const tokenSetUniversal = task( + "token:set-universal", + "Sets the universal contract address", + main +) .addParam("contract", "The address of the deployed contract") .addParam("universal", "The address of the universal contract to set") .addFlag("json", "Output the result in JSON format"); diff --git a/contracts/token/tasks/transfer.ts b/contracts/token/tasks/transfer.ts index c772461..80d9c70 100644 --- a/contracts/token/tasks/transfer.ts +++ b/contracts/token/tasks/transfer.ts @@ -1,39 +1,35 @@ import { task, types } from "hardhat/config"; import { HardhatRuntimeEnvironment } from "hardhat/types"; -import ZRC20ABI from "@zetachain/protocol-contracts/abi/ZRC20.sol/ZRC20.json"; const main = async (args: any, hre: HardhatRuntimeEnvironment) => { const { ethers } = hre; const [signer] = await ethers.getSigners(); - const value = ethers.utils.parseUnits(args.amount, 18); - const gasAmount = - args.gasAmount && ethers.utils.parseUnits(args.gasAmount, 18); + const { isAddress } = hre.ethers.utils; + + if (!isAddress(args.to) || !isAddress(args.revertAddress)) { + throw new Error("Invalid Ethereum address provided."); + } const txOptions = { gasPrice: args.txOptionsGasPrice, gasLimit: args.txOptionsGasLimit, }; - let tx; - let contract; - try { - contract = await ethers.getContractAt("Universal", args.from); - await (contract as any).isUniversal(); - const gasLimit = hre.ethers.BigNumber.from(args.txOptionsGasLimit); - const zrc20 = new ethers.Contract(args.to, ZRC20ABI.abi, signer); - const [, gasFee] = await zrc20.withdrawGasFeeWithGasLimit(gasLimit); - const zrc20TransferTx = await zrc20.approve(args.from, gasFee, txOptions); - await zrc20TransferTx.wait(); - const tokenApprove = await contract.approve(args.from, value); - await tokenApprove.wait(); - } catch (e) { - contract = await ethers.getContractAt("Connected", args.from); - } + const contract = await ethers.getContractAt( + "ZetaChainUniversalToken", + args.from + ); + + const value = ethers.utils.parseUnits(args.amount, 18); + const tokenApprove = await contract.approve(args.from, value); + await tokenApprove.wait(); + + const gasAmount = ethers.utils.parseUnits(args.gasAmount, 18); const receiver = args.receiver || signer.address; - tx = await (contract as any).transferCrossChain( + const tx = await (contract as any).transferCrossChain( args.to, receiver, args.amount, @@ -59,7 +55,11 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { } }; -task("transfer", "Transfer and lock an NFT", main) +export const tokenTransfer = task( + "token:transfer", + "Transfer and lock an NFT", + main +) .addParam("from", "The contract being transferred from") .addOptionalParam( "txOptionsGasPrice", @@ -94,5 +94,5 @@ task("transfer", "Transfer and lock an NFT", main) "ZRC-20 of the gas token of the destination chain", "0x0000000000000000000000000000000000000000" ) - .addOptionalParam("gasAmount", "The amount for gas") + .addParam("gasAmount", "The amount of gas to transfer", "0") .addParam("amount", "The amount of gas to transfer", "0"); diff --git a/contracts/token/yarn.lock b/contracts/token/yarn.lock index c23f5fa..820a341 100644 --- a/contracts/token/yarn.lock +++ b/contracts/token/yarn.lock @@ -7,6 +7,39 @@ resolved "https://registry.yarnpkg.com/@adraffy/ens-normalize/-/ens-normalize-1.10.1.tgz#63430d04bd8c5e74f8d7d049338f1cd9d4f02069" integrity sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw== +"@aws-crypto/sha256-js@1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-js/-/sha256-js-1.2.2.tgz#02acd1a1fda92896fc5a28ec7c6e164644ea32fc" + integrity sha512-Nr1QJIbW/afYYGzYvrF70LtaHrIRtd4TNAglX8BvlfxJLZ45SAmueIKYl5tWoNBPzp65ymXGFK0Bb1vZUpuc9g== + dependencies: + "@aws-crypto/util" "^1.2.2" + "@aws-sdk/types" "^3.1.0" + tslib "^1.11.1" + +"@aws-crypto/util@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@aws-crypto/util/-/util-1.2.2.tgz#b28f7897730eb6538b21c18bd4de22d0ea09003c" + integrity sha512-H8PjG5WJ4wz0UXAFXeJjWCW1vkvIJ3qUUD+rGRwJ2/hj+xT58Qle2MTql/2MGzkU+1JLAFuR6aJpLAjHwhmwwg== + dependencies: + "@aws-sdk/types" "^3.1.0" + "@aws-sdk/util-utf8-browser" "^3.0.0" + tslib "^1.11.1" + +"@aws-sdk/types@^3.1.0": + version "3.709.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.709.0.tgz#f8d7ab07e253d3ed0e3b360e09fc67c7430a73b9" + integrity sha512-ArtLTMxgjf13Kfu3gWH3Ez9Q5TkDdcRZUofpKH3pMGB/C6KAbeSCtIIDKfoRTUABzyGlPyCrZdnFjKyH+ypIpg== + dependencies: + "@smithy/types" "^3.7.2" + tslib "^2.6.2" + +"@aws-sdk/util-utf8-browser@^3.0.0": + version "3.259.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz#3275a6f5eb334f96ca76635b961d3c50259fd9ff" + integrity sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw== + dependencies: + tslib "^2.3.1" + "@babel/runtime@^7.21.0", "@babel/runtime@^7.25.0": version "7.26.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.26.0.tgz#8600c2f595f277c60815256418b85356a65173c1" @@ -14,6 +47,11 @@ dependencies: regenerator-runtime "^0.14.0" +"@bytecodealliance/preview2-shim@0.17.0": + version "0.17.0" + resolved "https://registry.yarnpkg.com/@bytecodealliance/preview2-shim/-/preview2-shim-0.17.0.tgz#9bc1cadbb9f86c446c6f579d3431c08a06a6672e" + integrity sha512-JorcEwe4ud0x5BS/Ar2aQWOQoFzjq/7jcnxYXCvSMh0oRm0dQXzOA+hqLDBnOMks1LLBA7dmiLLsEBl09Yd6iQ== + "@coral-xyz/anchor-errors@^0.30.1": version "0.30.1" resolved "https://registry.yarnpkg.com/@coral-xyz/anchor-errors/-/anchor-errors-0.30.1.tgz#bdfd3a353131345244546876eb4afc0e125bec30" @@ -1700,6 +1738,13 @@ resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-toolbox/-/hardhat-toolbox-2.0.2.tgz#ec95f23b53cb4e71a1a7091380fa223aad18f156" integrity sha512-vnN1AzxbvpSx9pfdRHbUzTRIXpMLPXnUlkW855VaDk6N1pwRaQ2gNzEmFAABk4lWf11E00PKwFd/q27HuwYrYg== +"@nomicfoundation/slang@^0.18.3": + version "0.18.3" + resolved "https://registry.yarnpkg.com/@nomicfoundation/slang/-/slang-0.18.3.tgz#976b6c3820081cebf050afbea434038aac9313cc" + integrity sha512-YqAWgckqbHM0/CZxi9Nlf4hjk9wUNLC9ngWCWBiqMxPIZmzsVKYuChdlrfeBPQyvQQBoOhbx+7C1005kLVQDZQ== + dependencies: + "@bytecodealliance/preview2-shim" "0.17.0" + "@nomicfoundation/solidity-analyzer-darwin-arm64@0.1.2": version "0.1.2" resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.2.tgz#3a9c3b20d51360b20affb8f753e756d553d49557" @@ -1779,6 +1824,56 @@ resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-5.1.0.tgz#4e61162f2a2bf414c4e10c45eca98ce5f1aadbd4" integrity sha512-p1ULhl7BXzjjbha5aqst+QMLY+4/LCWADXOCsmLHRM77AqiPjnd9vvUN9sosUfhL9JGKpZ0TjEGxgvnizmWGSA== +"@openzeppelin/defender-base-client@^1.46.0": + version "1.54.6" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-base-client/-/defender-base-client-1.54.6.tgz#b65a90dba49375ac1439d638832382344067a0b9" + integrity sha512-PTef+rMxkM5VQ7sLwLKSjp2DBakYQd661ZJiSRywx+q/nIpm3B/HYGcz5wPZCA5O/QcEP6TatXXDoeMwimbcnw== + dependencies: + amazon-cognito-identity-js "^6.0.1" + async-retry "^1.3.3" + axios "^1.4.0" + lodash "^4.17.19" + node-fetch "^2.6.0" + +"@openzeppelin/hardhat-upgrades@1.28.0": + version "1.28.0" + resolved "https://registry.yarnpkg.com/@openzeppelin/hardhat-upgrades/-/hardhat-upgrades-1.28.0.tgz#6361f313a8a879d8a08a5e395acf0933bc190950" + integrity sha512-7sb/Jf+X+uIufOBnmHR0FJVWuxEs2lpxjJnLNN6eCJCP8nD0v+Ot5lTOW2Qb/GFnh+fLvJtEkhkowz4ZQ57+zQ== + dependencies: + "@openzeppelin/defender-base-client" "^1.46.0" + "@openzeppelin/platform-deploy-client" "^0.8.0" + "@openzeppelin/upgrades-core" "^1.27.0" + chalk "^4.1.0" + debug "^4.1.1" + proper-lockfile "^4.1.1" + +"@openzeppelin/platform-deploy-client@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@openzeppelin/platform-deploy-client/-/platform-deploy-client-0.8.0.tgz#af6596275a19c283d6145f0128cc1247d18223c1" + integrity sha512-POx3AsnKwKSV/ZLOU/gheksj0Lq7Is1q2F3pKmcFjGZiibf+4kjGxr4eSMrT+2qgKYZQH1ZLQZ+SkbguD8fTvA== + dependencies: + "@ethersproject/abi" "^5.6.3" + "@openzeppelin/defender-base-client" "^1.46.0" + axios "^0.21.2" + lodash "^4.17.19" + node-fetch "^2.6.0" + +"@openzeppelin/upgrades-core@^1.27.0": + version "1.41.0" + resolved "https://registry.yarnpkg.com/@openzeppelin/upgrades-core/-/upgrades-core-1.41.0.tgz#3a5e044cf53acd50c392f3297e7c37e4ff8f8355" + integrity sha512-+oryinqZnxkiZvg7bWqWX4Ki/CNwVUZEqC6Elpi5PQoahpL3/6Sq9xjIozD5AiI2O61h8JHQ+A//5NtczyavJw== + dependencies: + "@nomicfoundation/slang" "^0.18.3" + cbor "^9.0.0" + chalk "^4.1.0" + compare-versions "^6.0.0" + debug "^4.1.1" + ethereumjs-util "^7.0.3" + minimatch "^9.0.5" + minimist "^1.2.7" + proper-lockfile "^4.1.1" + solidity-ast "^0.4.51" + "@rtsao/scc@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" @@ -1908,6 +2003,13 @@ resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== +"@smithy/types@^3.7.2": + version "3.7.2" + resolved "https://registry.yarnpkg.com/@smithy/types/-/types-3.7.2.tgz#05cb14840ada6f966de1bf9a9c7dd86027343e10" + integrity sha512-bNwBYYmN8Eh9RyjS1p2gW6MIhSO2rl7X9QeLM8iTdcGRP+eDiIWDt66c9IysCc22gefKszZv+ubV9qZc7hdESg== + dependencies: + tslib "^2.6.2" + "@solana-developers/helpers@^2.4.0": version "2.5.6" resolved "https://registry.yarnpkg.com/@solana-developers/helpers/-/helpers-2.5.6.tgz#2af7613ea6848ce087c0dec7cf38e6f172abcbd4" @@ -2605,6 +2707,17 @@ ajv@^8.0.1: json-schema-traverse "^1.0.0" require-from-string "^2.0.2" +amazon-cognito-identity-js@^6.0.1: + version "6.3.12" + resolved "https://registry.yarnpkg.com/amazon-cognito-identity-js/-/amazon-cognito-identity-js-6.3.12.tgz#af73df033094ad4c679c19cf6122b90058021619" + integrity sha512-s7NKDZgx336cp+oDeUtB2ZzT8jWJp/v2LWuYl+LQtMEODe22RF1IJ4nRiDATp+rp1pTffCZcm44Quw4jx2bqNg== + dependencies: + "@aws-crypto/sha256-js" "1.2.2" + buffer "4.9.2" + fast-base64-decode "^1.0.0" + isomorphic-unfetch "^3.0.0" + js-cookie "^2.2.1" + amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" @@ -2794,6 +2907,13 @@ astral-regex@^2.0.0: resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== +async-retry@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/async-retry/-/async-retry-1.3.3.tgz#0e7f36c04d8478e7a58bdbed80cedf977785f280" + integrity sha512-wfr/jstw9xNi/0teMHrRW7dsz3Lt5ARhYNZ2ewpadnhaIp5mbALhOAP+EAdsC7t4Z6wqsDVv9+W6gm1Dk9mEyw== + dependencies: + retry "0.13.1" + async@1.x: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" @@ -2825,6 +2945,13 @@ axios@1.7.4: form-data "^4.0.0" proxy-from-env "^1.1.0" +axios@^0.21.2: + version "0.21.4" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575" + integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== + dependencies: + follow-redirects "^1.14.0" + axios@^1.3.6, axios@^1.4.0, axios@^1.5.1, axios@^1.6.1: version "1.7.9" resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.9.tgz#d7d071380c132a24accda1b2cfc1535b79ec650a" @@ -2856,7 +2983,7 @@ base-x@^5.0.0: resolved "https://registry.yarnpkg.com/base-x/-/base-x-5.0.0.tgz#6d835ceae379130e1a4cb846a70ac4746f28ea9b" integrity sha512-sMW3VGSX1QWVFA6l8U62MLKz29rRfpTlYdCqLdpLo1/Yd4zZwSbnUaDfciIAowAqvq7YFnWq9hrhdg1KYgc1lQ== -base64-js@^1.3.0, base64-js@^1.3.1: +base64-js@^1.0.2, base64-js@^1.3.0, base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== @@ -3068,6 +3195,15 @@ buffer-xor@^1.0.3: resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== +buffer@4.9.2: + version "4.9.2" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.2.tgz#230ead344002988644841ab0244af8c44bbe3ef8" + integrity sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + buffer@6.0.3, buffer@^6.0.3, buffer@~6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" @@ -3136,6 +3272,13 @@ cbor@^8.1.0: dependencies: nofilter "^3.1.0" +cbor@^9.0.0: + version "9.0.2" + resolved "https://registry.yarnpkg.com/cbor/-/cbor-9.0.2.tgz#536b4f2d544411e70ec2b19a2453f10f83cd9fdb" + integrity sha512-JPypkxsB10s9QOWwa6zwPzqE1Md3vqpPc+cai4sAecuCsRyAtAl/pMyhPlMbT/xtPnm2dznJZYRLui57qiRhaQ== + dependencies: + nofilter "^3.1.0" + chai-as-promised@^7.1.1: version "7.1.2" resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-7.1.2.tgz#70cd73b74afd519754161386421fb71832c6d041" @@ -3371,6 +3514,11 @@ commander@^8.1.0: resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== +compare-versions@^6.0.0: + version "6.1.1" + resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-6.1.1.tgz#7af3cc1099ba37d244b3145a9af5201b629148a9" + integrity sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -4160,7 +4308,7 @@ ethereumjs-util@^6.0.0, ethereumjs-util@^6.2.1: ethjs-util "0.1.6" rlp "^2.2.3" -ethereumjs-util@^7.1.4: +ethereumjs-util@^7.0.3, ethereumjs-util@^7.1.4: version "7.1.5" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181" integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== @@ -4340,6 +4488,11 @@ eyes@^0.1.8: resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" integrity sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ== +fast-base64-decode@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz#b434a0dd7d92b12b43f26819300d2dafb83ee418" + integrity sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q== + fast-deep-equal@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" @@ -4463,7 +4616,7 @@ flatted@^3.2.9: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.2.tgz#adba1448a9841bec72b42c532ea23dbbedef1a27" integrity sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA== -follow-redirects@^1.12.1, follow-redirects@^1.15.6: +follow-redirects@^1.12.1, follow-redirects@^1.14.0, follow-redirects@^1.15.6: version "1.15.9" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== @@ -4974,7 +5127,7 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -ieee754@^1.1.13, ieee754@^1.2.1: +ieee754@^1.1.13, ieee754@^1.1.4, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -5266,16 +5419,16 @@ is-weakset@^2.0.3: call-bind "^1.0.7" get-intrinsic "^1.2.4" +isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + isarray@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== - isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -5289,6 +5442,14 @@ isomorphic-fetch@^3.0.0: node-fetch "^2.6.1" whatwg-fetch "^3.4.1" +isomorphic-unfetch@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/isomorphic-unfetch/-/isomorphic-unfetch-3.1.0.tgz#87341d5f4f7b63843d468438128cb087b7c3e98f" + integrity sha512-geDJjpoZ8N0kWexiwkX8F9NkTsXhetLPVbZFQ+JTW239QNOwvB0gniuR1Wc6f0AMTn7/mFGyXvHTifrCp/GH8Q== + dependencies: + node-fetch "^2.6.1" + unfetch "^4.2.0" + isomorphic-ws@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" @@ -5323,6 +5484,11 @@ joi@^17.11.0: "@sideway/formula" "^3.0.1" "@sideway/pinpoint" "^2.0.0" +js-cookie@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8" + integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ== + js-sha3@0.5.7: version "0.5.7" resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" @@ -5500,7 +5666,7 @@ lodash.truncate@^4.4.2: resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== -lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.21: +lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -5615,7 +5781,14 @@ minimatch@^5.0.1, minimatch@^5.1.6: dependencies: brace-expansion "^2.0.1" -minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@^1.2.8: +minimatch@^9.0.5: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6, minimist@^1.2.7, minimist@^1.2.8: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -5720,7 +5893,7 @@ node-emoji@^1.10.0: dependencies: lodash "^4.17.21" -node-fetch@^2.6.1, node-fetch@^2.6.12, node-fetch@^2.7.0: +node-fetch@^2.6.0, node-fetch@^2.6.1, node-fetch@^2.6.12, node-fetch@^2.7.0: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== @@ -6030,6 +6203,15 @@ promise@^8.0.0: dependencies: asap "~2.0.6" +proper-lockfile@^4.1.1: + version "4.1.2" + resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f" + integrity sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA== + dependencies: + graceful-fs "^4.2.4" + retry "^0.12.0" + signal-exit "^3.0.2" + proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" @@ -6234,6 +6416,16 @@ restore-cursor@^3.1.0: onetime "^5.1.0" signal-exit "^3.0.2" +retry@0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + +retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== + reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" @@ -6520,6 +6712,11 @@ solc@0.8.26: semver "^5.5.0" tmp "0.0.33" +solidity-ast@^0.4.51: + version "0.4.59" + resolved "https://registry.yarnpkg.com/solidity-ast/-/solidity-ast-0.4.59.tgz#290a2815aef70a61092591ab3e991da080ae5931" + integrity sha512-I+CX0wrYUN9jDfYtcgWSe+OAowaXy8/1YQy7NS4ni5IBDmIYBq7ZzaP/7QqouLjzZapmQtvGLqCaYgoUWqBo5g== + solidity-coverage@^0.8.0: version "0.8.14" resolved "https://registry.yarnpkg.com/solidity-coverage/-/solidity-coverage-0.8.14.tgz#db9bfcc10e3bc369fc074b35b267d665bcc6ae2e" @@ -6918,12 +7115,12 @@ tslib@2.7.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== -tslib@^1.8.1, tslib@^1.9.3: +tslib@^1.11.1, tslib@^1.8.1, tslib@^1.9.3: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.3, tslib@^2.1.0, tslib@^2.8.0: +tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.1, tslib@^2.6.2, tslib@^2.8.0: version "2.8.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== @@ -7112,6 +7309,11 @@ undici@^5.14.0: dependencies: "@fastify/busboy" "^2.0.0" +unfetch@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be" + integrity sha512-F9p7yYCn6cIW9El1zi0HI6vqpeIvBsr3dSuRO6Xuppb1u5rXpCPmMvLSyECLhybr9isec8Ohl0hPekMVrEinDA== + universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"