From 560abc168d4d78289851a6310a07bfa3b9df91cd Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Mon, 2 Dec 2024 16:02:00 +0300 Subject: [PATCH 01/18] upgradeable wip --- contracts/nft/contracts/evm/UniversalNFT.sol | 75 +++++++++++++------ contracts/nft/contracts/example/Connected.sol | 22 +++--- contracts/nft/contracts/example/Universal.sol | 15 +--- .../nft/contracts/zetachain/UniversalNFT.sol | 68 ++++++++++++----- contracts/nft/hardhat.config.ts | 12 ++- contracts/nft/package.json | 2 + contracts/nft/scripts/localnet.sh | 52 +++++++------ contracts/nft/tasks/connectedSetUniversal.ts | 4 +- contracts/nft/tasks/deploy.ts | 25 ++++--- contracts/nft/tasks/initialize.ts | 57 ++++++++++++++ contracts/nft/yarn.lock | 10 +++ 11 files changed, 238 insertions(+), 104 deletions(-) create mode 100644 contracts/nft/tasks/initialize.ts diff --git a/contracts/nft/contracts/evm/UniversalNFT.sol b/contracts/nft/contracts/evm/UniversalNFT.sol index a07d694..356f5e5 100644 --- a/contracts/nft/contracts/evm/UniversalNFT.sol +++ b/contracts/nft/contracts/evm/UniversalNFT.sol @@ -2,49 +2,69 @@ 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 {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 "../shared/Events.sol"; abstract contract UniversalNFT is - ERC721, - ERC721Enumerable, - ERC721URIStorage, - Ownable2Step, + Initializable, + ERC721Upgradeable, + ERC721EnumerableUpgradeable, + ERC721URIStorageUpgradeable, + ERC721BurnableUpgradeable, + OwnableUpgradeable, Events { - 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); if (gatewayAddress == address(0)) revert InvalidAddress(); if (gas == 0) revert InvalidGasLimit(); gasLimitAmount = gas; gateway = GatewayEVM(gatewayAddress); } + 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 onlyOwner { uint256 hash = uint256( keccak256( @@ -144,20 +164,29 @@ abstract contract UniversalNFT is address to, uint256 tokenId, address auth - ) internal override(ERC721, ERC721Enumerable) returns (address) { + ) + internal + override(ERC721Upgradeable, ERC721EnumerableUpgradeable) + 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,7 +195,11 @@ abstract contract UniversalNFT is ) public view - override(ERC721, ERC721Enumerable, ERC721URIStorage) + override( + ERC721Upgradeable, + ERC721EnumerableUpgradeable, + ERC721URIStorageUpgradeable + ) returns (bool) { return super.supportsInterface(interfaceId); diff --git a/contracts/nft/contracts/example/Connected.sol b/contracts/nft/contracts/example/Connected.sol index bd5f92c..58b4aa1 100644 --- a/contracts/nft/contracts/example/Connected.sol +++ b/contracts/nft/contracts/example/Connected.sol @@ -4,15 +4,15 @@ 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) - {} + // 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/Universal.sol b/contracts/nft/contracts/example/Universal.sol index 11ff979..e3a358b 100644 --- a/contracts/nft/contracts/example/Universal.sol +++ b/contracts/nft/contracts/example/Universal.sol @@ -3,17 +3,4 @@ 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) - {} -} +contract Universal is UniversalNFT {} diff --git a/contracts/nft/contracts/zetachain/UniversalNFT.sol b/contracts/nft/contracts/zetachain/UniversalNFT.sol index 181f031..1c1622f 100644 --- a/contracts/nft/contracts/zetachain/UniversalNFT.sol +++ b/contracts/nft/contracts/zetachain/UniversalNFT.sol @@ -1,32 +1,36 @@ // 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/GatewayZEVM.sol"; import {SwapHelperLib} from "@zetachain/toolkit/contracts/SwapHelperLib.sol"; import {SystemContract} from "@zetachain/toolkit/contracts/SystemContract.sol"; +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 "../shared/Events.sol"; -abstract contract UniversalNFT is - ERC721, - ERC721Enumerable, - ERC721URIStorage, - Ownable2Step, +contract UniversalNFT is + Initializable, + ERC721Upgradeable, + ERC721EnumerableUpgradeable, + ERC721URIStorageUpgradeable, + ERC721BurnableUpgradeable, + OwnableUpgradeable, UniversalContract, Events { - 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(); @@ -41,11 +45,24 @@ 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(); + __ERC721Burnable_init(); + __Ownable_init(initialOwner); if (gatewayAddress == address(0) || uniswapRouterAddress == address(0)) revert InvalidAddress(); if (gas == 0) revert InvalidGasLimit(); @@ -193,20 +210,29 @@ abstract contract UniversalNFT is address to, uint256 tokenId, address auth - ) internal override(ERC721, ERC721Enumerable) returns (address) { + ) + internal + override(ERC721Upgradeable, ERC721EnumerableUpgradeable) + 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,7 +241,11 @@ abstract contract UniversalNFT is ) public view - override(ERC721, ERC721Enumerable, ERC721URIStorage) + override( + ERC721Upgradeable, + ERC721EnumerableUpgradeable, + ERC721URIStorageUpgradeable + ) returns (bool) { return super.supportsInterface(interfaceId); diff --git a/contracts/nft/hardhat.config.ts b/contracts/nft/hardhat.config.ts index 38cc713..7be788a 100644 --- a/contracts/nft/hardhat.config.ts +++ b/contracts/nft/hardhat.config.ts @@ -1,7 +1,7 @@ import "./tasks/deploy"; -import "./tasks/deploy"; import "./tasks/mint"; import "./tasks/transfer"; +import "./tasks/initialize"; import "./tasks/universalSetConnected"; import "./tasks/connectedSetUniversal"; import "@zetachain/localnet/tasks"; @@ -15,7 +15,15 @@ const config: HardhatUserConfig = { networks: { ...getHardhatConfigNetworks(), }, - solidity: "0.8.26", + solidity: { + version: "0.8.26", + settings: { + optimizer: { + enabled: true, + runs: 200, + }, + }, + }, }; export default config; diff --git a/contracts/nft/package.json b/contracts/nft/package.json index 84fec51..32d2b4e 100644 --- a/contracts/nft/package.json +++ b/contracts/nft/package.json @@ -53,6 +53,8 @@ "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", diff --git a/contracts/nft/scripts/localnet.sh b/contracts/nft/scripts/localnet.sh index e546d97..3bc048a 100755 --- a/contracts/nft/scripts/localnet.sh +++ b/contracts/nft/scripts/localnet.sh @@ -27,7 +27,7 @@ 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 deploy --network localhost --name contracts/zetachain/UniversalNFT.sol:UniversalNFT --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') @@ -38,37 +38,41 @@ 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 initialize --network localhost --name contracts/zetachain/UniversalNFT.sol:UniversalNFT --contract "$CONTRACT_ZETACHAIN" --gateway "$GATEWAY_ZETACHAIN" --uniswap-router "$UNISWAP_ROUTER" --json +# npx hardhat initialize --network localhost --name Connected --contract "$CONTRACT_ETHEREUM" --gateway "$GATEWAY_ZETACHAIN" --json +# npx hardhat initialize --network localhost --name Connected --contract "$CONTRACT_BNB" --gateway "$GATEWAY_ZETACHAIN" --json -npx hardhat localnet-check -balance +# 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 -NFT_ID=$(npx hardhat 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 -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') +# echo -e "\nMinted NFT with ID: $NFT_ID on ZetaChain." -echo -e "\nTransferring NFT: ZetaChain ā†’ Ethereum..." -npx hardhat transfer --network localhost --json --token-id "$NFT_ID" --from "$CONTRACT_ZETACHAIN" --to "$ZRC20_ETHEREUM" +# npx hardhat localnet-check +# balance -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" -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 localnet-check +# balance -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 -echo -e "\nTransferring NFT: BNB ā†’ ZetaChain..." -npx hardhat transfer --network localhost --json --token-id "$NFT_ID" --from "$CONTRACT_BNB" +# npx hardhat localnet-check +# balance -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 localnet-check +# balance if [ "$1" = "start" ]; then npx hardhat localnet-stop; fi \ No newline at end of file diff --git a/contracts/nft/tasks/connectedSetUniversal.ts b/contracts/nft/tasks/connectedSetUniversal.ts index fb28783..6a08235 100644 --- a/contracts/nft/tasks/connectedSetUniversal.ts +++ b/contracts/nft/tasks/connectedSetUniversal.ts @@ -15,7 +15,9 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { 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) { diff --git a/contracts/nft/tasks/deploy.ts b/contracts/nft/tasks/deploy.ts index 845098d..d603dfd 100644 --- a/contracts/nft/tasks/deploy.ts +++ b/contracts/nft/tasks/deploy.ts @@ -13,17 +13,18 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { const factory: any = await hre.ethers.getContractFactory(args.name); - const contract = await factory.deploy( - args.gateway, - signer.address, - args.tokenName, - args.tokenSymbol, - args.gasLimit, - ...(args.uniswapRouter ? [args.uniswapRouter] : []), - { - gasPrice: args.deployGasPrice, - } - ); + const contract = await factory + .deploy + // args.gateway, + // signer.address, + // args.tokenName, + // args.tokenSymbol, + // args.gasLimit, + // ...(args.uniswapRouter ? [args.uniswapRouter] : []), + // { + // gasPrice: args.deployGasPrice, + // } + (); await contract.deployed(); @@ -51,7 +52,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/initialize.ts b/contracts/nft/tasks/initialize.ts new file mode 100644 index 0000000..6e69a77 --- /dev/null +++ b/contracts/nft/tasks/initialize.ts @@ -0,0 +1,57 @@ +import { task, types } from "hardhat/config"; +import { HardhatRuntimeEnvironment } from "hardhat/types"; + +const main = async (args: any, hre: HardhatRuntimeEnvironment) => { + const network = hre.network.name; + + const [signer] = await hre.ethers.getSigners(); + if (signer === undefined) { + throw new Error( + `Wallet not found. Please, run "npx hardhat account --save" or set PRIVATE_KEY env variable (for example, in a .env file)` + ); + } + + const contract: any = await hre.ethers.getContractAt( + args.name, + args.contract + ); + + const tx = await contract.initialize( + signer.address, + args.tokenName, + args.tokenSymbol, + args.gateway, + args.gasLimit, + ...(args.uniswapRouter ? [args.uniswapRouter] : []), + { + gasLimit: args.initializeGasLimit, + } + ); + + await tx.wait(); +}; + +task("initialize", "Initialize the NFT contract", main) + .addOptionalParam("name", "The contract name to deploy", "Universal") + .addFlag("json", "Output the result in JSON format") + .addParam("contract", "The address of the deployed contract") + .addOptionalParam("tokenName", "NFT name", "Universal NFT") + .addOptionalParam("tokenSymbol", "NFT symbol", "UNFT") + .addOptionalParam( + "gasLimit", + "Gas limit for the transaction", + 1000000, + types.int + ) + .addOptionalParam( + "gateway", + "Gateway address (default: ZetaChain Gateway)", + "0x6c533f7fe93fae114d0954697069df33c9b74fd7" + ) + .addOptionalParam( + "initializeGasLimit", + "Gas limit for initialize transaction", + 10000000, + types.int + ) + .addOptionalParam("uniswapRouter", "Uniswap v2 Router address"); diff --git a/contracts/nft/yarn.lock b/contracts/nft/yarn.lock index 14f8715..317d4f2 100644 --- a/contracts/nft/yarn.lock +++ b/contracts/nft/yarn.lock @@ -2010,11 +2010,21 @@ resolved "https://registry.yarnpkg.com/@openzeppelin/contracts-upgradeable/-/contracts-upgradeable-5.0.2.tgz#3e5321a2ecdd0b206064356798c21225b6ec7105" integrity sha512-0MmkHSHiW2NRFiT9/r5Lu4eJq5UJ4/tzlOgYXNAIj/ONkQTVnz22pLxDvp4C4uZ9he7ZFvGn3Driptn1/iU7tQ== +"@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": version "5.0.2" resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-5.0.2.tgz#b1d03075e49290d06570b2fd42154d76c2a5d210" integrity sha512-ytPc6eLGcHHnapAZ9S+5qsdomhjo6QBHTDRRBFfTxXIpsicMhVPouPgmUPebZZZGX7vt9USA+Z+0M0dSVtSUEA== +"@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== + "@scure/base@~1.1.0": version "1.1.1" resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938" From 9cbb94df3d7bf0f14a3e62a986530e73632d203d Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Tue, 3 Dec 2024 11:26:10 +0300 Subject: [PATCH 02/18] wip --- contracts/nft/contracts/example/Universal.sol | 33 +++++++++++++++++-- contracts/nft/hardhat.config.ts | 6 ---- contracts/nft/scripts/localnet.sh | 4 +-- contracts/nft/tasks/initialize.ts | 10 +++--- 4 files changed, 37 insertions(+), 16 deletions(-) diff --git a/contracts/nft/contracts/example/Universal.sol b/contracts/nft/contracts/example/Universal.sol index e3a358b..b015fa5 100644 --- a/contracts/nft/contracts/example/Universal.sol +++ b/contracts/nft/contracts/example/Universal.sol @@ -1,6 +1,33 @@ // SPDX-License-Identifier: MIT -pragma solidity 0.8.26; +// Compatible with OpenZeppelin Contracts ^5.0.0 +pragma solidity ^0.8.22; -import "../zetachain/UniversalNFT.sol"; +import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.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"; -contract Universal is UniversalNFT {} +contract Universal is + Initializable, + ERC20Upgradeable, + ERC20PermitUpgradeable, + OwnableUpgradeable, + UUPSUpgradeable +{ + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } + + function initialize(address initialOwner) public initializer { + __ERC20_init("UniversalNFT", "MTK"); + __ERC20Permit_init("UniversalNFT"); + __Ownable_init(initialOwner); + __UUPSUpgradeable_init(); + } + + function _authorizeUpgrade( + address newImplementation + ) internal override onlyOwner {} +} diff --git a/contracts/nft/hardhat.config.ts b/contracts/nft/hardhat.config.ts index 7be788a..9e21202 100644 --- a/contracts/nft/hardhat.config.ts +++ b/contracts/nft/hardhat.config.ts @@ -17,12 +17,6 @@ const config: HardhatUserConfig = { }, solidity: { version: "0.8.26", - settings: { - optimizer: { - enabled: true, - runs: 200, - }, - }, }, }; diff --git a/contracts/nft/scripts/localnet.sh b/contracts/nft/scripts/localnet.sh index 3bc048a..f1afc81 100755 --- a/contracts/nft/scripts/localnet.sh +++ b/contracts/nft/scripts/localnet.sh @@ -27,7 +27,7 @@ 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 --name contracts/zetachain/UniversalNFT.sol:UniversalNFT --json | jq -r '.contractAddress') +CONTRACT_ZETACHAIN=$(npx hardhat deploy --network localhost --name Universal --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') @@ -38,7 +38,7 @@ echo -e "šŸš€ Deployed NFT contract on BNB chain: $CONTRACT_BNB" echo -e "\nšŸ“® User Address: $SENDER" -npx hardhat initialize --network localhost --name contracts/zetachain/UniversalNFT.sol:UniversalNFT --contract "$CONTRACT_ZETACHAIN" --gateway "$GATEWAY_ZETACHAIN" --uniswap-router "$UNISWAP_ROUTER" --json +npx hardhat initialize --network localhost --name Universal --contract "$CONTRACT_ZETACHAIN" --gateway "$GATEWAY_ZETACHAIN" --uniswap-router "$UNISWAP_ROUTER" --json # npx hardhat initialize --network localhost --name Connected --contract "$CONTRACT_ETHEREUM" --gateway "$GATEWAY_ZETACHAIN" --json # npx hardhat initialize --network localhost --name Connected --contract "$CONTRACT_BNB" --gateway "$GATEWAY_ZETACHAIN" --json diff --git a/contracts/nft/tasks/initialize.ts b/contracts/nft/tasks/initialize.ts index 6e69a77..70df691 100644 --- a/contracts/nft/tasks/initialize.ts +++ b/contracts/nft/tasks/initialize.ts @@ -18,11 +18,11 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { const tx = await contract.initialize( signer.address, - args.tokenName, - args.tokenSymbol, - args.gateway, - args.gasLimit, - ...(args.uniswapRouter ? [args.uniswapRouter] : []), + // args.tokenName, + // args.tokenSymbol, + // args.gateway, + // args.gasLimit, + // ...(args.uniswapRouter ? [args.uniswapRouter] : []), { gasLimit: args.initializeGasLimit, } From 6b8e43c5bc13fbb3bcca6af5bfc53894cb69ac45 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Tue, 3 Dec 2024 14:24:24 +0300 Subject: [PATCH 03/18] wip --- contracts/nft/contracts/example/Universal.sol | 30 +- contracts/nft/hardhat.config.ts | 3 + contracts/nft/package.json | 7 +- contracts/nft/scripts/localnet.sh | 16 +- contracts/nft/tasks/deploy.ts | 39 +-- contracts/nft/yarn.lock | 308 +++++++++++++++++- 6 files changed, 325 insertions(+), 78 deletions(-) diff --git a/contracts/nft/contracts/example/Universal.sol b/contracts/nft/contracts/example/Universal.sol index b015fa5..72db12c 100644 --- a/contracts/nft/contracts/example/Universal.sol +++ b/contracts/nft/contracts/example/Universal.sol @@ -2,32 +2,6 @@ // Compatible with OpenZeppelin Contracts ^5.0.0 pragma solidity ^0.8.22; -import {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.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 "../zetachain/UniversalNFT.sol"; -contract Universal is - Initializable, - ERC20Upgradeable, - ERC20PermitUpgradeable, - OwnableUpgradeable, - UUPSUpgradeable -{ - /// @custom:oz-upgrades-unsafe-allow constructor - constructor() { - _disableInitializers(); - } - - function initialize(address initialOwner) public initializer { - __ERC20_init("UniversalNFT", "MTK"); - __ERC20Permit_init("UniversalNFT"); - __Ownable_init(initialOwner); - __UUPSUpgradeable_init(); - } - - function _authorizeUpgrade( - address newImplementation - ) internal override onlyOwner {} -} +contract Universal is UniversalNFT {} diff --git a/contracts/nft/hardhat.config.ts b/contracts/nft/hardhat.config.ts index 9e21202..a52ccc6 100644 --- a/contracts/nft/hardhat.config.ts +++ b/contracts/nft/hardhat.config.ts @@ -11,6 +11,9 @@ 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(), diff --git a/contracts/nft/package.json b/contracts/nft/package.json index 32d2b4e..8e8f751 100644 --- a/contracts/nft/package.json +++ b/contracts/nft/package.json @@ -15,11 +15,14 @@ "@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": "^3.6.0", "@typechain/ethers-v5": "^10.1.0", "@typechain/hardhat": "^6.1.2", "@types/chai": "^4.2.0", @@ -41,7 +44,7 @@ "eslint-plugin-simple-import-sort": "^10.0.0", "eslint-plugin-sort-keys-fix": "^1.1.2", "eslint-plugin-typescript-sort-keys": "^2.3.0", - "ethers": "^5.4.7", + "ethers": "^6.13.4", "hardhat": "^2.17.2", "hardhat-gas-reporter": "^1.0.8", "prettier": "^2.8.8", diff --git a/contracts/nft/scripts/localnet.sh b/contracts/nft/scripts/localnet.sh index f1afc81..09ad691 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,18 +29,18 @@ 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 --name Universal --json | jq -r '.contractAddress') +CONTRACT_ZETACHAIN=$(npx hardhat deploy --network localhost --name Universal --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') -echo -e "šŸš€ Deployed NFT contract on Ethereum: $CONTRACT_ETHEREUM" +# CONTRACT_ETHEREUM=$(npx hardhat deploy --name Connected --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') -echo -e "šŸš€ Deployed NFT contract on BNB chain: $CONTRACT_BNB" +# CONTRACT_BNB=$(npx hardhat deploy --name Connected --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šŸ“® User Address: $SENDER" -npx hardhat initialize --network localhost --name Universal --contract "$CONTRACT_ZETACHAIN" --gateway "$GATEWAY_ZETACHAIN" --uniswap-router "$UNISWAP_ROUTER" --json +# npx hardhat initialize --network localhost --name Universal --contract "$CONTRACT_ZETACHAIN" --gateway "$GATEWAY_ZETACHAIN" --uniswap-router "$UNISWAP_ROUTER" --json # npx hardhat initialize --network localhost --name Connected --contract "$CONTRACT_ETHEREUM" --gateway "$GATEWAY_ZETACHAIN" --json # npx hardhat initialize --network localhost --name Connected --contract "$CONTRACT_BNB" --gateway "$GATEWAY_ZETACHAIN" --json diff --git a/contracts/nft/tasks/deploy.ts b/contracts/nft/tasks/deploy.ts index d603dfd..91b6145 100644 --- a/contracts/nft/tasks/deploy.ts +++ b/contracts/nft/tasks/deploy.ts @@ -13,35 +13,16 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { const factory: any = await hre.ethers.getContractFactory(args.name); - const contract = await factory - .deploy - // args.gateway, - // signer.address, - // args.tokenName, - // args.tokenSymbol, - // args.gasLimit, - // ...(args.uniswapRouter ? [args.uniswapRouter] : []), - // { - // gasPrice: args.deployGasPrice, - // } - (); - - await contract.deployed(); - - if (args.json) { - console.log( - JSON.stringify({ - 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}`); - } + // const contract = await factory.deploy({ gasLimit: 200000 }); + const res = await hre.upgrades.deployProxy(factory, [ + signer.address, + args.tokenName, + args.tokenSymbol, + args.gateway, + args.gasLimit, + ...(args.uniswapRouter ? [args.uniswapRouter] : []), + ]); + console.log(res); }; task("deploy", "Deploy the NFT contract", main) diff --git a/contracts/nft/yarn.lock b/contracts/nft/yarn.lock index 317d4f2..32b2f29 100644 --- a/contracts/nft/yarn.lock +++ b/contracts/nft/yarn.lock @@ -12,6 +12,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.696.0" + resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.696.0.tgz#559c3df74dc389b6f40ba6ec6daffeab155330cd" + integrity sha512-9rTvUJIAj5d3//U5FDPWGJ1nFJLuWb30vugGOrWk7aNZ6y9tuA3PI7Cc9dP8WEXKVyK1vuuk8rSFP2iqXnlgrw== + dependencies: + "@smithy/types" "^3.7.1" + 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.24.8": version "7.25.0" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.0.tgz#3af9a91c1b739c569d5d80cc917280919c544ecb" @@ -26,6 +59,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== + "@chainsafe/as-sha256@^0.3.1": version "0.3.1" resolved "https://registry.yarnpkg.com/@chainsafe/as-sha256/-/as-sha256-0.3.1.tgz#3639df0e1435cab03f4d9870cc3ac079e57a6fc9" @@ -1899,6 +1937,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.2" resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-foundry/-/hardhat-foundry-1.1.2.tgz#4f5aaa1803b8f5d974dcbc361beb72d49c815562" @@ -1918,6 +1964,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.1": version "0.1.1" resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.1.tgz#4c858096b1c17fe58a474fe81b46815f93645c15" @@ -1984,7 +2052,7 @@ "@nomicfoundation/solidity-analyzer-win32-ia32-msvc" "0.1.1" "@nomicfoundation/solidity-analyzer-win32-x64-msvc" "0.1.1" -"@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== @@ -2025,6 +2093,63 @@ resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-5.1.0.tgz#4e61162f2a2bf414c4e10c45eca98ce5f1aadbd4" integrity sha512-p1ULhl7BXzjjbha5aqst+QMLY+4/LCWADXOCsmLHRM77AqiPjnd9vvUN9sosUfhL9JGKpZ0TjEGxgvnizmWGSA== +"@openzeppelin/defender-sdk-base-client@^1.14.4", "@openzeppelin/defender-sdk-base-client@^1.15.2": + version "1.15.2" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-base-client/-/defender-sdk-base-client-1.15.2.tgz#aae7ec001365968b81ccce087f39a6eb52fa13f9" + integrity sha512-N3ZTeH8TXyklL7yNPMLUv0dxQwT78DTkOEDhzMS2/QE2FxbXrclSseoeeXxl6UYI61RBtZKn+okbSsbwiB5QWQ== + dependencies: + amazon-cognito-identity-js "^6.3.6" + async-retry "^1.3.3" + +"@openzeppelin/defender-sdk-deploy-client@^1.14.4": + version "1.15.2" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-deploy-client/-/defender-sdk-deploy-client-1.15.2.tgz#3b1d953aa66b6cdee13e7e672a488af2e2acf974" + integrity sha512-zspzMqh+OC8arXAkgBqTUDVO+NfCkt54UrsmQHbA3UAjr5TiDXKycBKU5ORb01hE+2gAmoPwEpDW9uS2VLg33A== + dependencies: + "@openzeppelin/defender-sdk-base-client" "^1.15.2" + axios "^1.7.2" + lodash "^4.17.21" + +"@openzeppelin/defender-sdk-network-client@^1.14.4": + version "1.15.2" + resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-network-client/-/defender-sdk-network-client-1.15.2.tgz#7178836d9861272ad509d93dea8739a5c4bf86c1" + integrity sha512-9r9pegc1aR7xzP9fmj1zvkk0OXMRJE10JabxxiJzAQQgmNXDeTGI6W5bFgrNJfxzcImNGqddJ3K4weKdLyL21A== + dependencies: + "@openzeppelin/defender-sdk-base-client" "^1.15.2" + axios "^1.7.2" + lodash "^4.17.21" + +"@openzeppelin/hardhat-upgrades@^3.6.0": + version "3.6.0" + resolved "https://registry.yarnpkg.com/@openzeppelin/hardhat-upgrades/-/hardhat-upgrades-3.6.0.tgz#8a252d6015b21ade1f5151816b6bc7b12348df53" + integrity sha512-RuVuCciCfFOqCyKSJ2D4Zffp3hxhvXTn16JzTlD9cx3A7V/2d3JA75tpRHD7RVPic+dcSFIf+BZRWOHuhc2ayg== + dependencies: + "@openzeppelin/defender-sdk-base-client" "^1.14.4" + "@openzeppelin/defender-sdk-deploy-client" "^1.14.4" + "@openzeppelin/defender-sdk-network-client" "^1.14.4" + "@openzeppelin/upgrades-core" "^1.41.0" + chalk "^4.1.0" + debug "^4.1.1" + ethereumjs-util "^7.1.5" + proper-lockfile "^4.1.1" + undici "^6.11.1" + +"@openzeppelin/upgrades-core@^1.41.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" + "@scure/base@~1.1.0": version "1.1.1" resolved "https://registry.yarnpkg.com/@scure/base/-/base-1.1.1.tgz#ebb651ee52ff84f420097055f4bf46cfba403938" @@ -2149,6 +2274,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.1": + version "3.7.1" + resolved "https://registry.yarnpkg.com/@smithy/types/-/types-3.7.1.tgz#4af54c4e28351e9101996785a33f2fdbf93debe7" + integrity sha512-XKLcLXZY7sUQgvvWyeaL/qwNPp6V3dWcUjqrQKjSb+tzYiCy340R/c64LV5j+Tnb2GhmunEX0eou+L+m2hJNYA== + dependencies: + tslib "^2.6.2" + "@solana-developers/helpers@^2.4.0": version "2.4.0" resolved "https://registry.yarnpkg.com/@solana-developers/helpers/-/helpers-2.4.0.tgz#0589899ec08173e11a5c4e799e5eccbda400e801" @@ -2542,6 +2674,13 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469" integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q== +"@types/node@22.7.5": + version "22.7.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b" + integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ== + dependencies: + undici-types "~6.19.2" + "@types/node@^10.0.3": version "10.17.60" resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" @@ -2940,6 +3079,17 @@ ajv@^8.0.1: require-from-string "^2.0.2" uri-js "^4.2.2" +amazon-cognito-identity-js@^6.3.6: + 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" @@ -3158,6 +3308,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" @@ -3215,6 +3372,15 @@ axios@^1.6.1: form-data "^4.0.0" proxy-from-env "^1.1.0" +axios@^1.7.2: + version "1.7.8" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.8.tgz#1997b1496b394c21953e68c14aaa51b7b5de3d6e" + integrity sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -3237,7 +3403,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== @@ -3471,6 +3637,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" @@ -3544,6 +3719,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.1" resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-7.1.1.tgz#08645d825deb8696ee61725dbf590c012eb00ca0" @@ -3815,6 +3997,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" @@ -4585,7 +4772,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, ethereumjs-util@^7.1.5: version "7.1.5" resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz#9ecf04861e4fbbeed7465ece5f23317ad1129181" integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== @@ -4668,7 +4855,7 @@ ethers@5.6.8: "@ethersproject/web" "5.6.1" "@ethersproject/wordlists" "5.6.1" -ethers@5.7.2, ethers@^5.4.7, ethers@^5.7.1: +ethers@5.7.2, ethers@^5.7.1: version "5.7.2" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== @@ -4732,6 +4919,19 @@ ethers@^6.13.2: tslib "2.4.0" ws "8.17.1" +ethers@^6.13.4: + version "6.13.4" + resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.13.4.tgz#bd3e1c3dc1e7dc8ce10f9ffb4ee40967a651b53c" + integrity sha512-21YtnZVg4/zKkCQPjrDj38B1r4nQvTZLopUGMLQ1ePU2zV/joCfDC3t3iKQjWRzjjjbzR+mdAIoikeBRNkdllA== + dependencies: + "@adraffy/ens-normalize" "1.10.1" + "@noble/curves" "1.2.0" + "@noble/hashes" "1.3.2" + "@types/node" "22.7.5" + aes-js "4.0.0-beta.5" + tslib "2.7.0" + ws "8.17.1" + ethjs-unit@0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" @@ -4795,6 +4995,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" @@ -5624,7 +5829,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== @@ -5863,16 +6068,16 @@ is-weakref@^1.0.2: dependencies: call-bind "^1.0.2" +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" @@ -5886,6 +6091,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" @@ -5925,6 +6138,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-sdsl@^4.1.4: version "4.4.2" resolved "https://registry.yarnpkg.com/js-sdsl/-/js-sdsl-4.4.2.tgz#2e3c031b1f47d3aca8b775532e3ebb0818e7f847" @@ -6154,6 +6372,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" @@ -6321,7 +6549,14 @@ minimatch@5.0.1: 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== @@ -6847,6 +7082,11 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== +picocolors@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" @@ -6891,6 +7131,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" @@ -7139,6 +7388,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" @@ -7453,6 +7712,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.4" resolved "https://registry.yarnpkg.com/solidity-coverage/-/solidity-coverage-0.8.4.tgz#c57a21979f5e86859c5198de9fbae2d3bc6324a5" @@ -7887,7 +8151,12 @@ tslib@2.4.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== -tslib@^1.8.1, tslib@^1.9.3: +tslib@2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" + integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== + +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== @@ -7897,6 +8166,11 @@ tslib@^2.0.3, tslib@^2.1.0, tslib@^2.4.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== +tslib@^2.3.1, tslib@^2.6.2: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + tsort@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/tsort/-/tsort-0.0.1.tgz#e2280f5e817f8bf4275657fd0f9aebd44f5a2786" @@ -8082,6 +8356,16 @@ undici@^5.14.0: dependencies: "@fastify/busboy" "^2.0.0" +undici@^6.11.1: + version "6.21.0" + resolved "https://registry.yarnpkg.com/undici/-/undici-6.21.0.tgz#4b3d3afaef984e07b48e7620c34ed8a285ed4cd4" + integrity sha512-BUgJXc752Kou3oOIuU1i+yZZypyZRqNPW0vqoMPl8VaoalSfeR0D8/t4iAS3yirs79SSMTxTag+ZC86uswv+Cw== + +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" From 76b927b3bd62ef28ff9f40725eb3262270f09536 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Tue, 3 Dec 2024 18:08:29 +0300 Subject: [PATCH 04/18] wip --- .../nft/contracts/zetachain/UniversalNFT.sol | 3 ++ contracts/nft/hardhat.config.ts | 12 ++++++- contracts/nft/scripts/localnet.sh | 32 +++++++++---------- contracts/nft/tasks/deploy.ts | 18 +++++++++-- contracts/nft/tasks/mint.ts | 5 +-- 5 files changed, 48 insertions(+), 22 deletions(-) diff --git a/contracts/nft/contracts/zetachain/UniversalNFT.sol b/contracts/nft/contracts/zetachain/UniversalNFT.sol index 1c1622f..b846769 100644 --- a/contracts/nft/contracts/zetachain/UniversalNFT.sol +++ b/contracts/nft/contracts/zetachain/UniversalNFT.sol @@ -126,6 +126,8 @@ contract UniversalNFT is emit TokenTransfer(receiver, destination, tokenId, uri); } + event Mint(address to, uint256 tokenId, string uri); + function safeMint(address to, string memory uri) public onlyOwner { uint256 hash = uint256( keccak256( @@ -137,6 +139,7 @@ contract UniversalNFT is _safeMint(to, tokenId); _setTokenURI(tokenId, uri); + emit Mint(to, tokenId, uri); } function onCall( diff --git a/contracts/nft/hardhat.config.ts b/contracts/nft/hardhat.config.ts index a52ccc6..bc4af21 100644 --- a/contracts/nft/hardhat.config.ts +++ b/contracts/nft/hardhat.config.ts @@ -19,7 +19,17 @@ const config: HardhatUserConfig = { ...getHardhatConfigNetworks(), }, solidity: { - version: "0.8.26", + compilers: [ + { + settings: { + optimizer: { + enabled: true, + runs: 1000, + }, + }, + version: "0.8.26", + }, + ], }, }; diff --git a/contracts/nft/scripts/localnet.sh b/contracts/nft/scripts/localnet.sh index 09ad691..9711d66 100755 --- a/contracts/nft/scripts/localnet.sh +++ b/contracts/nft/scripts/localnet.sh @@ -32,32 +32,32 @@ SENDER=0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 CONTRACT_ZETACHAIN=$(npx hardhat deploy --network localhost --name Universal --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') -# echo -e "šŸš€ Deployed NFT contract on Ethereum: $CONTRACT_ETHEREUM" +CONTRACT_ETHEREUM=$(npx hardhat deploy --name Connected --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') -# echo -e "šŸš€ Deployed NFT contract on BNB chain: $CONTRACT_BNB" +CONTRACT_BNB=$(npx hardhat deploy --name Connected --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šŸ“® User Address: $SENDER" # npx hardhat initialize --network localhost --name Universal --contract "$CONTRACT_ZETACHAIN" --gateway "$GATEWAY_ZETACHAIN" --uniswap-router "$UNISWAP_ROUTER" --json # npx hardhat initialize --network localhost --name Connected --contract "$CONTRACT_ETHEREUM" --gateway "$GATEWAY_ZETACHAIN" --json # npx hardhat initialize --network localhost --name Connected --contract "$CONTRACT_BNB" --gateway "$GATEWAY_ZETACHAIN" --json -# 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 +echo -e "\nšŸ”— Setting universal and connected contracts..." +npx hardhat connected-set-universal --network localhost --contract "$CONTRACT_ETHEREUM" --universal "$CONTRACT_ZETACHAIN" --json +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 localnet-check -# balance +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') -# echo -e "\nMinted NFT with ID: $NFT_ID on ZetaChain." +NFT_ID=$(npx hardhat mint --network localhost --json --contract "$CONTRACT_ZETACHAIN" --token-uri https://example.com/nft/metadata/1) +echo -e "\nMinted NFT with ID: $NFT_ID on ZetaChain." -# npx hardhat localnet-check -# balance +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" diff --git a/contracts/nft/tasks/deploy.ts b/contracts/nft/tasks/deploy.ts index 91b6145..9e94168 100644 --- a/contracts/nft/tasks/deploy.ts +++ b/contracts/nft/tasks/deploy.ts @@ -13,8 +13,7 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { const factory: any = await hre.ethers.getContractFactory(args.name); - // const contract = await factory.deploy({ gasLimit: 200000 }); - const res = await hre.upgrades.deployProxy(factory, [ + const contract = await hre.upgrades.deployProxy(factory, [ signer.address, args.tokenName, args.tokenSymbol, @@ -22,7 +21,20 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { args.gasLimit, ...(args.uniswapRouter ? [args.uniswapRouter] : []), ]); - console.log(res); + + if (args.json) { + console.log( + JSON.stringify({ + contractAddress: contract.target, + deployer: signer.address, + network: network, + }) + ); + } else { + console.log(`šŸš€ Successfully deployed "${args.name}" contract on ${network}. +šŸ“œ Contract address: ${contract.target} +`); + } }; task("deploy", "Deploy the NFT contract", main) diff --git a/contracts/nft/tasks/mint.ts b/contracts/nft/tasks/mint.ts index 7806e3d..320eb21 100644 --- a/contracts/nft/tasks/mint.ts +++ b/contracts/nft/tasks/mint.ts @@ -19,11 +19,12 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { const tx = await contract.safeMint(recipient, args.tokenUri); const receipt = await tx.wait(); + console.log(receipt); + const transferEvent = receipt.events?.find( - (event: any) => event.event === "Transfer" + (event: any) => event.event === "Mint" ); const tokenId = transferEvent?.args?.tokenId; - if (args.json) { console.log( JSON.stringify({ From 76ecec6f260eef8516be183dbce97f768d6002b8 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Tue, 3 Dec 2024 21:00:54 +0300 Subject: [PATCH 05/18] wip --- .../nft/contracts/zetachain/UniversalNFT.sol | 3 --- contracts/nft/scripts/localnet.sh | 10 ++++----- contracts/nft/tasks/mint.ts | 22 +++++++++++++------ contracts/nft/tasks/transfer.ts | 6 ++--- 4 files changed, 22 insertions(+), 19 deletions(-) diff --git a/contracts/nft/contracts/zetachain/UniversalNFT.sol b/contracts/nft/contracts/zetachain/UniversalNFT.sol index b846769..1c1622f 100644 --- a/contracts/nft/contracts/zetachain/UniversalNFT.sol +++ b/contracts/nft/contracts/zetachain/UniversalNFT.sol @@ -126,8 +126,6 @@ contract UniversalNFT is emit TokenTransfer(receiver, destination, tokenId, uri); } - event Mint(address to, uint256 tokenId, string uri); - function safeMint(address to, string memory uri) public onlyOwner { uint256 hash = uint256( keccak256( @@ -139,7 +137,6 @@ contract UniversalNFT is _safeMint(to, tokenId); _setTokenURI(tokenId, uri); - emit Mint(to, tokenId, uri); } function onCall( diff --git a/contracts/nft/scripts/localnet.sh b/contracts/nft/scripts/localnet.sh index 9711d66..fe85a44 100755 --- a/contracts/nft/scripts/localnet.sh +++ b/contracts/nft/scripts/localnet.sh @@ -53,17 +53,17 @@ npx hardhat universal-set-connected --network localhost --contract "$CONTRACT_ZE npx hardhat localnet-check balance -NFT_ID=$(npx hardhat mint --network localhost --json --contract "$CONTRACT_ZETACHAIN" --token-uri https://example.com/nft/metadata/1) +NFT_ID=$(npx hardhat 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" +echo -e "\nTransferring NFT: ZetaChain ā†’ Ethereum..." +npx hardhat transfer --network localhost --json --token-id "$NFT_ID" --from "$CONTRACT_ZETACHAIN" --to "$ZRC20_ETHEREUM" --gas-amount 0.1 -# npx hardhat localnet-check -# balance +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 diff --git a/contracts/nft/tasks/mint.ts b/contracts/nft/tasks/mint.ts index 320eb21..517354a 100644 --- a/contracts/nft/tasks/mint.ts +++ b/contracts/nft/tasks/mint.ts @@ -19,12 +19,19 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { const tx = await contract.safeMint(recipient, args.tokenUri); const receipt = await tx.wait(); - console.log(receipt); + // Decode logs using contract interface + const transferEvent = receipt.logs + .map((log: any) => { + try { + return contract.interface.parseLog(log); + } catch { + return null; + } + }) + .find((parsedLog: any) => parsedLog?.name === "Transfer"); + + const tokenId = transferEvent?.args?.tokenId?.toString(); - const transferEvent = receipt.events?.find( - (event: any) => event.event === "Mint" - ); - const tokenId = transferEvent?.args?.tokenId; if (args.json) { console.log( JSON.stringify({ @@ -32,14 +39,15 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { mintTransactionHash: tx.hash, recipient: recipient, tokenURI: args.tokenUri, - tokenId: tokenId?.toString(), + tokenId: tokenId, }) ); } else { console.log(`šŸš€ Successfully minted NFT. šŸ“œ Contract address: ${args.contract} šŸ‘¤ Recipient: ${recipient} -šŸ†” Token ID: ${tokenId?.toString()} +šŸ†” Token ID: ${tokenId} +šŸ”— Metadata URI: ${metadataUri} šŸ”— Transaction hash: ${tx.hash}`); } }; diff --git a/contracts/nft/tasks/transfer.ts b/contracts/nft/tasks/transfer.ts index 1ecb9b5..7d2c9bd 100644 --- a/contracts/nft/tasks/transfer.ts +++ b/contracts/nft/tasks/transfer.ts @@ -30,13 +30,11 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { contract = await ethers.getContractAt("Connected", args.from); } - const gasAmount = ethers.utils.parseUnits(args.gasAmount, 18); + // 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, - }); + tx = await contract.transferCrossChain(args.tokenId, receiver, args.to); await tx.wait(); if (args.json) { From 7b75695990cbbbff53c08fa46d1e159c9940e511 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Wed, 11 Dec 2024 19:40:35 +0300 Subject: [PATCH 06/18] NFT works --- contracts/nft/contracts/evm/UniversalNFT.sol | 9 +- contracts/nft/contracts/example/Connected.sol | 14 +- .../nft/contracts/zetachain/UniversalNFT.sol | 9 +- contracts/nft/package.json | 6 +- contracts/nft/scripts/localnet.sh | 28 ++-- contracts/nft/tasks/deploy.ts | 2 +- contracts/nft/tasks/transfer.ts | 11 +- contracts/nft/yarn.lock | 120 +++++++----------- 8 files changed, 83 insertions(+), 116 deletions(-) diff --git a/contracts/nft/contracts/evm/UniversalNFT.sol b/contracts/nft/contracts/evm/UniversalNFT.sol index 356f5e5..6f68cae 100644 --- a/contracts/nft/contracts/evm/UniversalNFT.sol +++ b/contracts/nft/contracts/evm/UniversalNFT.sol @@ -10,16 +10,18 @@ import {ERC721EnumerableUpgradeable} from "@openzeppelin/contracts-upgradeable/t 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 "../shared/Events.sol"; -abstract contract UniversalNFT is +contract UniversalNFT is Initializable, ERC721Upgradeable, ERC721EnumerableUpgradeable, ERC721URIStorageUpgradeable, ERC721BurnableUpgradeable, OwnableUpgradeable, + UUPSUpgradeable, Events { GatewayEVM public gateway; @@ -53,6 +55,7 @@ abstract contract UniversalNFT is __ERC721Enumerable_init(); __ERC721URIStorage_init(); __Ownable_init(initialOwner); + __UUPSUpgradeable_init(); if (gatewayAddress == address(0)) revert InvalidAddress(); if (gas == 0) revert InvalidGasLimit(); gasLimitAmount = gas; @@ -204,4 +207,8 @@ abstract contract UniversalNFT is { return super.supportsInterface(interfaceId); } + + function _authorizeUpgrade( + address newImplementation + ) internal override onlyOwner {} } diff --git a/contracts/nft/contracts/example/Connected.sol b/contracts/nft/contracts/example/Connected.sol index 58b4aa1..21a7fef 100644 --- a/contracts/nft/contracts/example/Connected.sol +++ b/contracts/nft/contracts/example/Connected.sol @@ -3,16 +3,4 @@ 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) - // {} -} +contract Connected is UniversalNFT {} diff --git a/contracts/nft/contracts/zetachain/UniversalNFT.sol b/contracts/nft/contracts/zetachain/UniversalNFT.sol index 1c1622f..81a102d 100644 --- a/contracts/nft/contracts/zetachain/UniversalNFT.sol +++ b/contracts/nft/contracts/zetachain/UniversalNFT.sol @@ -13,6 +13,7 @@ import {ERC721EnumerableUpgradeable} from "@openzeppelin/contracts-upgradeable/t 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 "../shared/Events.sol"; @@ -24,6 +25,7 @@ contract UniversalNFT is ERC721BurnableUpgradeable, OwnableUpgradeable, UniversalContract, + UUPSUpgradeable, Events { GatewayZEVM public gateway; @@ -63,6 +65,7 @@ contract UniversalNFT is __ERC721URIStorage_init(); __ERC721Burnable_init(); __Ownable_init(initialOwner); + __UUPSUpgradeable_init(); if (gatewayAddress == address(0) || uniswapRouterAddress == address(0)) revert InvalidAddress(); if (gas == 0) revert InvalidGasLimit(); @@ -93,7 +96,7 @@ contract UniversalNFT is if (destination != gasZRC20) revert InvalidAddress(); if ( !IZRC20(destination).transferFrom(msg.sender, address(this), gasFee) - ) revert TransferFailed(); + ) revert TransferFailed(); // failing here if (!IZRC20(destination).approve(address(gateway), gasFee)) { revert ApproveFailed(); } @@ -250,4 +253,8 @@ contract UniversalNFT is { return super.supportsInterface(interfaceId); } + + function _authorizeUpgrade( + address newImplementation + ) internal override onlyOwner {} } diff --git a/contracts/nft/package.json b/contracts/nft/package.json index 8e8f751..5b17b38 100644 --- a/contracts/nft/package.json +++ b/contracts/nft/package.json @@ -22,7 +22,7 @@ "@nomicfoundation/hardhat-verify": "^2.0.12", "@nomiclabs/hardhat-ethers": "^2.2.3", "@nomiclabs/hardhat-etherscan": "^3.0.0", - "@openzeppelin/hardhat-upgrades": "^3.6.0", + "@openzeppelin/hardhat-upgrades": "1.28.0", "@typechain/ethers-v5": "^10.1.0", "@typechain/hardhat": "^6.1.2", "@types/chai": "^4.2.0", @@ -44,7 +44,7 @@ "eslint-plugin-simple-import-sort": "^10.0.0", "eslint-plugin-sort-keys-fix": "^1.1.2", "eslint-plugin-typescript-sort-keys": "^2.3.0", - "ethers": "^6.13.4", + "ethers": "^5.4.7", "hardhat": "^2.17.2", "hardhat-gas-reporter": "^1.0.8", "prettier": "^2.8.8", @@ -63,4 +63,4 @@ "@solana/web3.js": "^1.95.2", "@zetachain/protocol-contracts": "11.0.0-rc3" } -} +} \ No newline at end of file diff --git a/contracts/nft/scripts/localnet.sh b/contracts/nft/scripts/localnet.sh index fe85a44..12622dc 100755 --- a/contracts/nft/scripts/localnet.sh +++ b/contracts/nft/scripts/localnet.sh @@ -29,21 +29,17 @@ 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 --name Universal --gateway "$GATEWAY_ZETACHAIN" --uniswap-router "$UNISWAP_ROUTER" --json | jq -r '.contractAddress') +CONTRACT_ZETACHAIN=$(npx hardhat deploy --network localhost --name ./contracts/zetachain/UniversalNFT.sol:UniversalNFT --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 deploy --name ./contracts/evm/UniversalNFT.sol:UniversalNFT --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 deploy --name ./contracts/evm/UniversalNFT.sol:UniversalNFT --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" -# npx hardhat initialize --network localhost --name Universal --contract "$CONTRACT_ZETACHAIN" --gateway "$GATEWAY_ZETACHAIN" --uniswap-router "$UNISWAP_ROUTER" --json -# npx hardhat initialize --network localhost --name Connected --contract "$CONTRACT_ETHEREUM" --gateway "$GATEWAY_ZETACHAIN" --json -# npx hardhat initialize --network localhost --name Connected --contract "$CONTRACT_BNB" --gateway "$GATEWAY_ZETACHAIN" --json - echo -e "\nšŸ”— Setting universal and connected contracts..." npx hardhat connected-set-universal --network localhost --contract "$CONTRACT_ETHEREUM" --universal "$CONTRACT_ZETACHAIN" --json npx hardhat connected-set-universal --network localhost --contract "$CONTRACT_BNB" --universal "$CONTRACT_ZETACHAIN" --json &>/dev/null @@ -60,21 +56,21 @@ 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" --gas-amount 0.1 +npx hardhat transfer --network localhost --json --token-id "$NFT_ID" --from "$CONTRACT_ZETACHAIN" --to "$ZRC20_ETHEREUM" 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 +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 localnet-check -# balance +npx hardhat localnet-check +balance -# echo -e "\nTransferring NFT: BNB ā†’ ZetaChain..." -# npx hardhat transfer --network localhost --json --token-id "$NFT_ID" --from "$CONTRACT_BNB" +echo -e "\nTransferring NFT: BNB ā†’ ZetaChain..." +npx hardhat transfer --network localhost --json --token-id "$NFT_ID" --from "$CONTRACT_BNB" -# npx hardhat localnet-check -# balance +npx hardhat localnet-check +balance if [ "$1" = "start" ]; then npx hardhat localnet-stop; fi \ No newline at end of file diff --git a/contracts/nft/tasks/deploy.ts b/contracts/nft/tasks/deploy.ts index 9e94168..5a4d6bc 100644 --- a/contracts/nft/tasks/deploy.ts +++ b/contracts/nft/tasks/deploy.ts @@ -25,7 +25,7 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { if (args.json) { console.log( JSON.stringify({ - contractAddress: contract.target, + contractAddress: contract.address, deployer: signer.address, network: network, }) diff --git a/contracts/nft/tasks/transfer.ts b/contracts/nft/tasks/transfer.ts index 7d2c9bd..1bd49ce 100644 --- a/contracts/nft/tasks/transfer.ts +++ b/contracts/nft/tasks/transfer.ts @@ -21,7 +21,8 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { try { contract = await ethers.getContractAt("Universal", args.from); await (contract as any).isUniversal(); - const gasLimit = hre.ethers.BigNumber.from(args.txOptionsGasLimit); + const gasLimitAmount = await (contract as any).gasLimitAmount(); + const gasLimit = hre.ethers.BigNumber.from(gasLimitAmount); 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); @@ -30,11 +31,13 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { contract = await ethers.getContractAt("Connected", args.from); } - // const gasAmount = ethers.utils.parseUnits(args.gasAmount, 18); + const gasAmount = ethers.utils.parseUnits(args.gasAmount, 18); const receiver = args.receiver || signer.address; - tx = await contract.transferCrossChain(args.tokenId, receiver, args.to); + tx = await contract.transferCrossChain(args.tokenId, receiver, args.to, { + value: gasAmount, + }); await tx.wait(); if (args.json) { @@ -68,7 +71,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 32b2f29..c89db7c 100644 --- a/contracts/nft/yarn.lock +++ b/contracts/nft/yarn.lock @@ -2093,48 +2093,41 @@ resolved "https://registry.yarnpkg.com/@openzeppelin/contracts/-/contracts-5.1.0.tgz#4e61162f2a2bf414c4e10c45eca98ce5f1aadbd4" integrity sha512-p1ULhl7BXzjjbha5aqst+QMLY+4/LCWADXOCsmLHRM77AqiPjnd9vvUN9sosUfhL9JGKpZ0TjEGxgvnizmWGSA== -"@openzeppelin/defender-sdk-base-client@^1.14.4", "@openzeppelin/defender-sdk-base-client@^1.15.2": - version "1.15.2" - resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-base-client/-/defender-sdk-base-client-1.15.2.tgz#aae7ec001365968b81ccce087f39a6eb52fa13f9" - integrity sha512-N3ZTeH8TXyklL7yNPMLUv0dxQwT78DTkOEDhzMS2/QE2FxbXrclSseoeeXxl6UYI61RBtZKn+okbSsbwiB5QWQ== +"@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.3.6" + 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/defender-sdk-deploy-client@^1.14.4": - version "1.15.2" - resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-deploy-client/-/defender-sdk-deploy-client-1.15.2.tgz#3b1d953aa66b6cdee13e7e672a488af2e2acf974" - integrity sha512-zspzMqh+OC8arXAkgBqTUDVO+NfCkt54UrsmQHbA3UAjr5TiDXKycBKU5ORb01hE+2gAmoPwEpDW9uS2VLg33A== - dependencies: - "@openzeppelin/defender-sdk-base-client" "^1.15.2" - axios "^1.7.2" - lodash "^4.17.21" - -"@openzeppelin/defender-sdk-network-client@^1.14.4": - version "1.15.2" - resolved "https://registry.yarnpkg.com/@openzeppelin/defender-sdk-network-client/-/defender-sdk-network-client-1.15.2.tgz#7178836d9861272ad509d93dea8739a5c4bf86c1" - integrity sha512-9r9pegc1aR7xzP9fmj1zvkk0OXMRJE10JabxxiJzAQQgmNXDeTGI6W5bFgrNJfxzcImNGqddJ3K4weKdLyL21A== - dependencies: - "@openzeppelin/defender-sdk-base-client" "^1.15.2" - axios "^1.7.2" - lodash "^4.17.21" - -"@openzeppelin/hardhat-upgrades@^3.6.0": - version "3.6.0" - resolved "https://registry.yarnpkg.com/@openzeppelin/hardhat-upgrades/-/hardhat-upgrades-3.6.0.tgz#8a252d6015b21ade1f5151816b6bc7b12348df53" - integrity sha512-RuVuCciCfFOqCyKSJ2D4Zffp3hxhvXTn16JzTlD9cx3A7V/2d3JA75tpRHD7RVPic+dcSFIf+BZRWOHuhc2ayg== +"@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-sdk-base-client" "^1.14.4" - "@openzeppelin/defender-sdk-deploy-client" "^1.14.4" - "@openzeppelin/defender-sdk-network-client" "^1.14.4" - "@openzeppelin/upgrades-core" "^1.41.0" + "@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" - ethereumjs-util "^7.1.5" proper-lockfile "^4.1.1" - undici "^6.11.1" -"@openzeppelin/upgrades-core@^1.41.0": +"@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== @@ -2674,13 +2667,6 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.13.tgz#f64277c341150c979e42b00e4ac289290c9df469" integrity sha512-N+0kuo9KgrUQ1Sn/ifDXsvg0TTleP7rIy4zOBGECxAljqvqfqpTfzx0Q1NUedOixRMBfe2Whhb056a42cWs26Q== -"@types/node@22.7.5": - version "22.7.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b" - integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ== - dependencies: - undici-types "~6.19.2" - "@types/node@^10.0.3": version "10.17.60" resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" @@ -3079,7 +3065,7 @@ ajv@^8.0.1: require-from-string "^2.0.2" uri-js "^4.2.2" -amazon-cognito-identity-js@^6.3.6: +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== @@ -3354,6 +3340,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: version "1.6.1" resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.1.tgz#76550d644bf0a2d469a01f9244db6753208397d7" @@ -3372,15 +3365,6 @@ axios@^1.6.1: form-data "^4.0.0" proxy-from-env "^1.1.0" -axios@^1.7.2: - version "1.7.8" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.8.tgz#1997b1496b394c21953e68c14aaa51b7b5de3d6e" - integrity sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw== - dependencies: - follow-redirects "^1.15.6" - form-data "^4.0.0" - proxy-from-env "^1.1.0" - balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -4772,7 +4756,7 @@ ethereumjs-util@^6.0.0, ethereumjs-util@^6.2.1: ethjs-util "0.1.6" rlp "^2.2.3" -ethereumjs-util@^7.0.3, ethereumjs-util@^7.1.4, ethereumjs-util@^7.1.5: +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== @@ -4855,7 +4839,7 @@ ethers@5.6.8: "@ethersproject/web" "5.6.1" "@ethersproject/wordlists" "5.6.1" -ethers@5.7.2, ethers@^5.7.1: +ethers@5.7.2, ethers@^5.4.7, ethers@^5.7.1: version "5.7.2" resolved "https://registry.yarnpkg.com/ethers/-/ethers-5.7.2.tgz#3a7deeabbb8c030d4126b24f84e525466145872e" integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== @@ -4919,19 +4903,6 @@ ethers@^6.13.2: tslib "2.4.0" ws "8.17.1" -ethers@^6.13.4: - version "6.13.4" - resolved "https://registry.yarnpkg.com/ethers/-/ethers-6.13.4.tgz#bd3e1c3dc1e7dc8ce10f9ffb4ee40967a651b53c" - integrity sha512-21YtnZVg4/zKkCQPjrDj38B1r4nQvTZLopUGMLQ1ePU2zV/joCfDC3t3iKQjWRzjjjbzR+mdAIoikeBRNkdllA== - dependencies: - "@adraffy/ens-normalize" "1.10.1" - "@noble/curves" "1.2.0" - "@noble/hashes" "1.3.2" - "@types/node" "22.7.5" - aes-js "4.0.0-beta.5" - tslib "2.7.0" - ws "8.17.1" - ethjs-unit@0.1.6: version "0.1.6" resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" @@ -5138,6 +5109,11 @@ follow-redirects@^1.12.1, follow-redirects@^1.15.0, follow-redirects@^1.15.6: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== +follow-redirects@^1.14.0: + version "1.15.9" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.9.tgz#a604fa10e443bf98ca94228d9eebcc2e8a2c8ee1" + integrity sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ== + for-each@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" @@ -6757,7 +6733,7 @@ node-environment-flags@1.0.6: object.getownpropertydescriptors "^2.0.3" semver "^5.7.0" -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== @@ -8151,11 +8127,6 @@ tslib@2.4.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== -tslib@2.7.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" - integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== - 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" @@ -8356,11 +8327,6 @@ undici@^5.14.0: dependencies: "@fastify/busboy" "^2.0.0" -undici@^6.11.1: - version "6.21.0" - resolved "https://registry.yarnpkg.com/undici/-/undici-6.21.0.tgz#4b3d3afaef984e07b48e7620c34ed8a285ed4cd4" - integrity sha512-BUgJXc752Kou3oOIuU1i+yZZypyZRqNPW0vqoMPl8VaoalSfeR0D8/t4iAS3yirs79SSMTxTag+ZC86uswv+Cw== - unfetch@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/unfetch/-/unfetch-4.2.0.tgz#7e21b0ef7d363d8d9af0fb929a5555f6ef97a3be" From 32995102109ea59642edce405338ab2645e72050 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Thu, 12 Dec 2024 11:28:41 +0300 Subject: [PATCH 07/18] Remove initialize task --- contracts/nft/hardhat.config.ts | 1 - contracts/nft/tasks/initialize.ts | 57 ------------------------------- 2 files changed, 58 deletions(-) delete mode 100644 contracts/nft/tasks/initialize.ts diff --git a/contracts/nft/hardhat.config.ts b/contracts/nft/hardhat.config.ts index bc4af21..32b68ca 100644 --- a/contracts/nft/hardhat.config.ts +++ b/contracts/nft/hardhat.config.ts @@ -1,7 +1,6 @@ import "./tasks/deploy"; import "./tasks/mint"; import "./tasks/transfer"; -import "./tasks/initialize"; import "./tasks/universalSetConnected"; import "./tasks/connectedSetUniversal"; import "@zetachain/localnet/tasks"; diff --git a/contracts/nft/tasks/initialize.ts b/contracts/nft/tasks/initialize.ts deleted file mode 100644 index 70df691..0000000 --- a/contracts/nft/tasks/initialize.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { task, types } from "hardhat/config"; -import { HardhatRuntimeEnvironment } from "hardhat/types"; - -const main = async (args: any, hre: HardhatRuntimeEnvironment) => { - const network = hre.network.name; - - const [signer] = await hre.ethers.getSigners(); - if (signer === undefined) { - throw new Error( - `Wallet not found. Please, run "npx hardhat account --save" or set PRIVATE_KEY env variable (for example, in a .env file)` - ); - } - - const contract: any = await hre.ethers.getContractAt( - args.name, - args.contract - ); - - const tx = await contract.initialize( - signer.address, - // args.tokenName, - // args.tokenSymbol, - // args.gateway, - // args.gasLimit, - // ...(args.uniswapRouter ? [args.uniswapRouter] : []), - { - gasLimit: args.initializeGasLimit, - } - ); - - await tx.wait(); -}; - -task("initialize", "Initialize the NFT contract", main) - .addOptionalParam("name", "The contract name to deploy", "Universal") - .addFlag("json", "Output the result in JSON format") - .addParam("contract", "The address of the deployed contract") - .addOptionalParam("tokenName", "NFT name", "Universal NFT") - .addOptionalParam("tokenSymbol", "NFT symbol", "UNFT") - .addOptionalParam( - "gasLimit", - "Gas limit for the transaction", - 1000000, - types.int - ) - .addOptionalParam( - "gateway", - "Gateway address (default: ZetaChain Gateway)", - "0x6c533f7fe93fae114d0954697069df33c9b74fd7" - ) - .addOptionalParam( - "initializeGasLimit", - "Gas limit for initialize transaction", - 10000000, - types.int - ) - .addOptionalParam("uniswapRouter", "Uniswap v2 Router address"); From c10a0c47a4df6490e7ecf384edcee0021cf19c8c Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Thu, 12 Dec 2024 11:53:31 +0300 Subject: [PATCH 08/18] token contract now upgradeable --- contracts/nft/scripts/localnet.sh | 8 +- .../token/contracts/evm/UniversalToken.sol | 47 +++- .../token/contracts/example/Connected.sol | 14 +- .../token/contracts/example/Universal.sol | 15 +- .../contracts/zetachain/UniversalToken.sol | 43 +++- contracts/token/hardhat.config.ts | 3 + contracts/token/package.json | 3 +- contracts/token/scripts/localnet.sh | 4 +- contracts/token/tasks/deploy.ts | 10 +- contracts/token/tasks/transfer.ts | 3 +- contracts/token/yarn.lock | 230 ++++++++++++++++-- 11 files changed, 306 insertions(+), 74 deletions(-) diff --git a/contracts/nft/scripts/localnet.sh b/contracts/nft/scripts/localnet.sh index 12622dc..e433204 100755 --- a/contracts/nft/scripts/localnet.sh +++ b/contracts/nft/scripts/localnet.sh @@ -29,13 +29,13 @@ 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 --name ./contracts/zetachain/UniversalNFT.sol:UniversalNFT --gateway "$GATEWAY_ZETACHAIN" --uniswap-router "$UNISWAP_ROUTER" --json | jq -r '.contractAddress') +CONTRACT_ZETACHAIN=$(npx hardhat deploy --network localhost --name Universal --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 ./contracts/evm/UniversalNFT.sol:UniversalNFT --json --network localhost --gateway "$GATEWAY_ETHEREUM" | jq -r '.contractAddress') +CONTRACT_ETHEREUM=$(npx hardhat deploy --name Connected --json --network localhost --gateway "$GATEWAY_ETHEREUM" | jq -r '.contractAddress') echo -e "šŸš€ Deployed NFT contract on Ethereum: $CONTRACT_ETHEREUM" -CONTRACT_BNB=$(npx hardhat deploy --name ./contracts/evm/UniversalNFT.sol:UniversalNFT --json --network localhost --gas-limit 1000000 --gateway "$GATEWAY_BNB" | jq -r '.contractAddress') +CONTRACT_BNB=$(npx hardhat deploy --name Connected --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" @@ -62,7 +62,7 @@ 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 transfer --network localhost --json --token-id "$NFT_ID" --from "$CONTRACT_ETHEREUM" --to "$ZRC20_BNB" --gas-amount 1 npx hardhat localnet-check balance diff --git a/contracts/token/contracts/evm/UniversalToken.sol b/contracts/token/contracts/evm/UniversalToken.sol index 22c39df..348499c 100644 --- a/contracts/token/contracts/evm/UniversalToken.sol +++ b/contracts/token/contracts/evm/UniversalToken.sol @@ -1,16 +1,25 @@ // 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 {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.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 "../shared/Events.sol"; -abstract contract UniversalToken is ERC20, Ownable2Step, Events { - GatewayEVM public immutable gateway; +contract UniversalToken is + Initializable, + ERC20Upgradeable, + OwnableUpgradeable, + UUPSUpgradeable, + Events +{ + GatewayEVM public gateway; address public universal; - uint256 public immutable gasLimitAmount; + uint256 public gasLimitAmount; error InvalidAddress(); error Unauthorized(); @@ -22,18 +31,32 @@ 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); + __Ownable_init(initialOwner); + __UUPSUpgradeable_init(); if (gatewayAddress == address(0)) revert InvalidAddress(); gasLimitAmount = gas; gateway = GatewayEVM(gatewayAddress); } + 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 { _mint(to, amount); } @@ -108,4 +131,8 @@ abstract contract UniversalToken is ERC20, Ownable2Step, Events { receive() external payable {} fallback() external payable {} + + function _authorizeUpgrade( + address newImplementation + ) internal override onlyOwner {} } diff --git a/contracts/token/contracts/example/Connected.sol b/contracts/token/contracts/example/Connected.sol index 4918dd1..8e9ecc8 100644 --- a/contracts/token/contracts/example/Connected.sol +++ b/contracts/token/contracts/example/Connected.sol @@ -3,16 +3,4 @@ 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) - {} -} +contract Connected is UniversalToken {} diff --git a/contracts/token/contracts/example/Universal.sol b/contracts/token/contracts/example/Universal.sol index d61ac77..c2ec0b4 100644 --- a/contracts/token/contracts/example/Universal.sol +++ b/contracts/token/contracts/example/Universal.sol @@ -3,17 +3,4 @@ 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) - {} -} +contract Universal is UniversalToken {} diff --git a/contracts/token/contracts/zetachain/UniversalToken.sol b/contracts/token/contracts/zetachain/UniversalToken.sol index c358bc7..4c87138 100644 --- a/contracts/token/contracts/zetachain/UniversalToken.sol +++ b/contracts/token/contracts/zetachain/UniversalToken.sol @@ -1,27 +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 {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 {ERC20Upgradeable} from "@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.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 "../shared/Events.sol"; -abstract contract UniversalToken is - ERC20, - Ownable2Step, +contract UniversalToken is + Initializable, + ERC20Upgradeable, + OwnableUpgradeable, + UUPSUpgradeable, UniversalContract, Events { - 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(); @@ -36,11 +42,22 @@ 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); + __Ownable_init(initialOwner); + __UUPSUpgradeable_init(); if (gatewayAddress == address(0) || uniswapRouterAddress == address(0)) revert InvalidAddress(); if (gas == 0) revert InvalidGasLimit(); @@ -156,4 +173,8 @@ abstract contract UniversalToken is _mint(sender, amount); emit TokenTransferReverted(sender, amount); } + + function _authorizeUpgrade( + address newImplementation + ) internal override onlyOwner {} } diff --git a/contracts/token/hardhat.config.ts b/contracts/token/hardhat.config.ts index cb20229..493dc7d 100644 --- a/contracts/token/hardhat.config.ts +++ b/contracts/token/hardhat.config.ts @@ -10,6 +10,9 @@ 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(), 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..9709874 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,7 +29,7 @@ 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 deploy --name Universal --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') diff --git a/contracts/token/tasks/deploy.ts b/contracts/token/tasks/deploy.ts index 28db1d8..536adbd 100644 --- a/contracts/token/tasks/deploy.ts +++ b/contracts/token/tasks/deploy.ts @@ -12,15 +12,15 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { } 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( diff --git a/contracts/token/tasks/transfer.ts b/contracts/token/tasks/transfer.ts index c772461..a449bf2 100644 --- a/contracts/token/tasks/transfer.ts +++ b/contracts/token/tasks/transfer.ts @@ -20,7 +20,8 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { try { contract = await ethers.getContractAt("Universal", args.from); await (contract as any).isUniversal(); - const gasLimit = hre.ethers.BigNumber.from(args.txOptionsGasLimit); + const gasLimitAmount = await (contract as any).gasLimitAmount(); + const gasLimit = hre.ethers.BigNumber.from(gasLimitAmount); 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); 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" From 27035238b18be1acb58fc1a02f0effa1ce0f4eb5 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Thu, 12 Dec 2024 11:54:23 +0300 Subject: [PATCH 09/18] solidity version --- contracts/nft/contracts/example/Universal.sol | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/contracts/nft/contracts/example/Universal.sol b/contracts/nft/contracts/example/Universal.sol index 72db12c..e7fa88a 100644 --- a/contracts/nft/contracts/example/Universal.sol +++ b/contracts/nft/contracts/example/Universal.sol @@ -1,6 +1,5 @@ // SPDX-License-Identifier: MIT -// Compatible with OpenZeppelin Contracts ^5.0.0 -pragma solidity ^0.8.22; +pragma solidity ^0.8.26; import "../zetachain/UniversalNFT.sol"; From 2d205689b5a7c1009a46c63e6d93bde5ef3790e4 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Fri, 13 Dec 2024 19:03:44 +0300 Subject: [PATCH 10/18] remove comment --- contracts/nft/contracts/zetachain/UniversalNFT.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/nft/contracts/zetachain/UniversalNFT.sol b/contracts/nft/contracts/zetachain/UniversalNFT.sol index 81a102d..c770f2d 100644 --- a/contracts/nft/contracts/zetachain/UniversalNFT.sol +++ b/contracts/nft/contracts/zetachain/UniversalNFT.sol @@ -96,7 +96,7 @@ contract UniversalNFT is if (destination != gasZRC20) revert InvalidAddress(); if ( !IZRC20(destination).transferFrom(msg.sender, address(this), gasFee) - ) revert TransferFailed(); // failing here + ) revert TransferFailed(); if (!IZRC20(destination).approve(address(gateway), gasFee)) { revert ApproveFailed(); } From 510ad53d5f7b4e113d6f31952d8537a80eb199d5 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Fri, 13 Dec 2024 19:04:06 +0300 Subject: [PATCH 11/18] gitignore --- contracts/nft/.gitignore | 2 ++ 1 file changed, 2 insertions(+) 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 From 41115eaabd83583f45faff920626a6619e976169 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Tue, 17 Dec 2024 12:04:18 +0300 Subject: [PATCH 12/18] feat: use ZETA for gas when sending from ZetaChain (#10) --- .../{Connected.sol => EVMUniversalNFT.sol} | 2 +- ...niversal.sol => ZetaChainUniversalNFT.sol} | 2 +- .../nft/contracts/zetachain/UniversalNFT.sol | 35 ++++++++++++++----- contracts/nft/scripts/localnet.sh | 8 ++--- contracts/nft/scripts/testnet.sh | 15 ++++---- contracts/nft/tasks/connectedSetUniversal.ts | 6 ++-- contracts/nft/tasks/mint.ts | 9 +++-- contracts/nft/tasks/transfer.ts | 14 +------- contracts/nft/tasks/universalSetConnected.ts | 6 ++-- 9 files changed, 53 insertions(+), 44 deletions(-) rename contracts/nft/contracts/example/{Connected.sol => EVMUniversalNFT.sol} (67%) rename contracts/nft/contracts/example/{Universal.sol => ZetaChainUniversalNFT.sol} (66%) diff --git a/contracts/nft/contracts/example/Connected.sol b/contracts/nft/contracts/example/EVMUniversalNFT.sol similarity index 67% rename from contracts/nft/contracts/example/Connected.sol rename to contracts/nft/contracts/example/EVMUniversalNFT.sol index 21a7fef..9e625ae 100644 --- a/contracts/nft/contracts/example/Connected.sol +++ b/contracts/nft/contracts/example/EVMUniversalNFT.sol @@ -3,4 +3,4 @@ pragma solidity 0.8.26; import "../evm/UniversalNFT.sol"; -contract Connected is UniversalNFT {} +contract EVMUniversalNFT is UniversalNFT {} diff --git a/contracts/nft/contracts/example/Universal.sol b/contracts/nft/contracts/example/ZetaChainUniversalNFT.sol similarity index 66% rename from contracts/nft/contracts/example/Universal.sol rename to contracts/nft/contracts/example/ZetaChainUniversalNFT.sol index e7fa88a..3b5db25 100644 --- a/contracts/nft/contracts/example/Universal.sol +++ b/contracts/nft/contracts/example/ZetaChainUniversalNFT.sol @@ -3,4 +3,4 @@ pragma solidity ^0.8.26; import "../zetachain/UniversalNFT.sol"; -contract Universal is UniversalNFT {} +contract ZetaChainUniversalNFT is UniversalNFT {} diff --git a/contracts/nft/contracts/zetachain/UniversalNFT.sol b/contracts/nft/contracts/zetachain/UniversalNFT.sol index c770f2d..de0ba5e 100644 --- a/contracts/nft/contracts/zetachain/UniversalNFT.sol +++ b/contracts/nft/contracts/zetachain/UniversalNFT.sol @@ -4,6 +4,7 @@ pragma solidity ^0.8.26; 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"; @@ -86,7 +87,7 @@ contract UniversalNFT is uint256 tokenId, address receiver, address destination - ) public { + ) public payable { if (receiver == address(0)) revert InvalidAddress(); string memory uri = tokenURI(tokenId); _burn(tokenId); @@ -94,12 +95,28 @@ 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, @@ -107,7 +124,6 @@ contract UniversalNFT is 0, msg.sender ); - CallOptions memory callOptions = CallOptions(gasLimitAmount, false); RevertOptions memory revertOptions = RevertOptions( @@ -118,6 +134,7 @@ contract UniversalNFT is gasLimitAmount ); + IZRC20(gasZRC20).approve(address(gateway), gasFee); gateway.call( abi.encodePacked(connected[destination]), destination, @@ -125,8 +142,6 @@ contract UniversalNFT is callOptions, revertOptions ); - - emit TokenTransfer(receiver, destination, tokenId, uri); } function safeMint(address to, string memory uri) public onlyOwner { @@ -257,4 +272,6 @@ contract UniversalNFT is function _authorizeUpgrade( address newImplementation ) internal override onlyOwner {} + + receive() external payable {} } diff --git a/contracts/nft/scripts/localnet.sh b/contracts/nft/scripts/localnet.sh index e433204..274ec98 100755 --- a/contracts/nft/scripts/localnet.sh +++ b/contracts/nft/scripts/localnet.sh @@ -29,13 +29,13 @@ 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 --name Universal --gateway "$GATEWAY_ZETACHAIN" --uniswap-router "$UNISWAP_ROUTER" --json | jq -r '.contractAddress') +CONTRACT_ZETACHAIN=$(npx hardhat 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 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 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" @@ -56,7 +56,7 @@ 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 transfer --network localhost --json --token-id "$NFT_ID" --from "$CONTRACT_ZETACHAIN" --to "$ZRC20_ETHEREUM" --gas-amount 1 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/connectedSetUniversal.ts b/contracts/nft/tasks/connectedSetUniversal.ts index 6a08235..7f99525 100644 --- a/contracts/nft/tasks/connectedSetUniversal.ts +++ b/contracts/nft/tasks/connectedSetUniversal.ts @@ -1,6 +1,6 @@ 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 [signer] = await hre.ethers.getSigners(); @@ -10,8 +10,8 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { ); } - const contract: Connected = await hre.ethers.getContractAt( - "Connected", + const contract: EVMUniversalNFT = await hre.ethers.getContractAt( + "EVMUniversalNFT", args.contract ); diff --git a/contracts/nft/tasks/mint.ts b/contracts/nft/tasks/mint.ts index 517354a..dc45c44 100644 --- a/contracts/nft/tasks/mint.ts +++ b/contracts/nft/tasks/mint.ts @@ -10,7 +10,7 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { } const contract = await hre.ethers.getContractAt( - args.name as "Universal" | "Connected", + args.name as "ZetaChainUniversalNFT" | "EVMUniversalNFT", args.contract ); @@ -47,7 +47,6 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { šŸ“œ Contract address: ${args.contract} šŸ‘¤ Recipient: ${recipient} šŸ†” Token ID: ${tokenId} -šŸ”— Metadata URI: ${metadataUri} šŸ”— Transaction hash: ${tx.hash}`); } }; @@ -59,5 +58,9 @@ task("mint", "Mint an NFT", main) "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/transfer.ts b/contracts/nft/tasks/transfer.ts index 1bd49ce..7ce8f97 100644 --- a/contracts/nft/tasks/transfer.ts +++ b/contracts/nft/tasks/transfer.ts @@ -17,19 +17,7 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { }; let tx; - let contract; - try { - contract = await ethers.getContractAt("Universal", args.from); - await (contract as any).isUniversal(); - const gasLimitAmount = await (contract as any).gasLimitAmount(); - const gasLimit = hre.ethers.BigNumber.from(gasLimitAmount); - 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); - } + let contract = await ethers.getContractAt("ZetaChainUniversalNFT", args.from); const gasAmount = ethers.utils.parseUnits(args.gasAmount, 18); diff --git a/contracts/nft/tasks/universalSetConnected.ts b/contracts/nft/tasks/universalSetConnected.ts index 249bdb0..50ed651 100644 --- a/contracts/nft/tasks/universalSetConnected.ts +++ b/contracts/nft/tasks/universalSetConnected.ts @@ -1,6 +1,6 @@ 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 [signer] = await hre.ethers.getSigners(); @@ -10,8 +10,8 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { ); } - const contract: Universal = await hre.ethers.getContractAt( - "Universal", + const contract: ZetaChainUniversalNFT = await hre.ethers.getContractAt( + "ZetaChainUniversalNFT", args.contract ); From 9ca161f6ad41342f8023054a15a4cfa2403a0e9e Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Tue, 17 Dec 2024 16:04:52 +0300 Subject: [PATCH 13/18] rename ft contracts --- contracts/token/contracts/example/Connected.sol | 2 +- contracts/token/contracts/example/Universal.sol | 2 +- contracts/token/scripts/localnet.sh | 6 +++--- contracts/token/tasks/connectedSetUniversal.ts | 6 +++--- contracts/token/tasks/deploy.ts | 6 +++++- contracts/token/tasks/mint.ts | 6 +++++- contracts/token/tasks/transfer.ts | 4 ++-- contracts/token/tasks/universalSetConnected.ts | 6 +++--- 8 files changed, 23 insertions(+), 15 deletions(-) diff --git a/contracts/token/contracts/example/Connected.sol b/contracts/token/contracts/example/Connected.sol index 8e9ecc8..80ae7b5 100644 --- a/contracts/token/contracts/example/Connected.sol +++ b/contracts/token/contracts/example/Connected.sol @@ -3,4 +3,4 @@ pragma solidity 0.8.26; import "../evm/UniversalToken.sol"; -contract Connected is UniversalToken {} +contract EVMUniversalToken is UniversalToken {} diff --git a/contracts/token/contracts/example/Universal.sol b/contracts/token/contracts/example/Universal.sol index c2ec0b4..c9b9abd 100644 --- a/contracts/token/contracts/example/Universal.sol +++ b/contracts/token/contracts/example/Universal.sol @@ -3,4 +3,4 @@ pragma solidity 0.8.26; import "../zetachain/UniversalToken.sol"; -contract Universal is UniversalToken {} +contract ZetaChainUniversalToken is UniversalToken {} diff --git a/contracts/token/scripts/localnet.sh b/contracts/token/scripts/localnet.sh index 9709874..ed04644 100755 --- a/contracts/token/scripts/localnet.sh +++ b/contracts/token/scripts/localnet.sh @@ -29,13 +29,13 @@ 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 --name Universal --network localhost --gateway "$GATEWAY_ZETACHAIN" --uniswap-router "$UNISWAP_ROUTER" --json | jq -r '.contractAddress') +CONTRACT_ZETACHAIN=$(npx hardhat 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 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 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" diff --git a/contracts/token/tasks/connectedSetUniversal.ts b/contracts/token/tasks/connectedSetUniversal.ts index 0e5a2c4..453a78a 100644 --- a/contracts/token/tasks/connectedSetUniversal.ts +++ b/contracts/token/tasks/connectedSetUniversal.ts @@ -1,6 +1,6 @@ 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 [signer] = await hre.ethers.getSigners(); @@ -10,8 +10,8 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { ); } - const contract: Connected = await hre.ethers.getContractAt( - "Connected", + const contract: EVMUniversalToken = await hre.ethers.getContractAt( + "EVMUniversalToken", args.contract ); diff --git a/contracts/token/tasks/deploy.ts b/contracts/token/tasks/deploy.ts index 536adbd..88ac064 100644 --- a/contracts/token/tasks/deploy.ts +++ b/contracts/token/tasks/deploy.ts @@ -42,7 +42,11 @@ task("deploy", "Deploy the NFT 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/mint.ts b/contracts/token/tasks/mint.ts index 3276974..94e8c00 100644 --- a/contracts/token/tasks/mint.ts +++ b/contracts/token/tasks/mint.ts @@ -50,5 +50,9 @@ task("mint", "Mint an NFT", main) "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/transfer.ts b/contracts/token/tasks/transfer.ts index a449bf2..81ea5c8 100644 --- a/contracts/token/tasks/transfer.ts +++ b/contracts/token/tasks/transfer.ts @@ -18,7 +18,7 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { let contract; try { - contract = await ethers.getContractAt("Universal", args.from); + contract = await ethers.getContractAt("ZetaChainUniversalToken", args.from); await (contract as any).isUniversal(); const gasLimitAmount = await (contract as any).gasLimitAmount(); const gasLimit = hre.ethers.BigNumber.from(gasLimitAmount); @@ -29,7 +29,7 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { const tokenApprove = await contract.approve(args.from, value); await tokenApprove.wait(); } catch (e) { - contract = await ethers.getContractAt("Connected", args.from); + contract = await ethers.getContractAt("EVMUniversalToken", args.from); } const receiver = args.receiver || signer.address; diff --git a/contracts/token/tasks/universalSetConnected.ts b/contracts/token/tasks/universalSetConnected.ts index b8de726..8aaeab8 100644 --- a/contracts/token/tasks/universalSetConnected.ts +++ b/contracts/token/tasks/universalSetConnected.ts @@ -1,6 +1,6 @@ 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 [signer] = await hre.ethers.getSigners(); @@ -10,8 +10,8 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { ); } - const contract: Universal = await hre.ethers.getContractAt( - "Universal", + const contract: ZetaChainUniversalToken = await hre.ethers.getContractAt( + "ZetaChainUniversalToken", args.contract ); From a3f58ba9eaa5c4c53c080fd3b1215fbc5c41a3c3 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Tue, 17 Dec 2024 17:11:25 +0300 Subject: [PATCH 14/18] FT: pay with ZETA when transferring tokens from ZetaChain --- contracts/nft/tasks/transfer.ts | 16 +++++---- .../contracts/zetachain/UniversalToken.sol | 30 ++++++++++++---- contracts/token/scripts/localnet.sh | 2 +- contracts/token/tasks/transfer.ts | 35 +++++++------------ 4 files changed, 47 insertions(+), 36 deletions(-) diff --git a/contracts/nft/tasks/transfer.ts b/contracts/nft/tasks/transfer.ts index 7ce8f97..70ea8b6 100644 --- a/contracts/nft/tasks/transfer.ts +++ b/contracts/nft/tasks/transfer.ts @@ -1,6 +1,5 @@ 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; @@ -15,17 +14,22 @@ const main = async (args: any, hre: HardhatRuntimeEnvironment) => { gasPrice: args.txOptionsGasPrice, gasLimit: args.txOptionsGasLimit, }; - let tx; - let contract = await ethers.getContractAt("ZetaChainUniversalNFT", 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) { diff --git a/contracts/token/contracts/zetachain/UniversalToken.sol b/contracts/token/contracts/zetachain/UniversalToken.sol index 4c87138..0868549 100644 --- a/contracts/token/contracts/zetachain/UniversalToken.sol +++ b/contracts/token/contracts/zetachain/UniversalToken.sol @@ -78,7 +78,7 @@ contract UniversalToken is address destination, address receiver, uint256 amount - ) public { + ) public payable { if (receiver == address(0)) revert InvalidAddress(); _burn(msg.sender, amount); @@ -86,12 +86,27 @@ 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); @@ -104,6 +119,7 @@ contract UniversalToken is gasLimitAmount ); + IZRC20(gasZRC20).approve(address(gateway), gasFee); gateway.call( abi.encodePacked(connected[destination]), destination, @@ -177,4 +193,6 @@ contract UniversalToken is function _authorizeUpgrade( address newImplementation ) internal override onlyOwner {} + + receive() external payable {} } diff --git a/contracts/token/scripts/localnet.sh b/contracts/token/scripts/localnet.sh index ed04644..61cb5f0 100755 --- a/contracts/token/scripts/localnet.sh +++ b/contracts/token/scripts/localnet.sh @@ -56,7 +56,7 @@ 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 transfer --network localhost --json --amount 10 --from "$CONTRACT_ZETACHAIN" --to "$ZRC20_ETHEREUM" --gas-amount 1 npx hardhat localnet-check balance diff --git a/contracts/token/tasks/transfer.ts b/contracts/token/tasks/transfer.ts index 81ea5c8..884e401 100644 --- a/contracts/token/tasks/transfer.ts +++ b/contracts/token/tasks/transfer.ts @@ -1,40 +1,29 @@ 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 txOptions = { gasPrice: args.txOptionsGasPrice, gasLimit: args.txOptionsGasLimit, }; - let tx; - let contract; - try { - contract = await ethers.getContractAt("ZetaChainUniversalToken", args.from); - await (contract as any).isUniversal(); - const gasLimitAmount = await (contract as any).gasLimitAmount(); - const gasLimit = hre.ethers.BigNumber.from(gasLimitAmount); - 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("EVMUniversalToken", 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, @@ -95,5 +84,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"); From d7e824ce96150da5044962802f4b35cd0dc768c8 Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Wed, 18 Dec 2024 18:25:55 +0300 Subject: [PATCH 15/18] feat: allow incoming and outgoing transfers --- .../nft/contracts/zetachain/UniversalNFT.sol | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/contracts/nft/contracts/zetachain/UniversalNFT.sol b/contracts/nft/contracts/zetachain/UniversalNFT.sol index de0ba5e..8b5b419 100644 --- a/contracts/nft/contracts/zetachain/UniversalNFT.sol +++ b/contracts/nft/contracts/zetachain/UniversalNFT.sol @@ -1,22 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.26; -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 {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 "../shared/Events.sol"; +// Existing imports... contract UniversalNFT is Initializable, @@ -35,11 +20,16 @@ contract UniversalNFT is bool public constant isUniversal = true; uint256 public gasLimitAmount; + bool public allowOutgoing = true; + bool public allowIncoming = true; + error TransferFailed(); error Unauthorized(); error InvalidAddress(); error InvalidGasLimit(); error ApproveFailed(); + error OutgoingTransfersNotAllowed(); + error IncomingTransfersNotAllowed(); mapping(address => address) public connected; @@ -75,6 +65,14 @@ contract UniversalNFT is gasLimitAmount = gas; } + function setAllowOutgoing(bool _allowOutgoing) external onlyOwner { + allowOutgoing = _allowOutgoing; + } + + function setAllowIncoming(bool _allowIncoming) external onlyOwner { + allowIncoming = _allowIncoming; + } + function setConnected( address zrc20, address contractAddress @@ -88,7 +86,9 @@ contract UniversalNFT is address receiver, address destination ) public payable { + if (!allowOutgoing) revert OutgoingTransfersNotAllowed(); if (receiver == address(0)) revert InvalidAddress(); + string memory uri = tokenURI(tokenId); _burn(tokenId); @@ -174,6 +174,7 @@ contract UniversalNFT is ) = abi.decode(message, (address, address, uint256, string, address)); if (destination == address(0)) { + if (!allowIncoming) revert IncomingTransfersNotAllowed(); _safeMint(receiver, tokenId); _setTokenURI(tokenId, uri); emit TokenTransferReceived(receiver, tokenId, uri); From 52f511869441cceef3dfebe559c399c1d1277f5c Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Wed, 18 Dec 2024 18:28:41 +0300 Subject: [PATCH 16/18] add imports back --- .../nft/contracts/zetachain/UniversalNFT.sol | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/contracts/nft/contracts/zetachain/UniversalNFT.sol b/contracts/nft/contracts/zetachain/UniversalNFT.sol index 8b5b419..92d67df 100644 --- a/contracts/nft/contracts/zetachain/UniversalNFT.sol +++ b/contracts/nft/contracts/zetachain/UniversalNFT.sol @@ -1,7 +1,22 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.26; -// Existing imports... +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 {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 "../shared/Events.sol"; contract UniversalNFT is Initializable, From 6f608b24deffef81670ee76eecc05f52c373e0fe Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Wed, 18 Dec 2024 18:33:31 +0300 Subject: [PATCH 17/18] allow outgoing/incoming on EVM --- contracts/nft/contracts/evm/UniversalNFT.sol | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/contracts/nft/contracts/evm/UniversalNFT.sol b/contracts/nft/contracts/evm/UniversalNFT.sol index 6f68cae..713ce0b 100644 --- a/contracts/nft/contracts/evm/UniversalNFT.sol +++ b/contracts/nft/contracts/evm/UniversalNFT.sol @@ -29,10 +29,15 @@ contract UniversalNFT is address public universal; uint256 public gasLimitAmount; + bool public allowOutgoing = true; + bool public allowIncoming = true; + error InvalidAddress(); error Unauthorized(); error InvalidGasLimit(); error GasTokenTransferFailed(); + error OutgoingTransfersNotAllowed(); + error IncomingTransfersNotAllowed(); modifier onlyGateway() { if (msg.sender != address(gateway)) revert Unauthorized(); @@ -62,6 +67,14 @@ contract UniversalNFT is gateway = GatewayEVM(gatewayAddress); } + function setAllowOutgoing(bool _allowOutgoing) external onlyOwner { + allowOutgoing = _allowOutgoing; + } + + function setAllowIncoming(bool _allowIncoming) external onlyOwner { + allowIncoming = _allowIncoming; + } + function setUniversal(address contractAddress) external onlyOwner { if (contractAddress == address(0)) revert InvalidAddress(); universal = contractAddress; @@ -87,6 +100,7 @@ contract UniversalNFT is address receiver, address destination ) external payable { + if (!allowOutgoing) revert OutgoingTransfersNotAllowed(); if (receiver == address(0)) revert InvalidAddress(); string memory uri = tokenURI(tokenId); @@ -125,6 +139,7 @@ contract UniversalNFT is MessageContext calldata context, bytes calldata message ) external payable onlyGateway returns (bytes4) { + if (!allowIncoming) revert IncomingTransfersNotAllowed(); if (context.sender != universal) revert Unauthorized(); ( From c313c2440f14b56eb345f386ac9fc5e51723a34f Mon Sep 17 00:00:00 2001 From: Denis Fadeev Date: Thu, 19 Dec 2024 14:41:46 +0300 Subject: [PATCH 18/18] set variables in initialize --- contracts/nft/contracts/evm/UniversalNFT.sol | 6 ++++-- contracts/nft/contracts/zetachain/UniversalNFT.sol | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/contracts/nft/contracts/evm/UniversalNFT.sol b/contracts/nft/contracts/evm/UniversalNFT.sol index 713ce0b..9fc3018 100644 --- a/contracts/nft/contracts/evm/UniversalNFT.sol +++ b/contracts/nft/contracts/evm/UniversalNFT.sol @@ -29,8 +29,8 @@ contract UniversalNFT is address public universal; uint256 public gasLimitAmount; - bool public allowOutgoing = true; - bool public allowIncoming = true; + bool public allowOutgoing; + bool public allowIncoming; error InvalidAddress(); error Unauthorized(); @@ -65,6 +65,8 @@ contract UniversalNFT is if (gas == 0) revert InvalidGasLimit(); gasLimitAmount = gas; gateway = GatewayEVM(gatewayAddress); + allowOutgoing = true; + allowIncoming = true; } function setAllowOutgoing(bool _allowOutgoing) external onlyOwner { diff --git a/contracts/nft/contracts/zetachain/UniversalNFT.sol b/contracts/nft/contracts/zetachain/UniversalNFT.sol index 92d67df..78a2f03 100644 --- a/contracts/nft/contracts/zetachain/UniversalNFT.sol +++ b/contracts/nft/contracts/zetachain/UniversalNFT.sol @@ -35,8 +35,8 @@ contract UniversalNFT is bool public constant isUniversal = true; uint256 public gasLimitAmount; - bool public allowOutgoing = true; - bool public allowIncoming = true; + bool public allowOutgoing; + bool public allowIncoming; error TransferFailed(); error Unauthorized(); @@ -78,6 +78,8 @@ contract UniversalNFT is gateway = GatewayZEVM(gatewayAddress); uniswapRouter = uniswapRouterAddress; gasLimitAmount = gas; + allowOutgoing = true; + allowIncoming = true; } function setAllowOutgoing(bool _allowOutgoing) external onlyOwner {