diff --git a/challenge-1-vesting/README.md b/challenge-1-vesting/README.md index 9cc7a2c..f9bb906 100644 --- a/challenge-1-vesting/README.md +++ b/challenge-1-vesting/README.md @@ -10,7 +10,7 @@ Add your information to the below list to officially participate in the workshop | Emoji | Name | Github Username | Occupations | | ----- | ---- | ------------------------------------- | ----------- | -| 🎅 | Ippo | [NTP-996](https://github.com/NTP-996) | DevRel | +| 🦄 | Abhishek | [AbhiXverse](https://github.com/AbhiXverse) | Developer | ## 💻 Local development environment setup diff --git a/challenge-1-vesting/contracts/TokenVesting.sol b/challenge-1-vesting/contracts/TokenVesting.sol index 43d4c3a..f50e933 100644 --- a/challenge-1-vesting/contracts/TokenVesting.sol +++ b/challenge-1-vesting/contracts/TokenVesting.sol @@ -21,7 +21,7 @@ Here's your starter code: */ // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity ^0.8.18; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; @@ -30,48 +30,54 @@ import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; contract TokenVesting is Ownable(msg.sender), Pausable, ReentrancyGuard { struct VestingSchedule { - // TODO: Define the vesting schedule struct + uint256 totalAmount; // total amount of tokens to be vested + uint256 startTime; // when vesting begins + uint256 cliffDuration; // how long until first tokens can be claimed + uint256 vestingDuration; // total vesting period + uint256 amountClaimed; // how much has been claimed so far + bool revoked; // whether this schedule has been revoked } - // Token being vested - // TODO: Add state variables + // ERC20 token to be vested + IERC20 public token; + // mapping of beneficiary address to VestingSchedule and whitelist + mapping(address => VestingSchedule) public vestingSchedules; + mapping(address => bool) public whitelist; - // Mapping from beneficiary to vesting schedule - // TODO: Add state variables - - // Whitelist of beneficiaries - // TODO: Add state variables - - // Events + // events for created vesting schedule, claimed tokens, revoked vesting, and whitelist management event VestingScheduleCreated(address indexed beneficiary, uint256 amount); event TokensClaimed(address indexed beneficiary, uint256 amount); event VestingRevoked(address indexed beneficiary); event BeneficiaryWhitelisted(address indexed beneficiary); event BeneficiaryRemovedFromWhitelist(address indexed beneficiary); + // constructor to set the token address constructor(address tokenAddress) { - // TODO: Initialize the contract - + require(tokenAddress != address(0), "token adress cannot be zero"); // checks if token address is valid + token = IERC20(tokenAddress); // initializes the token variable } - // Modifier to check if beneficiary is whitelisted + // modifier to check if beneficiary is whitelisted modifier onlyWhitelisted(address beneficiary) { - require(whitelist[beneficiary], "Beneficiary not whitelisted"); + require(whitelist[beneficiary], "beneficiary not whitelisted"); _; } + // function to add a beneficiary to the whitelist function addToWhitelist(address beneficiary) external onlyOwner { - require(beneficiary != address(0), "Invalid address"); - whitelist[beneficiary] = true; - emit BeneficiaryWhitelisted(beneficiary); + require(beneficiary != address(0), "invalid address"); // checks if address is valid + whitelist[beneficiary] = true; // adds the address to the whitelist + emit BeneficiaryWhitelisted(beneficiary); // emits event for whitelisting } + // function to remove a beneficiary from the whitelist function removeFromWhitelist(address beneficiary) external onlyOwner { - whitelist[beneficiary] = false; - emit BeneficiaryRemovedFromWhitelist(beneficiary); + whitelist[beneficiary] = false; // removes the address from the whitelist + emit BeneficiaryRemovedFromWhitelist(beneficiary); // emits event for removal } + // function to create a vesting schedule function createVestingSchedule( address beneficiary, uint256 amount, @@ -79,28 +85,103 @@ contract TokenVesting is Ownable(msg.sender), Pausable, ReentrancyGuard { uint256 vestingDuration, uint256 startTime ) external onlyOwner onlyWhitelisted(beneficiary) whenNotPaused { - // TODO: Implement vesting schedule creation + require(beneficiary != address(0), "invalid beneficiary address"); // checks if address is valid + require(amount > 0, "vesting amount must be greather than 0"); // checks if amount is valid + require(vestingDuration > 0, "vesting duration must be greather than 0"); // checks if vesting duration is valid + require(vestingDuration >= cliffDuration,"Vesting duration must be >= cliff"); // checks if cliff duration is valid + VestingSchedule storage existing = vestingSchedules[beneficiary]; // get the existing vesting schedule + require(existing.totalAmount == 0 || existing.revoked, "schedule exists"); // checks if schedule exists + + // transfer tokens from sender to contract + require(token.transferFrom(msg.sender, address(this), amount), "Token transfer failed"); + + vestingSchedules[beneficiary] = VestingSchedule({ // creates a new vesting schedule + totalAmount: amount, + startTime: startTime, + cliffDuration: cliffDuration, + vestingDuration: vestingDuration, + amountClaimed: 0, + revoked: false + }); + + require(token.transferFrom(msg.sender, address(this), amount),"token transfer failed"); // transfers tokens from the sender to contract + emit VestingScheduleCreated(beneficiary, amount); // emits event for created vesting schedule } - function calculateVestedAmount( - address beneficiary - ) public view returns (uint256) { - // TODO: Implement vested amount calculation + // function to calculate the vested amount for a beneficiary + function calculateVestedAmount(address beneficiary) public view returns (uint256) { + + VestingSchedule storage schedule = vestingSchedules[beneficiary]; // get the vesting schedule for the beneficiary + + // return 0 if there's no schedule or it has been revoked + if (schedule.totalAmount == 0 || schedule.revoked) { + return 0; + } + + // if current time is before cliff, nothing is vested + if (block.timestamp < schedule.startTime + schedule.cliffDuration) { + return 0; + } + + // if vesting is complete, everything is vested + if (block.timestamp >= schedule.startTime + schedule.vestingDuration) { + return schedule.totalAmount; + } + + // linear vesting calculation + uint256 timePassedSinceStart = block.timestamp - schedule.startTime; // time passed since start + uint256 vestedAmount = (schedule.totalAmount * timePassedSinceStart) / schedule.vestingDuration; // linear vesting formula + return vestedAmount; } + // function to claim vested tokens function claimVestedTokens() external nonReentrant whenNotPaused { - // TODO: Implement token claiming + address beneficiary = msg.sender; // get the address of the beneficiary + VestingSchedule storage schedule = vestingSchedules[beneficiary]; // get the vesting schedule for the beneficiary + + require(schedule.totalAmount > 0, "no vesting schedule found"); // checks if schedule exists + require(!schedule.revoked, "vesting schedule has been revoked"); // checks if schedule is revoked + + uint256 vestedAmount = calculateVestedAmount(beneficiary); // calculate the vested amount + uint256 claimableAmount = vestedAmount - schedule.amountClaimed; // calculate the claimable amount + + require(claimableAmount > 0, "no tokens available to claim"); // checks if there are tokens to claim + + // update claimed amount before transfer to prevent reentrancy + schedule.amountClaimed += claimableAmount; + + // transfer tokens to beneficiary + require(token.transfer(beneficiary, claimableAmount), "token transfer failed"); + emit TokensClaimed(beneficiary, claimableAmount); // emit event for claimed tokens } + // function to revoke vesting schedule function revokeVesting(address beneficiary) external onlyOwner { - // TODO: Implement vesting revocation - + VestingSchedule storage schedule = vestingSchedules[beneficiary]; // get the vesting schedule for the beneficiary + + require(schedule.totalAmount > 0, "no vesting schedule found"); // checks if schedule exists + + // calculate vested and unvested amounts + uint256 vestedAmount = calculateVestedAmount(beneficiary); + uint256 unvestedAmount = schedule.totalAmount - vestedAmount; + + // mark as revoked + schedule.revoked = true; + + // transfer unvested tokens back to owner + if (unvestedAmount > 0) { + require(token.transfer(owner(), unvestedAmount), "token transfer failed"); + } + + emit VestingRevoked(beneficiary); // emit event for revoked vesting } + // function to pause the contract function pause() external onlyOwner { _pause(); } + // function to unpause the contract function unpause() external onlyOwner { _unpause(); } @@ -145,4 +226,4 @@ Solution template (key points to implement): - Calculate and transfer unvested tokens back - Mark schedule as revoked - Emit event -*/ \ No newline at end of file +*/ diff --git a/challenge-1-vesting/package-lock.json b/challenge-1-vesting/package-lock.json index ebb18e8..6394269 100644 --- a/challenge-1-vesting/package-lock.json +++ b/challenge-1-vesting/package-lock.json @@ -14,6 +14,7 @@ "dotenv": "^16.4.7" }, "devDependencies": { + "@nomicfoundation/hardhat-network-helpers": "^1.0.12", "@nomicfoundation/hardhat-toolbox": "^5.0.0", "hardhat": "^2.22.17" } @@ -133,9 +134,9 @@ } }, "node_modules/@ethersproject/abi": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", - "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.8.0.tgz", + "integrity": "sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q==", "funding": [ { "type": "individual", @@ -146,22 +147,23 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "dependencies": { - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/strings": "^5.7.0" + "@ethersproject/address": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/hash": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/strings": "^5.8.0" } }, "node_modules/@ethersproject/abstract-provider": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", - "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.8.0.tgz", + "integrity": "sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg==", "funding": [ { "type": "individual", @@ -172,20 +174,21 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "dependencies": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/networks": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/web": "^5.7.0" + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/networks": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/transactions": "^5.8.0", + "@ethersproject/web": "^5.8.0" } }, "node_modules/@ethersproject/abstract-signer": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", - "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.8.0.tgz", + "integrity": "sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA==", "funding": [ { "type": "individual", @@ -196,18 +199,19 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "dependencies": { - "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0" + "@ethersproject/abstract-provider": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0" } }, "node_modules/@ethersproject/address": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", - "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.8.0.tgz", + "integrity": "sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA==", "funding": [ { "type": "individual", @@ -218,18 +222,19 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "dependencies": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/rlp": "^5.7.0" + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/rlp": "^5.8.0" } }, "node_modules/@ethersproject/base64": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", - "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.8.0.tgz", + "integrity": "sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ==", "funding": [ { "type": "individual", @@ -240,14 +245,15 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "dependencies": { - "@ethersproject/bytes": "^5.7.0" + "@ethersproject/bytes": "^5.8.0" } }, "node_modules/@ethersproject/basex": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz", - "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.8.0.tgz", + "integrity": "sha512-PIgTszMlDRmNwW9nhS6iqtVfdTAKosA7llYXNmGPw4YAI1PUyMv28988wAb41/gHF/WqGdoLv0erHaRcHRKW2Q==", "dev": true, "funding": [ { @@ -259,16 +265,17 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "peer": true, "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/properties": "^5.7.0" + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/properties": "^5.8.0" } }, "node_modules/@ethersproject/bignumber": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", - "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.8.0.tgz", + "integrity": "sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA==", "funding": [ { "type": "individual", @@ -279,16 +286,17 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", "bn.js": "^5.2.1" } }, "node_modules/@ethersproject/bytes": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", - "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.8.0.tgz", + "integrity": "sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==", "funding": [ { "type": "individual", @@ -299,14 +307,15 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "dependencies": { - "@ethersproject/logger": "^5.7.0" + "@ethersproject/logger": "^5.8.0" } }, "node_modules/@ethersproject/constants": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", - "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.8.0.tgz", + "integrity": "sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg==", "funding": [ { "type": "individual", @@ -317,14 +326,15 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "dependencies": { - "@ethersproject/bignumber": "^5.7.0" + "@ethersproject/bignumber": "^5.8.0" } }, "node_modules/@ethersproject/contracts": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", - "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.8.0.tgz", + "integrity": "sha512-0eFjGz9GtuAi6MZwhb4uvUM216F38xiuR0yYCjKJpNfSEy4HUM8hvqqBj9Jmm0IUz8l0xKEhWwLIhPgxNY0yvQ==", "dev": true, "funding": [ { @@ -336,24 +346,25 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "peer": true, "dependencies": { - "@ethersproject/abi": "^5.7.0", - "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/transactions": "^5.7.0" + "@ethersproject/abi": "^5.8.0", + "@ethersproject/abstract-provider": "^5.8.0", + "@ethersproject/abstract-signer": "^5.8.0", + "@ethersproject/address": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/transactions": "^5.8.0" } }, "node_modules/@ethersproject/hash": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", - "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.8.0.tgz", + "integrity": "sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA==", "funding": [ { "type": "individual", @@ -364,22 +375,23 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "dependencies": { - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/base64": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/strings": "^5.7.0" + "@ethersproject/abstract-signer": "^5.8.0", + "@ethersproject/address": "^5.8.0", + "@ethersproject/base64": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/strings": "^5.8.0" } }, "node_modules/@ethersproject/hdnode": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", - "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.8.0.tgz", + "integrity": "sha512-4bK1VF6E83/3/Im0ERnnUeWOY3P1BZml4ZD3wcH8Ys0/d1h1xaFt6Zc+Dh9zXf9TapGro0T4wvO71UTCp3/uoA==", "dev": true, "funding": [ { @@ -391,26 +403,27 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "peer": true, "dependencies": { - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/basex": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/pbkdf2": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/sha2": "^5.7.0", - "@ethersproject/signing-key": "^5.7.0", - "@ethersproject/strings": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/wordlists": "^5.7.0" + "@ethersproject/abstract-signer": "^5.8.0", + "@ethersproject/basex": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/pbkdf2": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/sha2": "^5.8.0", + "@ethersproject/signing-key": "^5.8.0", + "@ethersproject/strings": "^5.8.0", + "@ethersproject/transactions": "^5.8.0", + "@ethersproject/wordlists": "^5.8.0" } }, "node_modules/@ethersproject/json-wallets": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", - "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.8.0.tgz", + "integrity": "sha512-HxblNck8FVUtNxS3VTEYJAcwiKYsBIF77W15HufqlBF9gGfhmYOJtYZp8fSDZtn9y5EaXTE87zDwzxRoTFk11w==", "dev": true, "funding": [ { @@ -422,19 +435,20 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "peer": true, - "dependencies": { - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/hdnode": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/pbkdf2": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/random": "^5.7.0", - "@ethersproject/strings": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/abstract-signer": "^5.8.0", + "@ethersproject/address": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/hdnode": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/pbkdf2": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/random": "^5.8.0", + "@ethersproject/strings": "^5.8.0", + "@ethersproject/transactions": "^5.8.0", "aes-js": "3.0.0", "scrypt-js": "3.0.1" } @@ -444,12 +458,13 @@ "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/@ethersproject/keccak256": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", - "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.8.0.tgz", + "integrity": "sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng==", "funding": [ { "type": "individual", @@ -460,15 +475,16 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "dependencies": { - "@ethersproject/bytes": "^5.7.0", + "@ethersproject/bytes": "^5.8.0", "js-sha3": "0.8.0" } }, "node_modules/@ethersproject/logger": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", - "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.8.0.tgz", + "integrity": "sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==", "funding": [ { "type": "individual", @@ -478,12 +494,13 @@ "type": "individual", "url": "https://www.buymeacoffee.com/ricmoo" } - ] + ], + "license": "MIT" }, "node_modules/@ethersproject/networks": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", - "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.8.0.tgz", + "integrity": "sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg==", "funding": [ { "type": "individual", @@ -494,14 +511,15 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "dependencies": { - "@ethersproject/logger": "^5.7.0" + "@ethersproject/logger": "^5.8.0" } }, "node_modules/@ethersproject/pbkdf2": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", - "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.8.0.tgz", + "integrity": "sha512-wuHiv97BrzCmfEaPbUFpMjlVg/IDkZThp9Ri88BpjRleg4iePJaj2SW8AIyE8cXn5V1tuAaMj6lzvsGJkGWskg==", "dev": true, "funding": [ { @@ -513,16 +531,17 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "peer": true, "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/sha2": "^5.7.0" + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/sha2": "^5.8.0" } }, "node_modules/@ethersproject/properties": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", - "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.8.0.tgz", + "integrity": "sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==", "funding": [ { "type": "individual", @@ -533,14 +552,15 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "dependencies": { - "@ethersproject/logger": "^5.7.0" + "@ethersproject/logger": "^5.8.0" } }, "node_modules/@ethersproject/providers": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", - "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.8.0.tgz", + "integrity": "sha512-3Il3oTzEx3o6kzcg9ZzbE+oCZYyY+3Zh83sKkn4s1DZfTUjIegHnN2Cm0kbn9YFy45FDVcuCLLONhU7ny0SsCw==", "dev": true, "funding": [ { @@ -552,42 +572,44 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "peer": true, - "dependencies": { - "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/base64": "^5.7.0", - "@ethersproject/basex": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/networks": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/random": "^5.7.0", - "@ethersproject/rlp": "^5.7.0", - "@ethersproject/sha2": "^5.7.0", - "@ethersproject/strings": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/web": "^5.7.0", + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/abstract-provider": "^5.8.0", + "@ethersproject/abstract-signer": "^5.8.0", + "@ethersproject/address": "^5.8.0", + "@ethersproject/base64": "^5.8.0", + "@ethersproject/basex": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/hash": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/networks": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/random": "^5.8.0", + "@ethersproject/rlp": "^5.8.0", + "@ethersproject/sha2": "^5.8.0", + "@ethersproject/strings": "^5.8.0", + "@ethersproject/transactions": "^5.8.0", + "@ethersproject/web": "^5.8.0", "bech32": "1.1.4", - "ws": "7.4.6" + "ws": "8.18.0" } }, "node_modules/@ethersproject/providers/node_modules/ws": { - "version": "7.4.6", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", - "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", "dev": true, + "license": "MIT", "peer": true, "engines": { - "node": ">=8.3.0" + "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -599,9 +621,9 @@ } }, "node_modules/@ethersproject/random": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", - "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.8.0.tgz", + "integrity": "sha512-E4I5TDl7SVqyg4/kkA/qTfuLWAQGXmSOgYyO01So8hLfwgKvYK5snIlzxJMk72IFdG/7oh8yuSqY2KX7MMwg+A==", "dev": true, "funding": [ { @@ -613,16 +635,17 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "peer": true, "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0" + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0" } }, "node_modules/@ethersproject/rlp": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", - "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.8.0.tgz", + "integrity": "sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q==", "funding": [ { "type": "individual", @@ -633,15 +656,16 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0" + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0" } }, "node_modules/@ethersproject/sha2": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", - "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.8.0.tgz", + "integrity": "sha512-dDOUrXr9wF/YFltgTBYS0tKslPEKr6AekjqDW2dbn1L1xmjGR+9GiKu4ajxovnrDbwxAKdHjW8jNcwfz8PAz4A==", "dev": true, "funding": [ { @@ -653,17 +677,18 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "peer": true, "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", "hash.js": "1.1.7" } }, "node_modules/@ethersproject/signing-key": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", - "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.8.0.tgz", + "integrity": "sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w==", "funding": [ { "type": "individual", @@ -674,19 +699,20 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", "bn.js": "^5.2.1", - "elliptic": "6.5.4", + "elliptic": "6.6.1", "hash.js": "1.1.7" } }, "node_modules/@ethersproject/solidity": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", - "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.8.0.tgz", + "integrity": "sha512-4CxFeCgmIWamOHwYN9d+QWGxye9qQLilpgTU0XhYs1OahkclF+ewO+3V1U0mvpiuQxm5EHHmv8f7ClVII8EHsA==", "dev": true, "funding": [ { @@ -698,20 +724,21 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "peer": true, "dependencies": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/sha2": "^5.7.0", - "@ethersproject/strings": "^5.7.0" + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/sha2": "^5.8.0", + "@ethersproject/strings": "^5.8.0" } }, "node_modules/@ethersproject/strings": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", - "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.8.0.tgz", + "integrity": "sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg==", "funding": [ { "type": "individual", @@ -722,16 +749,17 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/logger": "^5.7.0" + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/logger": "^5.8.0" } }, "node_modules/@ethersproject/transactions": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", - "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.8.0.tgz", + "integrity": "sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg==", "funding": [ { "type": "individual", @@ -742,22 +770,23 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "dependencies": { - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/rlp": "^5.7.0", - "@ethersproject/signing-key": "^5.7.0" + "@ethersproject/address": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/rlp": "^5.8.0", + "@ethersproject/signing-key": "^5.8.0" } }, "node_modules/@ethersproject/units": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", - "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.8.0.tgz", + "integrity": "sha512-lxq0CAnc5kMGIiWW4Mr041VT8IhNM+Pn5T3haO74XZWFulk7wH1Gv64HqE96hT4a7iiNMdOCFEBgaxWuk8ETKQ==", "dev": true, "funding": [ { @@ -769,17 +798,18 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "peer": true, "dependencies": { - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/constants": "^5.7.0", - "@ethersproject/logger": "^5.7.0" + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/constants": "^5.8.0", + "@ethersproject/logger": "^5.8.0" } }, "node_modules/@ethersproject/wallet": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", - "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.8.0.tgz", + "integrity": "sha512-G+jnzmgg6UxurVKRKvw27h0kvG75YKXZKdlLYmAHeF32TGUzHkOFd7Zn6QHOTYRFWnfjtSSFjBowKo7vfrXzPA==", "dev": true, "funding": [ { @@ -791,29 +821,30 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "peer": true, - "dependencies": { - "@ethersproject/abstract-provider": "^5.7.0", - "@ethersproject/abstract-signer": "^5.7.0", - "@ethersproject/address": "^5.7.0", - "@ethersproject/bignumber": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/hdnode": "^5.7.0", - "@ethersproject/json-wallets": "^5.7.0", - "@ethersproject/keccak256": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/random": "^5.7.0", - "@ethersproject/signing-key": "^5.7.0", - "@ethersproject/transactions": "^5.7.0", - "@ethersproject/wordlists": "^5.7.0" + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/abstract-provider": "^5.8.0", + "@ethersproject/abstract-signer": "^5.8.0", + "@ethersproject/address": "^5.8.0", + "@ethersproject/bignumber": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/hash": "^5.8.0", + "@ethersproject/hdnode": "^5.8.0", + "@ethersproject/json-wallets": "^5.8.0", + "@ethersproject/keccak256": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/random": "^5.8.0", + "@ethersproject/signing-key": "^5.8.0", + "@ethersproject/transactions": "^5.8.0", + "@ethersproject/wordlists": "^5.8.0" } }, "node_modules/@ethersproject/web": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", - "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.8.0.tgz", + "integrity": "sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw==", "funding": [ { "type": "individual", @@ -824,18 +855,19 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "dependencies": { - "@ethersproject/base64": "^5.7.0", - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/strings": "^5.7.0" + "@ethersproject/base64": "^5.8.0", + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/strings": "^5.8.0" } }, "node_modules/@ethersproject/wordlists": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", - "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.8.0.tgz", + "integrity": "sha512-2df9bbXicZws2Sb5S6ET493uJ0Z84Fjr3pC4tu/qlnZERibZCeUVuqdtt+7Tv9xxhUxHoIekIA7avrKUWHrezg==", "dev": true, "funding": [ { @@ -847,13 +879,14 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], + "license": "MIT", "peer": true, "dependencies": { - "@ethersproject/bytes": "^5.7.0", - "@ethersproject/hash": "^5.7.0", - "@ethersproject/logger": "^5.7.0", - "@ethersproject/properties": "^5.7.0", - "@ethersproject/strings": "^5.7.0" + "@ethersproject/bytes": "^5.8.0", + "@ethersproject/hash": "^5.8.0", + "@ethersproject/logger": "^5.8.0", + "@ethersproject/properties": "^5.8.0", + "@ethersproject/strings": "^5.8.0" } }, "node_modules/@fastify/busboy": { @@ -892,21 +925,6 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/@metamask/eth-sig-util": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz", - "integrity": "sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==", - "dependencies": { - "ethereumjs-abi": "^0.6.8", - "ethereumjs-util": "^6.2.1", - "ethjs-util": "^0.1.6", - "tweetnacl": "^1.0.3", - "tweetnacl-util": "^0.15.1" - }, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/@noble/curves": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.2.0.tgz", @@ -990,183 +1008,86 @@ } }, "node_modules/@nomicfoundation/edr": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.6.5.tgz", - "integrity": "sha512-tAqMslLP+/2b2sZP4qe9AuGxG3OkQ5gGgHE4isUuq6dUVjwCRPFhAOhpdFl+OjY5P3yEv3hmq9HjUGRa2VNjng==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr/-/edr-0.10.0.tgz", + "integrity": "sha512-ed9qHSNssgh+0hYUx4ilDoMxxgf/sNT8SjnzgmA5A/LSXHaq2ax68bkdQ8otLYTlxHCO9BS5Nhb8bfajV4FZeA==", + "license": "MIT", "dependencies": { - "@nomicfoundation/edr-darwin-arm64": "0.6.5", - "@nomicfoundation/edr-darwin-x64": "0.6.5", - "@nomicfoundation/edr-linux-arm64-gnu": "0.6.5", - "@nomicfoundation/edr-linux-arm64-musl": "0.6.5", - "@nomicfoundation/edr-linux-x64-gnu": "0.6.5", - "@nomicfoundation/edr-linux-x64-musl": "0.6.5", - "@nomicfoundation/edr-win32-x64-msvc": "0.6.5" + "@nomicfoundation/edr-darwin-arm64": "0.10.0", + "@nomicfoundation/edr-darwin-x64": "0.10.0", + "@nomicfoundation/edr-linux-arm64-gnu": "0.10.0", + "@nomicfoundation/edr-linux-arm64-musl": "0.10.0", + "@nomicfoundation/edr-linux-x64-gnu": "0.10.0", + "@nomicfoundation/edr-linux-x64-musl": "0.10.0", + "@nomicfoundation/edr-win32-x64-msvc": "0.10.0" }, "engines": { "node": ">= 18" } }, "node_modules/@nomicfoundation/edr-darwin-arm64": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.6.5.tgz", - "integrity": "sha512-A9zCCbbNxBpLgjS1kEJSpqxIvGGAX4cYbpDYCU2f3jVqOwaZ/NU761y1SvuCRVpOwhoCXqByN9b7HPpHi0L4hw==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-arm64/-/edr-darwin-arm64-0.10.0.tgz", + "integrity": "sha512-n0N+CVM4LKN9QeGZ5irr94Q4vwSs4u7W6jfuhNLmx1cpUxwE9RpeW+ym93JXDv62iVsbekeI5VsUEBHy0hymtA==", + "license": "MIT", "engines": { "node": ">= 18" } }, "node_modules/@nomicfoundation/edr-darwin-x64": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.6.5.tgz", - "integrity": "sha512-x3zBY/v3R0modR5CzlL6qMfFMdgwd6oHrWpTkuuXnPFOX8SU31qq87/230f4szM+ukGK8Hi+mNq7Ro2VF4Fj+w==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-darwin-x64/-/edr-darwin-x64-0.10.0.tgz", + "integrity": "sha512-nmImWM/3qWopYzOmicMzK/MF3rFKpm2Biuc8GpQYTLjdXhmItpP9JwEPyjbAWv/1HI09C2pRzgNzKfTxoIgJ6w==", + "license": "MIT", "engines": { "node": ">= 18" } }, "node_modules/@nomicfoundation/edr-linux-arm64-gnu": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.6.5.tgz", - "integrity": "sha512-HGpB8f1h8ogqPHTyUpyPRKZxUk2lu061g97dOQ/W4CxevI0s/qiw5DB3U3smLvSnBHKOzYS1jkxlMeGN01ky7A==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-gnu/-/edr-linux-arm64-gnu-0.10.0.tgz", + "integrity": "sha512-B/N1IyrCU7J6H4QckkQ1cSWAq1jSrJcXpO8GzRaQD1bgOOvg8wrUOrCD+Mfw7MLa6+X9vdZoXtPZOaaOQ9LmhA==", + "license": "MIT", "engines": { "node": ">= 18" } }, "node_modules/@nomicfoundation/edr-linux-arm64-musl": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.6.5.tgz", - "integrity": "sha512-ESvJM5Y9XC03fZg9KaQg3Hl+mbx7dsSkTIAndoJS7X2SyakpL9KZpOSYrDk135o8s9P9lYJdPOyiq+Sh+XoCbQ==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-arm64-musl/-/edr-linux-arm64-musl-0.10.0.tgz", + "integrity": "sha512-NA9DFLB0LzcKy9mTCUzgnRDbmmSfW0CdO22ySwOy+MKt4Cr9eJi+XR5ZH933Rxpi6BWNkSPeS2ECETE25sJT3w==", + "license": "MIT", "engines": { "node": ">= 18" } }, "node_modules/@nomicfoundation/edr-linux-x64-gnu": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.6.5.tgz", - "integrity": "sha512-HCM1usyAR1Ew6RYf5AkMYGvHBy64cPA5NMbaeY72r0mpKaH3txiMyydcHibByOGdQ8iFLWpyUdpl1egotw+Tgg==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-gnu/-/edr-linux-x64-gnu-0.10.0.tgz", + "integrity": "sha512-bDrbRTA9qZ9wSw5mqa8VpLFbf6ue2Z4qmRd08404eKm8RyBEFxjdHflFzCx46gz/Td0e+GLXy6KTVDj5D29r8w==", + "license": "MIT", "engines": { "node": ">= 18" } }, "node_modules/@nomicfoundation/edr-linux-x64-musl": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.6.5.tgz", - "integrity": "sha512-nB2uFRyczhAvWUH7NjCsIO6rHnQrof3xcCe6Mpmnzfl2PYcGyxN7iO4ZMmRcQS7R1Y670VH6+8ZBiRn8k43m7A==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-linux-x64-musl/-/edr-linux-x64-musl-0.10.0.tgz", + "integrity": "sha512-wx7yOlC/hx4N1xuIeh5cAebpzCTx8ZH8/z0IyYMf2t4v52KHERz4IyzBz5OLfd+0IqTRg8ZU5EnFBacIoPeP/g==", + "license": "MIT", "engines": { "node": ">= 18" } }, "node_modules/@nomicfoundation/edr-win32-x64-msvc": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.6.5.tgz", - "integrity": "sha512-B9QD/4DSSCFtWicO8A3BrsnitO1FPv7axB62wq5Q+qeJ50yJlTmyeGY3cw62gWItdvy2mh3fRM6L1LpnHiB77A==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@nomicfoundation/edr-win32-x64-msvc/-/edr-win32-x64-msvc-0.10.0.tgz", + "integrity": "sha512-DpBdVMimb+BUEs0E+nLGQ5JFHdGHyxQQNA+nh9V1eKtgarsV21S6br/d1vlQBMLQqkIzwmc6n+/O9Zjk2KfB3g==", + "license": "MIT", "engines": { "node": ">= 18" } }, - "node_modules/@nomicfoundation/ethereumjs-common": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-common/-/ethereumjs-common-4.0.4.tgz", - "integrity": "sha512-9Rgb658lcWsjiicr5GzNCjI1llow/7r0k50dLL95OJ+6iZJcVbi15r3Y0xh2cIO+zgX0WIHcbzIu6FeQf9KPrg==", - "dependencies": { - "@nomicfoundation/ethereumjs-util": "9.0.4" - } - }, - "node_modules/@nomicfoundation/ethereumjs-rlp": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-rlp/-/ethereumjs-rlp-5.0.4.tgz", - "integrity": "sha512-8H1S3s8F6QueOc/X92SdrA4RDenpiAEqMg5vJH99kcQaCy/a3Q6fgseo75mgWlbanGJXSlAPtnCeG9jvfTYXlw==", - "bin": { - "rlp": "bin/rlp.cjs" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@nomicfoundation/ethereumjs-tx": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-tx/-/ethereumjs-tx-5.0.4.tgz", - "integrity": "sha512-Xjv8wAKJGMrP1f0n2PeyfFCCojHd7iS3s/Ab7qzF1S64kxZ8Z22LCMynArYsVqiFx6rzYy548HNVEyI+AYN/kw==", - "dependencies": { - "@nomicfoundation/ethereumjs-common": "4.0.4", - "@nomicfoundation/ethereumjs-rlp": "5.0.4", - "@nomicfoundation/ethereumjs-util": "9.0.4", - "ethereum-cryptography": "0.1.3" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "c-kzg": "^2.1.2" - }, - "peerDependenciesMeta": { - "c-kzg": { - "optional": true - } - } - }, - "node_modules/@nomicfoundation/ethereumjs-tx/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - }, - "node_modules/@nomicfoundation/ethereumjs-util": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ethereumjs-util/-/ethereumjs-util-9.0.4.tgz", - "integrity": "sha512-sLOzjnSrlx9Bb9EFNtHzK/FJFsfg2re6bsGqinFinH1gCqVfz9YYlXiMWwDM4C/L4ywuHFCYwfKTVr/QHQcU0Q==", - "dependencies": { - "@nomicfoundation/ethereumjs-rlp": "5.0.4", - "ethereum-cryptography": "0.1.3" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "c-kzg": "^2.1.2" - }, - "peerDependenciesMeta": { - "c-kzg": { - "optional": true - } - } - }, - "node_modules/@nomicfoundation/ethereumjs-util/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - }, "node_modules/@nomicfoundation/hardhat-chai-matchers": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-chai-matchers/-/hardhat-chai-matchers-2.0.8.tgz", @@ -1202,12 +1123,13 @@ } }, "node_modules/@nomicfoundation/hardhat-ignition": { - "version": "0.15.8", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition/-/hardhat-ignition-0.15.8.tgz", - "integrity": "sha512-TN8TFQokcd7VyqGfbXO+KS8Q4K/gmsOFlv8dPnt/N596AncgV2Igxh5C3O+KVez11PDHNqoj1JzcDzzNVHrIRw==", + "version": "0.15.11", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition/-/hardhat-ignition-0.15.11.tgz", + "integrity": "sha512-OXebmK9FCMwwbb4mIeHBbVFFicAGgyGKJT2zrONrpixrROxrVs6KEi1gzsiN25qtQhCQePt8BTjjYrgy86Dfxg==", + "license": "MIT", "dependencies": { - "@nomicfoundation/ignition-core": "^0.15.8", - "@nomicfoundation/ignition-ui": "^0.15.8", + "@nomicfoundation/ignition-core": "^0.15.11", + "@nomicfoundation/ignition-ui": "^0.15.11", "chalk": "^4.0.0", "debug": "^4.3.2", "fs-extra": "^10.0.0", @@ -1220,15 +1142,16 @@ } }, "node_modules/@nomicfoundation/hardhat-ignition-ethers": { - "version": "0.15.8", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition-ethers/-/hardhat-ignition-ethers-0.15.8.tgz", - "integrity": "sha512-5Ev8cXBKgqqOsFXxWe8iijsRabWGd/Vclx3SC903KeKVePdssVsZcYTtRNRcIwRcPJ0RIKJPIZz7MNDo64l3+w==", + "version": "0.15.11", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-ignition-ethers/-/hardhat-ignition-ethers-0.15.11.tgz", + "integrity": "sha512-srXzvf7qCDHLrnvQWtpVA9gWpcbp4BcnsOqJt6ISet9OlUnxk4GgRMbdFq4YpM48bHQTX397jS9yk1AtJCjt/g==", "dev": true, + "license": "MIT", "peer": true, "peerDependencies": { "@nomicfoundation/hardhat-ethers": "^3.0.4", - "@nomicfoundation/hardhat-ignition": "^0.15.8", - "@nomicfoundation/ignition-core": "^0.15.8", + "@nomicfoundation/hardhat-ignition": "^0.15.11", + "@nomicfoundation/ignition-core": "^0.15.11", "ethers": "^6.7.0", "hardhat": "^2.18.0" } @@ -1270,7 +1193,7 @@ "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-network-helpers/-/hardhat-network-helpers-1.0.12.tgz", "integrity": "sha512-xTNQNI/9xkHvjmCJnJOTyqDSl8uq1rKb2WOVmixQxFtRd7Oa3ecO8zM0cyC2YmOK+jHB9WPZ+F/ijkHg1CoORA==", "dev": true, - "peer": true, + "license": "MIT", "dependencies": { "ethereumjs-util": "^7.1.4" }, @@ -1283,7 +1206,6 @@ "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", "dev": true, - "peer": true, "dependencies": { "@types/pbkdf2": "^3.0.0", "@types/secp256k1": "^4.0.1", @@ -1307,7 +1229,6 @@ "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", "dev": true, - "peer": true, "dependencies": { "@types/bn.js": "^5.1.0", "bn.js": "^5.1.2", @@ -1346,9 +1267,10 @@ } }, "node_modules/@nomicfoundation/hardhat-verify": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-verify/-/hardhat-verify-2.0.12.tgz", - "integrity": "sha512-Lg3Nu7DCXASQRVI/YysjuAX2z8jwOCbS0w5tz2HalWGSTZThqA0v9N0v0psHbKNqzPJa8bNOeapIVSziyJTnAg==", + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@nomicfoundation/hardhat-verify/-/hardhat-verify-2.0.13.tgz", + "integrity": "sha512-i57GX1sC0kYGyRVnbQrjjyBTpWTKgrvKC+jH8CMKV6gHp959Upb8lKaZ58WRHIU0espkulTxLnacYeUDirwJ2g==", + "license": "MIT", "peer": true, "dependencies": { "@ethersproject/abi": "^5.1.2", @@ -1366,9 +1288,10 @@ } }, "node_modules/@nomicfoundation/ignition-core": { - "version": "0.15.8", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ignition-core/-/ignition-core-0.15.8.tgz", - "integrity": "sha512-U+CmTjKU9uwvh7qIabqboy/K/sDoClDgpsFRHoFvAj87DPDkXYb/mZBSkXPTU1wxTxrW6GTFE4lG3e7LAyF+kw==", + "version": "0.15.11", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ignition-core/-/ignition-core-0.15.11.tgz", + "integrity": "sha512-PeYKRlrQ0koT72yRnlyyG66cXMFiv5X/cIB8hBFPl3ekeg5tPXcHAgs/VZhOsgwEox4ejphTtItLESb1IDBw0w==", + "license": "MIT", "dependencies": { "@ethersproject/address": "5.6.1", "@nomicfoundation/solidity-analyzer": "^0.1.1", @@ -1447,9 +1370,9 @@ } }, "node_modules/@nomicfoundation/ignition-ui": { - "version": "0.15.8", - "resolved": "https://registry.npmjs.org/@nomicfoundation/ignition-ui/-/ignition-ui-0.15.8.tgz", - "integrity": "sha512-VUD5MsWrrv7E2P0AJO01pV8w8m66Du0uwBKXM0oUV5DRIzqm6eYHt9eCDb1KBINDpiFxOQiuyWQMdeKxgPp3qw==" + "version": "0.15.11", + "resolved": "https://registry.npmjs.org/@nomicfoundation/ignition-ui/-/ignition-ui-0.15.11.tgz", + "integrity": "sha512-VPOVl5xqCKhYCyPOQlposx+stjCwqXQ+BCs5lnw/f2YUfgII+G5Ye0JfHiJOfCJGmqyS03WertBslcj9zQg50A==" }, "node_modules/@nomicfoundation/solidity-analyzer": { "version": "0.1.2", @@ -1866,6 +1789,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.2.tgz", "integrity": "sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==", + "dev": true, "dependencies": { "@types/node": "*" } @@ -1888,6 +1812,7 @@ "version": "4.0.6", "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.6.tgz", "integrity": "sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==", + "dev": true, "dependencies": { "@types/node": "*" } @@ -2163,10 +2088,11 @@ } }, "node_modules/axios": { - "version": "1.7.9", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", - "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz", + "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "follow-redirects": "^1.15.6", @@ -2183,6 +2109,7 @@ "version": "3.0.10", "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.10.tgz", "integrity": "sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==", + "dev": true, "dependencies": { "safe-buffer": "^5.0.1" } @@ -2192,6 +2119,7 @@ "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", "dev": true, + "license": "MIT", "peer": true }, "node_modules/binary-extensions": { @@ -2208,7 +2136,8 @@ "node_modules/blakejs": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", - "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==" + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==", + "dev": true }, "node_modules/bn.js": { "version": "5.2.1", @@ -2280,6 +2209,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, "dependencies": { "buffer-xor": "^1.0.3", "cipher-base": "^1.0.0", @@ -2293,6 +2223,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "dev": true, "dependencies": { "base-x": "^3.0.2" } @@ -2301,6 +2232,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "dev": true, "dependencies": { "bs58": "^4.0.0", "create-hash": "^1.1.0", @@ -2315,7 +2247,23 @@ "node_modules/buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true + }, + "node_modules/bufferutil": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.9.tgz", + "integrity": "sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } }, "node_modules/bytes": { "version": "3.1.2", @@ -2345,10 +2293,11 @@ } }, "node_modules/call-bind-apply-helpers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", - "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { "es-errors": "^1.3.0", @@ -2481,6 +2430,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz", "integrity": "sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==", + "dev": true, "dependencies": { "inherits": "^2.0.4", "safe-buffer": "^5.2.1" @@ -2839,6 +2789,7 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, "dependencies": { "cipher-base": "^1.0.1", "inherits": "^2.0.1", @@ -2851,6 +2802,7 @@ "version": "1.1.7", "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, "dependencies": { "cipher-base": "^1.0.3", "create-hash": "^1.1.0", @@ -3023,13 +2975,14 @@ } }, "node_modules/dunder-proto": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.0.tgz", - "integrity": "sha512-9+Sj30DIu+4KvHqMfLUGLFYL2PkURSYMVXJyXe92nFRvlYq5hBjLEhblKB+vkd/WVlUYMWigiY07T91Fkk0+4A==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "call-bind-apply-helpers": "^1.0.0", + "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" }, @@ -3038,9 +2991,10 @@ } }, "node_modules/elliptic": { - "version": "6.5.4", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", - "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "license": "MIT", "dependencies": { "bn.js": "^4.11.9", "brorand": "^1.1.0", @@ -3052,9 +3006,10 @@ } }, "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==" + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.2.tgz", + "integrity": "sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==", + "license": "MIT" }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -3101,6 +3056,20 @@ "node": ">= 0.4" } }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -3222,9 +3191,9 @@ } }, "node_modules/eth-gas-reporter/node_modules/ethers": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", - "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.8.0.tgz", + "integrity": "sha512-DUq+7fHrCg1aPDFCHx6UIPb3nmt2XMpM7Y/g2gLhsl3lIBqeAfOJIl1qEvRf2uq3BiKxmh6Fh5pfp2ieyek7Kg==", "dev": true, "funding": [ { @@ -3236,38 +3205,39 @@ "url": "https://www.buymeacoffee.com/ricmoo" } ], - "peer": true, - "dependencies": { - "@ethersproject/abi": "5.7.0", - "@ethersproject/abstract-provider": "5.7.0", - "@ethersproject/abstract-signer": "5.7.0", - "@ethersproject/address": "5.7.0", - "@ethersproject/base64": "5.7.0", - "@ethersproject/basex": "5.7.0", - "@ethersproject/bignumber": "5.7.0", - "@ethersproject/bytes": "5.7.0", - "@ethersproject/constants": "5.7.0", - "@ethersproject/contracts": "5.7.0", - "@ethersproject/hash": "5.7.0", - "@ethersproject/hdnode": "5.7.0", - "@ethersproject/json-wallets": "5.7.0", - "@ethersproject/keccak256": "5.7.0", - "@ethersproject/logger": "5.7.0", - "@ethersproject/networks": "5.7.1", - "@ethersproject/pbkdf2": "5.7.0", - "@ethersproject/properties": "5.7.0", - "@ethersproject/providers": "5.7.2", - "@ethersproject/random": "5.7.0", - "@ethersproject/rlp": "5.7.0", - "@ethersproject/sha2": "5.7.0", - "@ethersproject/signing-key": "5.7.0", - "@ethersproject/solidity": "5.7.0", - "@ethersproject/strings": "5.7.0", - "@ethersproject/transactions": "5.7.0", - "@ethersproject/units": "5.7.0", - "@ethersproject/wallet": "5.7.0", - "@ethersproject/web": "5.7.1", - "@ethersproject/wordlists": "5.7.0" + "license": "MIT", + "peer": true, + "dependencies": { + "@ethersproject/abi": "5.8.0", + "@ethersproject/abstract-provider": "5.8.0", + "@ethersproject/abstract-signer": "5.8.0", + "@ethersproject/address": "5.8.0", + "@ethersproject/base64": "5.8.0", + "@ethersproject/basex": "5.8.0", + "@ethersproject/bignumber": "5.8.0", + "@ethersproject/bytes": "5.8.0", + "@ethersproject/constants": "5.8.0", + "@ethersproject/contracts": "5.8.0", + "@ethersproject/hash": "5.8.0", + "@ethersproject/hdnode": "5.8.0", + "@ethersproject/json-wallets": "5.8.0", + "@ethersproject/keccak256": "5.8.0", + "@ethersproject/logger": "5.8.0", + "@ethersproject/networks": "5.8.0", + "@ethersproject/pbkdf2": "5.8.0", + "@ethersproject/properties": "5.8.0", + "@ethersproject/providers": "5.8.0", + "@ethersproject/random": "5.8.0", + "@ethersproject/rlp": "5.8.0", + "@ethersproject/sha2": "5.8.0", + "@ethersproject/signing-key": "5.8.0", + "@ethersproject/solidity": "5.8.0", + "@ethersproject/strings": "5.8.0", + "@ethersproject/transactions": "5.8.0", + "@ethersproject/units": "5.8.0", + "@ethersproject/wallet": "5.8.0", + "@ethersproject/web": "5.8.0", + "@ethersproject/wordlists": "5.8.0" } }, "node_modules/ethereum-bloom-filters": { @@ -3304,70 +3274,6 @@ "@scure/bip39": "1.1.1" } }, - "node_modules/ethereumjs-abi": { - "version": "0.6.8", - "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz", - "integrity": "sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==", - "deprecated": "This library has been deprecated and usage is discouraged.", - "dependencies": { - "bn.js": "^4.11.8", - "ethereumjs-util": "^6.0.0" - } - }, - "node_modules/ethereumjs-abi/node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==" - }, - "node_modules/ethereumjs-util": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", - "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", - "dependencies": { - "@types/bn.js": "^4.11.3", - "bn.js": "^4.11.0", - "create-hash": "^1.1.2", - "elliptic": "^6.5.2", - "ethereum-cryptography": "^0.1.3", - "ethjs-util": "0.1.6", - "rlp": "^2.2.3" - } - }, - "node_modules/ethereumjs-util/node_modules/@types/bn.js": { - "version": "4.11.6", - "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", - "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/ethereumjs-util/node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==" - }, - "node_modules/ethereumjs-util/node_modules/ethereum-cryptography": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", - "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", - "dependencies": { - "@types/pbkdf2": "^3.0.0", - "@types/secp256k1": "^4.0.1", - "blakejs": "^1.1.0", - "browserify-aes": "^1.2.0", - "bs58check": "^2.1.2", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "hash.js": "^1.1.7", - "keccak": "^3.0.0", - "pbkdf2": "^3.0.17", - "randombytes": "^2.1.0", - "safe-buffer": "^5.1.2", - "scrypt-js": "^3.0.0", - "secp256k1": "^4.0.1", - "setimmediate": "^1.0.5" - } - }, "node_modules/ethers": { "version": "6.13.4", "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.13.4.tgz", @@ -3466,23 +3372,11 @@ "dev": true, "peer": true }, - "node_modules/ethjs-util": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", - "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", - "dependencies": { - "is-hex-prefixed": "1.0.0", - "strip-hex-prefix": "1.0.0" - }, - "engines": { - "node": ">=6.5.0", - "npm": ">=3" - } - }, "node_modules/evp_bytestokey": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, "dependencies": { "md5.js": "^1.3.4", "safe-buffer": "^5.1.1" @@ -3700,20 +3594,23 @@ } }, "node_modules/get-intrinsic": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.5.tgz", - "integrity": "sha512-Y4+pKa7XeRUPWFNvOOYHkRYrfzW07oraURSvjDmRVOJ748OrVmeXtpE4+GCEHncjCjkTxPNRt8kEbxDhsn6VTg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, + "license": "MIT", "peer": true, "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "dunder-proto": "^1.0.0", + "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", + "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", - "hasown": "^2.0.2" + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -3732,6 +3629,21 @@ "node": ">=4" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/ghost-testrpc": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/ghost-testrpc/-/ghost-testrpc-0.0.2.tgz", @@ -3989,16 +3901,14 @@ } }, "node_modules/hardhat": { - "version": "2.22.17", - "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.22.17.tgz", - "integrity": "sha512-tDlI475ccz4d/dajnADUTRc1OJ3H8fpP9sWhXhBPpYsQOg8JHq5xrDimo53UhWPl7KJmAeDCm1bFG74xvpGRpg==", + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/hardhat/-/hardhat-2.23.0.tgz", + "integrity": "sha512-xnORx1LgX46TxylOFme96JmSAIjXuHUVpOlUnaCt8MKMGsgy0NGsfPo5rJI/ncCBPLFLURGfZUQ2Uc6ZYN4kYg==", + "license": "MIT", "dependencies": { + "@ethereumjs/util": "^9.1.0", "@ethersproject/abi": "^5.1.2", - "@metamask/eth-sig-util": "^4.0.0", - "@nomicfoundation/edr": "^0.6.5", - "@nomicfoundation/ethereumjs-common": "4.0.4", - "@nomicfoundation/ethereumjs-tx": "5.0.4", - "@nomicfoundation/ethereumjs-util": "9.0.4", + "@nomicfoundation/edr": "^0.10.0", "@nomicfoundation/solidity-analyzer": "^0.1.0", "@sentry/node": "^5.18.1", "@types/bn.js": "^5.1.0", @@ -4013,7 +3923,6 @@ "enquirer": "^2.3.0", "env-paths": "^2.2.0", "ethereum-cryptography": "^1.0.3", - "ethereumjs-abi": "^0.6.8", "find-up": "^5.0.0", "fp-ts": "1.19.3", "fs-extra": "^7.0.1", @@ -4022,6 +3931,7 @@ "json-stream-stringify": "^3.1.4", "keccak": "^3.0.2", "lodash": "^4.17.11", + "micro-eth-signer": "^0.14.0", "mnemonist": "^0.38.0", "mocha": "^10.0.0", "p-map": "^4.0.0", @@ -4069,6 +3979,94 @@ "hardhat": "^2.0.2" } }, + "node_modules/hardhat/node_modules/@ethereumjs/rlp": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/rlp/-/rlp-5.0.2.tgz", + "integrity": "sha512-DziebCdg4JpGlEqEdGgXmjqcFoJi+JGulUXwEjsZGAscAQ7MyD/7LE/GVCP29vEQxKc7AAwjT3A2ywHp2xfoCA==", + "license": "MPL-2.0", + "bin": { + "rlp": "bin/rlp.cjs" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/hardhat/node_modules/@ethereumjs/util": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@ethereumjs/util/-/util-9.1.0.tgz", + "integrity": "sha512-XBEKsYqLGXLah9PNJbgdkigthkG7TAGvlD/sH12beMXEyHDyigfcbdvHhmLyDWgDyOJn4QwiQUaF7yeuhnjdog==", + "license": "MPL-2.0", + "dependencies": { + "@ethereumjs/rlp": "^5.0.2", + "ethereum-cryptography": "^2.2.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/hardhat/node_modules/@ethereumjs/util/node_modules/ethereum-cryptography": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.2.1.tgz", + "integrity": "sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==", + "license": "MIT", + "dependencies": { + "@noble/curves": "1.4.2", + "@noble/hashes": "1.4.0", + "@scure/bip32": "1.4.0", + "@scure/bip39": "1.3.0" + } + }, + "node_modules/hardhat/node_modules/@noble/curves": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.4.2.tgz", + "integrity": "sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.4.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat/node_modules/@noble/hashes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.4.0.tgz", + "integrity": "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==", + "license": "MIT", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat/node_modules/@scure/bip32": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.4.0.tgz", + "integrity": "sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.4.0", + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/hardhat/node_modules/@scure/bip39": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.3.0.tgz", + "integrity": "sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.4.0", + "@scure/base": "~1.1.6" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -4107,6 +4105,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, "dependencies": { "inherits": "^2.0.4", "readable-stream": "^3.6.0", @@ -4348,6 +4347,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", "integrity": "sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==", + "dev": true, + "peer": true, "engines": { "node": ">=6.5.0", "npm": ">=3" @@ -4593,10 +4594,22 @@ "dev": true, "peer": true }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/md5.js": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, "dependencies": { "hash-base": "^3.0.0", "inherits": "^2.0.1", @@ -4621,6 +4634,44 @@ "node": ">= 8" } }, + "node_modules/micro-eth-signer": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/micro-eth-signer/-/micro-eth-signer-0.14.0.tgz", + "integrity": "sha512-5PLLzHiVYPWClEvZIXXFu5yutzpadb73rnQCpUqIHu3No3coFuWQNfE5tkBQJ7djuLYl6aRLaS0MgWJYGoqiBw==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.8.1", + "@noble/hashes": "~1.7.1", + "micro-packed": "~0.7.2" + } + }, + "node_modules/micro-eth-signer/node_modules/@noble/curves": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.8.2.tgz", + "integrity": "sha512-vnI7V6lFNe0tLAuJMu+2sX+FcL14TaCWy1qiczg1VwRmPrpQCdq5ESXQMqUc2tluRNf6irBXrWbl1mGN8uaU/g==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.7.2" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/micro-eth-signer/node_modules/@noble/hashes": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.7.2.tgz", + "integrity": "sha512-biZ0NUSxyjLLqo6KxEJ1b+C2NAx0wtDoFvCaXHGgUkeHzf3Xc1xKumFKREuT7f7DARNZ/slvYUwFG6B0f2b6hQ==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/micro-ftch": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/micro-ftch/-/micro-ftch-0.3.1.tgz", @@ -4628,6 +4679,27 @@ "dev": true, "peer": true }, + "node_modules/micro-packed": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/micro-packed/-/micro-packed-0.7.3.tgz", + "integrity": "sha512-2Milxs+WNC00TRlem41oRswvw31146GiSaoCT7s3Xi2gMUglW5QBeqlQaZeHr5tJx9nm3i57LNXPqxOOaWtTYg==", + "license": "MIT", + "dependencies": { + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/micro-packed/node_modules/@scure/base": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.5.tgz", + "integrity": "sha512-9rE6EOVeIQzt5TSu4v+K523F8u6DhBsoZWPGKlnCshhlDhy0kJzUX4V+tr2dWmzF1GdekvThABoEQBGBQI7xZw==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", @@ -5092,6 +5164,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dev": true, "dependencies": { "create-hash": "^1.1.2", "create-hmac": "^1.1.4", @@ -5414,6 +5487,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, "dependencies": { "hash-base": "^3.0.0", "inherits": "^2.0.1" @@ -5423,6 +5497,7 @@ "version": "2.2.7", "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", + "dev": true, "dependencies": { "bn.js": "^5.2.0" }, @@ -5617,12 +5692,14 @@ "node_modules/scrypt-js": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", - "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==", + "dev": true }, "node_modules/secp256k1": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.4.tgz", "integrity": "sha512-6JfvwvjUOn8F/jUoBY2Q1v5WY5XS+rj8qSe0v8Y4ezH4InLgTEeOOPQsRll9OV429Pvo6BCHGavIyJfr3TAhsw==", + "dev": true, "hasInstallScript": true, "dependencies": { "elliptic": "^6.5.7", @@ -5633,29 +5710,11 @@ "node": ">=18.0.0" } }, - "node_modules/secp256k1/node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==" - }, - "node_modules/secp256k1/node_modules/elliptic": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", - "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, "node_modules/secp256k1/node_modules/node-addon-api": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", - "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==" + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", + "dev": true }, "node_modules/semver": { "version": "6.3.1", @@ -5694,7 +5753,8 @@ "node_modules/setimmediate": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true }, "node_modules/setprototypeof": { "version": "1.2.0", @@ -5705,6 +5765,7 @@ "version": "2.4.11", "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, "dependencies": { "inherits": "^2.0.1", "safe-buffer": "^5.0.1" @@ -5871,10 +5932,11 @@ } }, "node_modules/solidity-coverage": { - "version": "0.8.14", - "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.14.tgz", - "integrity": "sha512-ItAAObe5GaEOp20kXC2BZRnph+9P7Rtoqg2mQc2SXGEHgSDF2wWd1Wxz3ntzQWXkbCtIIGdJT918HG00cObwbA==", + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/solidity-coverage/-/solidity-coverage-0.8.15.tgz", + "integrity": "sha512-qH7290NKww4/t/qFvnSEePEzON0k025IGVlwc8wo8Q6p+h1Tt6fV2M0k3yfsps3TomZYTROsfPXjx7MSnwD5uA==", "dev": true, + "license": "ISC", "peer": true, "dependencies": { "@ethersproject/abi": "^5.0.9", @@ -6119,6 +6181,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", "integrity": "sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==", + "dev": true, + "peer": true, "dependencies": { "is-hex-prefixed": "1.0.0" }, @@ -6412,16 +6476,6 @@ "resolved": "https://registry.npmjs.org/tsort/-/tsort-0.0.1.tgz", "integrity": "sha512-Tyrf5mxF8Ofs1tNoxA13lFeZ2Zrbd6cKbuH3V+MQ5sb6DtBj5FjrXVsRWT8YvNAQTqNoz66dz1WsbigI22aEnw==" }, - "node_modules/tweetnacl": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", - "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" - }, - "node_modules/tweetnacl-util": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", - "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==" - }, "node_modules/type-check": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", @@ -6586,9 +6640,10 @@ } }, "node_modules/undici": { - "version": "5.28.4", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.28.4.tgz", - "integrity": "sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==", + "version": "5.29.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz", + "integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==", + "license": "MIT", "dependencies": { "@fastify/busboy": "^2.0.0" }, @@ -6617,6 +6672,21 @@ "node": ">= 0.8" } }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, "node_modules/utf8": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", diff --git a/challenge-1-vesting/package.json b/challenge-1-vesting/package.json index e3d28da..f7e028a 100644 --- a/challenge-1-vesting/package.json +++ b/challenge-1-vesting/package.json @@ -10,6 +10,7 @@ "license": "ISC", "description": "", "devDependencies": { + "@nomicfoundation/hardhat-network-helpers": "^1.0.12", "@nomicfoundation/hardhat-toolbox": "^5.0.0", "hardhat": "^2.22.17" }, diff --git a/challenge-1-vesting/test/vesting.ts b/challenge-1-vesting/test/vesting.ts index 803c7be..75c9b31 100644 --- a/challenge-1-vesting/test/vesting.ts +++ b/challenge-1-vesting/test/vesting.ts @@ -87,7 +87,7 @@ describe("TokenVesting", function () { vestingDuration, startTime ) - ).to.be.revertedWith("Beneficiary not whitelisted"); + ).to.be.revertedWith("beneficiary not whitelisted"); }); }); @@ -108,7 +108,7 @@ describe("TokenVesting", function () { await time.increase(60); // Move past start time await expect( vesting.connect(beneficiary).claimVestedTokens() - ).to.be.revertedWith("No tokens to claim"); + ).to.be.revertedWith("no tokens available to claim"); }); it("Should allow claiming after cliff", async function () { diff --git a/challenge-2-yield-farm/contracts/yeild.sol b/challenge-2-yield-farm/contracts/yeild.sol index 421496a..50137eb 100644 --- a/challenge-2-yield-farm/contracts/yeild.sol +++ b/challenge-2-yield-farm/contracts/yeild.sol @@ -17,136 +17,199 @@ import "@openzeppelin/contracts/access/Ownable.sol"; */ contract YieldFarm is ReentrancyGuard, Ownable { + // LP token that users can stake IERC20 public lpToken; - // Token given as reward + // token given as reward IERC20 public rewardToken; - // Reward rate per second - uint256 public rewardRate; - - // Last update time - uint256 public lastUpdateTime; - - // Reward per token stored - uint256 public rewardPerTokenStored; - - // Total staked amount - uint256 public totalStaked; + uint256 public rewardRate; // reward rate per second + uint256 public lastUpdateTime; // last update time + uint256 public rewardPerTokenStored; // reward per token stored + uint256 public totalStaked; // total staked amount - // User struct to track staking info + // user struct to track staking info struct UserInfo { - uint256 amount; // Amount of LP tokens staked - uint256 startTime; // Time when user started staking - uint256 rewardDebt; // Reward debt - uint256 pendingRewards; // Unclaimed rewards + uint256 amount; // amount of LP tokens staked + uint256 startTime; // time when user started staking + uint256 rewardDebt; // reward debt + uint256 pendingRewards; // unclaimed rewards } - // Mapping of user address to their info + // mapping of user address to their info mapping(address => UserInfo) public userInfo; - // Boost multiplier thresholds (in seconds) + // boost multiplier thresholds uint256 public constant BOOST_THRESHOLD_1 = 7 days; uint256 public constant BOOST_THRESHOLD_2 = 30 days; uint256 public constant BOOST_THRESHOLD_3 = 90 days; - // Events + // Events for staking, withdrawing, claiming rewards, and emergency withdrawal event Staked(address indexed user, uint256 amount); event Withdrawn(address indexed user, uint256 amount); event RewardsClaimed(address indexed user, uint256 amount); event EmergencyWithdrawn(address indexed user, uint256 amount); - // TODO: Implement the following functions - /** * @notice Initialize the contract with the LP token and reward token addresses * @param _lpToken Address of the LP token * @param _rewardToken Address of the reward token * @param _rewardRate Initial reward rate per second */ - constructor( - address _lpToken, - address _rewardToken, - uint256 _rewardRate - ) Ownable(msg.sender) { - // TODO: Initialize contract state + + // constructor to set the LP token, reward token addresses and reward rate + constructor(address _lpToken, address _rewardToken, uint256 _rewardRate) Ownable(msg.sender) { + + require(_lpToken != address(0), "LP token address cannot be zero"); // checks if LP token address is valid + require(_rewardToken != address(0), "reward token address cannot be zero"); // checks if reward token address is valid + + lpToken = IERC20(_lpToken); // initializes the LP token variable + rewardToken = IERC20(_rewardToken); // initializes the reward token variable + rewardRate = _rewardRate; // sets the initial reward rate + lastUpdateTime = block.timestamp; // sets the last update time to current block timestamp } + // function to update the reward for a user function updateReward(address _user) internal { - rewardPerTokenStored = rewardPerToken(); - lastUpdateTime = block.timestamp; + rewardPerTokenStored = rewardPerToken(); // calculate the reward per token + lastUpdateTime = block.timestamp; // update the last update time - if (_user != address(0)) { - UserInfo storage user = userInfo[_user]; - user.pendingRewards = earned(_user); - user.rewardDebt = (user.amount * rewardPerTokenStored) / 1e18; + if (_user != address(0)) { // checks if user is not zero address + UserInfo storage user = userInfo[_user]; // get the user info + user.pendingRewards = earned(_user); // calculate the earned rewards + user.rewardDebt = (user.amount * rewardPerTokenStored) / 1e18; // update the reward debt } } + // function to calculate the reward per token function rewardPerToken() public view returns (uint256) { - // TODO: Implement pending rewards calculation - // Requirements: - // 1. Calculate rewards since last update - // 2. Apply boost multiplier - // 3. Return total pending rewards + + if (totalStaked == 0) { // checks if total staked amount is zero + return rewardPerTokenStored; + } + + uint256 timeElapsed = block.timestamp - lastUpdateTime; // calculate the time elapsed since last update + uint256 reward = (timeElapsed * rewardRate * 1e18) / totalStaked; // calculate the reward based on time elapsed and total staked amount + return rewardPerTokenStored + reward; // return the updated reward per token } + // function to calculate the earned rewards for a user function earned(address _user) public view returns (uint256) { - // TODO: Implement pending rewards calculation - // Requirements: - // 1. Calculate rewards since last update - // 2. Apply boost multiplier - // 3. Return total pending rewards + UserInfo storage user = userInfo[_user]; // get the user info + + if (user.amount == 0) { + return user.pendingRewards; + } + + uint256 currentRewardPerToken = rewardPerToken(); // get the current reward per token + uint256 newRewards = (user.amount * (currentRewardPerToken - user.rewardDebt / user.amount)) / 1e18; // calculate the new rewards + + // apply boost multiplier + uint256 boostMultiplier = calculateBoostMultiplier(_user); // calculate the boost multiplier based on staking duration + newRewards = (newRewards * boostMultiplier) / 100; // apply the boost multiplier + return user.pendingRewards + newRewards; // return the total earned rewards } /** * @notice Stake LP tokens into the farm * @param _amount Amount of LP tokens to stake */ + + // function to stake LP tokens function stake(uint256 _amount) external nonReentrant { - // TODO: Implement staking logic - // Requirements: - // 1. Update rewards - // 2. Transfer LP tokens from user - // 3. Update user info and total staked amount - // 4. Emit Staked event + require(_amount > 0, "cannot stake zero amount"); // checks if amount is greater than zero + + updateReward(msg.sender); // update the reward for the user + + // transfer LP tokens from user to contract + require(lpToken.transferFrom(msg.sender, address(this), _amount), "LP token transfer failed"); + + UserInfo storage user = userInfo[msg.sender]; // get the user info + + // if first time staking, set start time + if (user.amount == 0) { + user.startTime = block.timestamp; + } + + // update user info and total staked amount + user.amount += _amount; + totalStaked += _amount; + + emit Staked(msg.sender, _amount); // emit event for staking } /** * @notice Withdraw staked LP tokens * @param _amount Amount of LP tokens to withdraw */ + + // function to withdraw staked LP tokens function withdraw(uint256 _amount) external nonReentrant { - // TODO: Implement withdrawal logic - // Requirements: - // 1. Update rewards - // 2. Transfer LP tokens to user - // 3. Update user info and total staked amount - // 4. Emit Withdrawn event + UserInfo storage user = userInfo[msg.sender]; + require(user.amount >= _amount, "withdraw amount exceeds balance"); + + updateReward(msg.sender); + + // transfer LP tokens back to user + require(lpToken.transfer(msg.sender, _amount), "LP token transfer failed"); + + // update user info and total staked amount + user.amount -= _amount; + totalStaked -= _amount; + + // if user withdraws everything, reset start time + if (user.amount == 0) { + user.startTime = 0; + } + + emit Withdrawn(msg.sender, _amount); } /** * @notice Claim pending rewards */ + + // function to claim pending rewards function claimRewards() external nonReentrant { - // TODO: Implement reward claiming logic - // Requirements: - // 1. Calculate pending rewards with boost multiplier - // 2. Transfer rewards to user - // 3. Update user reward debt - // 4. Emit RewardsClaimed event + UserInfo storage user = userInfo[msg.sender]; + + updateReward(msg.sender); + + uint256 rewardsToSend = user.pendingRewards; // get the pending rewards + require(rewardsToSend > 0, "no rewards to claim"); // checks if there are rewards to claim + + // reset pending rewards + user.pendingRewards = 0; + + // transfer rewards to user + require(rewardToken.transfer(msg.sender, rewardsToSend), "reward transfer failed"); + + emit RewardsClaimed(msg.sender, rewardsToSend); // emit event for claiming rewards } /** * @notice Emergency withdraw without caring about rewards */ + + // function for emergency withdrawal function emergencyWithdraw() external nonReentrant { - // TODO: Implement emergency withdrawal - // Requirements: - // 1. Transfer all LP tokens back to user - // 2. Reset user info - // 3. Emit EmergencyWithdrawn event + UserInfo storage user = userInfo[msg.sender]; + uint256 amount = user.amount; + + require(amount > 0, "no LP tokens to withdraw"); // checks if there are LP tokens to withdraw + + // reset user info + totalStaked -= amount; // update total staked amount + user.amount = 0; // reset user amount + user.startTime = 0; // reset start time + user.rewardDebt = 0; // reset reward debt + user.pendingRewards = 0; // reset pending rewards + + // transfer LP tokens back to user + require(lpToken.transfer(msg.sender, amount), "LP token transfer failed"); + + emit EmergencyWithdrawn(msg.sender, amount); // emit event for emergency withdrawal } /** @@ -154,24 +217,46 @@ contract YieldFarm is ReentrancyGuard, Ownable { * @param _user Address of the user * @return Boost multiplier (100 = 1x, 150 = 1.5x, etc.) */ - function calculateBoostMultiplier( - address _user - ) public view returns (uint256) { - // TODO: Implement boost multiplier calculation - // Requirements: - // 1. Calculate staking duration - // 2. Return appropriate multiplier based on duration thresholds + + // function to calculate boost multiplier based on staking duration + function calculateBoostMultiplier(address _user) public view returns (uint256) { + + UserInfo storage user = userInfo[_user]; // get the user info + + // if user hasn't staked, return base multiplier + if (user.startTime == 0) { + return 100; // 1x multiplier + } + + uint256 stakingDuration = block.timestamp - user.startTime; // calculate staking duration + + // apply boost based on duration thresholds + if (stakingDuration >= BOOST_THRESHOLD_3) { + return 200; // 2x boost for 90+ days + + } else if (stakingDuration >= BOOST_THRESHOLD_2) { + return 150; // 1.5x boost for 30+ days + + } else if (stakingDuration >= BOOST_THRESHOLD_1) { + return 120; // 1.2x boost for 7+ days + } else { + + return 100; // 1x (no boost) for less than 7 days + } } /** * @notice Update reward rate * @param _newRate New reward rate per second */ + + // function to update the reward rate function updateRewardRate(uint256 _newRate) external onlyOwner { - // TODO: Implement reward rate update logic - // Requirements: - // 1. Update rewards before changing rate - // 2. Set new reward rate + // update rewards for all users before changing the rate + updateReward(address(0)); + + // set new reward rate + rewardRate = _newRate; } /** @@ -179,6 +264,8 @@ contract YieldFarm is ReentrancyGuard, Ownable { * @param _user Address of the user * @return Pending reward amount */ + + // function to view pending rewards for a user function pendingRewards(address _user) external view returns (uint256) { return earned(_user); } diff --git a/challenge-2-yield-farm/package-lock.json b/challenge-2-yield-farm/package-lock.json index 4cbdfb0..d60931b 100644 --- a/challenge-2-yield-farm/package-lock.json +++ b/challenge-2-yield-farm/package-lock.json @@ -9,7 +9,8 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@openzeppelin/contracts": "^5.1.0" + "@openzeppelin/contracts": "^5.1.0", + "dotenv": "^16.5.0" }, "devDependencies": { "@nomicfoundation/hardhat-toolbox": "^5.0.0", @@ -3383,6 +3384,18 @@ "node": ">=8" } }, + "node_modules/dotenv": { + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", + "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/dunder-proto": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.0.tgz", diff --git a/challenge-2-yield-farm/package.json b/challenge-2-yield-farm/package.json index 5366ac8..1d307cb 100644 --- a/challenge-2-yield-farm/package.json +++ b/challenge-2-yield-farm/package.json @@ -17,6 +17,7 @@ "hardhat": "^2.22.17" }, "dependencies": { - "@openzeppelin/contracts": "^5.1.0" + "@openzeppelin/contracts": "^5.1.0", + "dotenv": "^16.5.0" } } diff --git a/challenge-2-yield-farm/test/yeild.ts b/challenge-2-yield-farm/test/yeild.ts index 828753a..59189ef 100644 --- a/challenge-2-yield-farm/test/yeild.ts +++ b/challenge-2-yield-farm/test/yeild.ts @@ -85,7 +85,7 @@ describe("YieldFarm", function () { it("Should not allow staking zero amount", async function () { await expect(yieldFarm.connect(user1).stake(0)).to.be.revertedWith( - "Cannot stake 0" + "cannot stake zero amount" ); }); @@ -115,7 +115,7 @@ describe("YieldFarm", function () { // Test different boost thresholds const tests = [ { days: 3, expectedMultiplier: 100n }, // No boost - { days: 8, expectedMultiplier: 125n }, // 1.25x boost + { days: 8, expectedMultiplier: 120n }, // 1.2x boost { days: 31, expectedMultiplier: 150n }, // 1.5x boost { days: 91, expectedMultiplier: 200n }, // 2x boost ]; @@ -160,7 +160,7 @@ describe("YieldFarm", function () { const tooMuch = stakeAmount * 2n; await expect( yieldFarm.connect(user1).withdraw(tooMuch) - ).to.be.revertedWith("Insufficient balance"); + ).to.be.revertedWith("withdraw amount exceeds balance"); }); it("Should allow emergency withdrawal", async function () { diff --git a/challenge-3-frontend/.gitignore b/challenge-3-frontend/.gitignore index fd3dbb5..7875e01 100644 --- a/challenge-3-frontend/.gitignore +++ b/challenge-3-frontend/.gitignore @@ -1,10 +1,14 @@ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. # dependencies -/node_modules -/.pnp -.pnp.js -.yarn/install-state.gz +node_modules +.pnp +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/versions # testing /coverage @@ -24,9 +28,10 @@ npm-debug.log* yarn-debug.log* yarn-error.log* +.pnpm-debug.log* -# local env files -.env*.local +# env files (can opt-in for committing if needed) +.env # vercel .vercel @@ -34,3 +39,11 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts + +.vscode + +# Docker +postgres_data/ + +# local env files +.env*.local \ No newline at end of file diff --git a/challenge-3-frontend/app/layout.tsx b/challenge-3-frontend/app/layout.tsx index db98252..f274693 100644 --- a/challenge-3-frontend/app/layout.tsx +++ b/challenge-3-frontend/app/layout.tsx @@ -1,14 +1,15 @@ import type { Metadata } from "next"; import { Unbounded } from "next/font/google"; import "./globals.css"; -import '@rainbow-me/rainbowkit/styles.css'; -import { Providers } from '@/app/providers'; +import "@rainbow-me/rainbowkit/styles.css"; +import { Providers } from "@/app/providers"; +import Navbar from "@/components/navbar"; const unbounded = Unbounded({ - subsets: ['latin'], - weight: ['400', '700'], - display: 'swap', -}) + subsets: ["latin"], + weight: ["400", "700"], + display: "swap", +}); export const metadata: Metadata = { title: "DOT UI kit", @@ -21,14 +22,11 @@ export default function RootLayout({ children: React.ReactNode; }>) { return ( - - + + -
- {children} -
+ +
{children}
diff --git a/challenge-3-frontend/app/mint-redeem-lst-bifrost/page.tsx b/challenge-3-frontend/app/mint-redeem-lst-bifrost/page.tsx index aa53c21..d9f4a62 100644 --- a/challenge-3-frontend/app/mint-redeem-lst-bifrost/page.tsx +++ b/challenge-3-frontend/app/mint-redeem-lst-bifrost/page.tsx @@ -1,15 +1,29 @@ "use client"; + import MintRedeemLstBifrost from "@/components/mint-redeem-lst-bifrost"; -import SigpassKit from "@/components/sigpasskit"; -import Navbar from "@/components/navbar"; +import { + Card, + CardHeader, + CardTitle, + CardDescription, +} from "@/components/ui/card"; export default function MintRedeemLstBifrostPage() { return ( -
- - -

Mint/Redeem LST Bifrost

+
+ + + + Mint / Redeem LST Bifrost + + + Swap supported assets for liquid staking tokens or redeem them anytime through + cross-chain Bifrost orders with seamless approvals and progress tracking. + + + +
); -} +} \ No newline at end of file diff --git a/challenge-3-frontend/app/page.tsx b/challenge-3-frontend/app/page.tsx index fb01185..76ae99c 100644 --- a/challenge-3-frontend/app/page.tsx +++ b/challenge-3-frontend/app/page.tsx @@ -1,110 +1,351 @@ -import Image from "next/image"; +"use client"; + import Link from "next/link"; +import { + ArrowRight, + Github, + Layers, + Shield, + Zap, + ChevronRight, +} from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { cn } from "@/lib/utils"; + +/* -------------------------------------------------------------------------- */ +/* Page View */ +/* -------------------------------------------------------------------------- */ -export default function Home() { +export default function HomePage() { return ( -
-
- OpenGuild logo -

Get started by checking out the demos

-
    -
  1. - Wallet -
  2. -
  3. - Send transaction -
  4. -
  5. - Write contract -
  6. -
  7. - Mint/Redeem LST Bifrost -
  8. -
-
- - Vercel logomark - Deploy now - - + + + + + + + + + + + + + ); +} + +/* -------------------------------------------------------------------------- */ +/* Hero */ +/* -------------------------------------------------------------------------- */ + +function Hero() { + return ( +
+ {/* background blur rings */} +
+ ); +} + +/* -------------------------------------------------------------------------- */ +/* Ecosystem Statistics */ +/* -------------------------------------------------------------------------- */ + +function EcosystemStats() { + const stats = [ + { label: "Parachains", value: "50+" }, + { label: "Active Wallets", value: "1.2 M" }, + { label: "Daily TXs", value: "3.5 M" }, + { label: "Relay Chain TPS", value: "10k+" }, + ]; + + return ( +
+
+ {stats.map(({ label, value }) => ( +
+ {value} + {label} +
+ ))} +
+
+ ); +} + +/* -------------------------------------------------------------------------- */ +/* Feature Showcase */ +/* -------------------------------------------------------------------------- */ + +function FeatureShowcase() { + const features = [ + { + title: "Passkey Wallets", + emoji: "🔑", + description: + "Password-less SigpassKit lets users create secure, on-device wallets in seconds.", + }, + { + title: "One-click Staking", + emoji: "📈", + description: + "Stake LP tokens and watch rewards accrue with lightning-fast updates.", + }, + { + title: "Token Vesting", + emoji: "⏳", + description: + "Schedule releases with cliffs & durations—no back-end required.", + }, + { + title: "Gas-less Send", + emoji: "🚀", + description: + "Smart UX with pending, confirming & confirmed states out of the box.", + }, + { + title: "Contract Studio", + emoji: "📝", + description: + "Read & write any smart contract instantly through auto-generated forms.", + }, + { + title: "Responsive Design", + emoji: "💎", + description: + "Tailwind + Radix ensure crystal-clear visuals on every device.", + }, + ]; + + return ( +
+
+ + +
+ {features.map((f) => ( + + ))}
- +
+
+ ); +} + +function FeatureCard({ + title, + emoji, + description, +}: { + title: string; + emoji: string; + description: string; +}) { + return ( +
+ {emoji} +

{title}

+

{description}

); } + +/* -------------------------------------------------------------------------- */ +/* Why Polkadot */ +/* -------------------------------------------------------------------------- */ + +function WhyPolkadot() { + const perks = [ + { + icon: Layers, + title: "True Interoperability", + body: "Seamlessly connect multiple blockchains and unlock cross-chain applications.", + }, + { + icon: Shield, + title: "Shared Security", + body: "Relay-chain validators secure every parachain so you can focus on UX.", + }, + { + icon: Zap, + title: "Instant Upgradeability", + body: "Upgrade your runtime without hard forks and stay ahead of the curve.", + }, + ]; + + return ( +
+
+ +
+ {perks.map(({ icon: Icon, title, body }) => ( +
+ +

{title}

+

{body}

+
+ ))} +
+
+
+ ); +} + +/* -------------------------------------------------------------------------- */ +/* Get Started Timeline */ +/* -------------------------------------------------------------------------- */ + +function GetStartedSteps() { + const steps = [ + { + title: "Install", + body: "Clone the repo & run pnpm install to fetch dependencies.", + }, + { + title: "Configure", + body: "Edit app/providers.tsx with your WalletConnect ID.", + }, + { + title: "Ship", + body: "Deploy to Vercel, IPFS, or your favorite infra—zero extra setup.", + }, + ]; + + return ( +
+
+ +
    + {steps.map((s, i) => ( +
  1. + + {i + 1} + +
    {s.title}
    +

    +

  2. + ))} + {/* connecting line */} +
    +
+
+
+ ); +} + +/* -------------------------------------------------------------------------- */ +/* Call to Action */ +/* -------------------------------------------------------------------------- */ + +function CallToAction() { + return ( +
+
+

+ Ready to craft the next killer Polkadot DApp? +

+

+ Fork the kit, drop in your chain config, and ship to mainnet today. +

+ +
+ ); +} + +/* -------------------------------------------------------------------------- */ +/* Reusable Helpers */ +/* -------------------------------------------------------------------------- */ + +function SectionHeader({ + title, + subtitle, + invert = false, +}: { + title: string; + subtitle: string; + invert?: boolean; +}) { + return ( +
+

+ {title} +

+

+ {subtitle} +

+
+ ); +} diff --git a/challenge-3-frontend/app/providers.tsx b/challenge-3-frontend/app/providers.tsx index 91243fe..b7b16a3 100644 --- a/challenge-3-frontend/app/providers.tsx +++ b/challenge-3-frontend/app/providers.tsx @@ -20,7 +20,11 @@ import { defineChain } from 'viem'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import { WagmiProvider, http, createConfig } from 'wagmi'; import { Provider as JotaiProvider } from 'jotai'; -// import according to docs +import { + LIQUIDITY_POOL_TOKEN_CONTRACT_ADDRESS, + REWARD_TOKEN_CONTRACT_ADDRESS, + YIELD_FARMING_CONTRACT_ADDRESS, +} from "@/lib/config"; export const westendAssetHub = defineChain({ id: 420420421, @@ -40,9 +44,14 @@ export const westendAssetHub = defineChain({ default: { name: 'Explorer', url: 'https://assethub-westend.subscan.io' }, }, contracts: { - multicall3: { - address: '0x5545dec97cb957e83d3e6a1e82fabfacf9764cf1', - blockCreated: 10174702, + lpToken: { + address: LIQUIDITY_POOL_TOKEN_CONTRACT_ADDRESS, + }, + rewardToken: { + address: REWARD_TOKEN_CONTRACT_ADDRESS, + }, + yieldToken: { + address: YIELD_FARMING_CONTRACT_ADDRESS, }, }, }) @@ -67,7 +76,7 @@ const { wallets } = getDefaultWallets(); // initialize and destructure wallets object const config = getDefaultConfig({ - appName: "DOTUI", // Name your app + appName: "OpenGuild", // Name your app projectId: "ddf8cf3ee0013535c3760d4c79c9c8b9", // Enter your WalletConnect Project ID here wallets: [ ...wallets, diff --git a/challenge-3-frontend/app/send-transaction/page.tsx b/challenge-3-frontend/app/send-transaction/page.tsx index 80b85dc..395041e 100644 --- a/challenge-3-frontend/app/send-transaction/page.tsx +++ b/challenge-3-frontend/app/send-transaction/page.tsx @@ -1,15 +1,28 @@ "use client"; + import SendTransaction from "@/components/send-transaction"; -import SigpassKit from "@/components/sigpasskit"; -import Navbar from "@/components/navbar"; +import { + Card, + CardHeader, + CardTitle, + CardDescription, +} from "@/components/ui/card"; export default function SendTransactionPage() { return ( -
- - -

Send Transaction

+
+ + + + Send Transaction + + + Transfer assets securely using passkey or browser wallets, with intuitive validation and real-time status updates from submission to confirmation. + + + +
); -} +} \ No newline at end of file diff --git a/challenge-3-frontend/app/vesting /page.tsx b/challenge-3-frontend/app/vesting /page.tsx new file mode 100644 index 0000000..2cbfa66 --- /dev/null +++ b/challenge-3-frontend/app/vesting /page.tsx @@ -0,0 +1,41 @@ +"use client"; + +import Vesting from "@/components/vesting"; +import { + Card, + CardHeader, + CardTitle, + CardDescription, + CardContent, +} from "@/components/ui/card"; + +export default function VestingPage() { + return ( +
+ {/* headline + how-it-works */} + + + + Token Vesting Studio + + + Craft multi-cliff schedules with custom slice periods and optional + revocability, unlock tokens linearly (or instantly after each cliff), and + monitor real-time release progress with human-readable timestamps. + + + +

How it works

+
    +
  • Cliff — minimum time before any tokens unlock.
  • +
  • Slice period — granularity of unlock distributions.
  • +
  • Revocable — if enabled, the creator can revoke unvested tokens.
  • +
+
+
+ + {/* interactive widgets */} + +
+ ); +} \ No newline at end of file diff --git a/challenge-3-frontend/app/write-contract/page.tsx b/challenge-3-frontend/app/write-contract/page.tsx index 1947eea..569128e 100644 --- a/challenge-3-frontend/app/write-contract/page.tsx +++ b/challenge-3-frontend/app/write-contract/page.tsx @@ -1,14 +1,28 @@ "use client"; + import WriteContract from "@/components/write-contract"; -import SigpassKit from "@/components/sigpasskit"; -import Navbar from "@/components/navbar"; +import { + Card, + CardHeader, + CardTitle, + CardDescription, +} from "@/components/ui/card"; -export default function SendTransactionPage() { +export default function WriteContractPage() { return ( -
- - -

Write Contract

+
+ + + + Contract Studio + + + Interact with any smart contract effortlessly: auto-generated forms, typed + validations, and on-chain transaction tracking—no code required. + + + +
); diff --git a/challenge-3-frontend/app/yield-farm /page.tsx b/challenge-3-frontend/app/yield-farm /page.tsx new file mode 100644 index 0000000..529df86 --- /dev/null +++ b/challenge-3-frontend/app/yield-farm /page.tsx @@ -0,0 +1,37 @@ +"use client"; + +import YieldFarm from "@/components/yield-farm"; +import { + Card, + CardHeader, + CardTitle, + CardDescription, + CardContent, +} from "@/components/ui/card"; + +export default function YieldFarmPage() { + return ( +
+ {/* headline card */} + + + + Yield Farming Dashboard + + + Supply liquidity, lock positions for boosted APR, auto-compound + rewards on-chain, and inspect full emission logs & TVL + analytics—all in one place. + + + + Figures refresh every 15 s from the latest block; past + performance is not a guarantee of future returns. + + + + {/* interactive area */} + +
+ ); +} diff --git a/challenge-3-frontend/components/create-wallet-dialog.tsx b/challenge-3-frontend/components/create-wallet-dialog.tsx new file mode 100644 index 0000000..a07f183 --- /dev/null +++ b/challenge-3-frontend/components/create-wallet-dialog.tsx @@ -0,0 +1,139 @@ +"use client"; + +import { useState, useEffect } from "react"; +import { useAtom } from "jotai"; +import { createWalletDialogOpenAtom } from "@/lib/atoms"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogFooter, + DialogTitle, +} from "@/components/ui/dialog"; +import { Button } from "@/components/ui/button"; +import { KeyRound, Ban, ExternalLink } from "lucide-react"; +import Image from "next/image"; +import { + createSigpassWallet, + checkBrowserWebAuthnSupport, +} from "@/lib/sigpass"; + +/** + * Globally mounted dialog that lets users generate a Sigpass wallet. + * Because it’s outside the drawer hierarchy, it survives when the drawer unmounts. + */ +export default function CreateWalletDialog() { + const [open, setOpen] = useAtom(createWalletDialogOpenAtom); + const [webAuthn, setWebAuthn] = useState(false); + + useEffect(() => { + setWebAuthn(checkBrowserWebAuthnSupport()); + }, []); + + const handleCreate = async () => { + await createSigpassWallet("dapp"); + // Dialog closes only after successful creation + setOpen(false); + }; + + return ( + + + + Create Wallet + + Instantly get a wallet secured by  + + Passkey + + + + +
+

What is a Wallet?

+ +
+ Digital assets icon +
+

+ A Home for your Digital Assets +

+

+ Wallets are used to send, receive, store, and display digital + assets like Polkadot and NFTs. +

+
+
+ +
+ Login icon +
+

A new way to Log In

+

+ Instead of creating new accounts and passwords on every + website, just connect your wallet. +

+
+
+
+ + + + Learn more + + + {webAuthn ? ( + + ) : ( + + )} + + +

+ Powered by  + + Sigpass + +

+
+
+ ); +} diff --git a/challenge-3-frontend/components/mint-redeem-lst-bifrost.tsx b/challenge-3-frontend/components/mint-redeem-lst-bifrost.tsx index 54672c7..cb615b8 100644 --- a/challenge-3-frontend/components/mint-redeem-lst-bifrost.tsx +++ b/challenge-3-frontend/components/mint-redeem-lst-bifrost.tsx @@ -10,8 +10,9 @@ import { useConfig, useWriteContract, useReadContracts, - useAccount + useAccount, } from "wagmi"; +import type { WriteContractErrorType } from "wagmi/actions"; // viem import { parseUnits, formatUnits } from "viem"; @@ -96,24 +97,21 @@ import { addressAtom } from "@/components/sigpasskit"; import { localConfig } from "@/app/providers"; // abi for the Moonbeam SLPX contract and ERC20 token -import {erc20Abi , moonbeamSlpxAbi} from "@/lib/abi"; +import { erc20Abi, moonbeamSlpxAbi } from "@/lib/abi"; export default function MintRedeemLstBifrost() { - // useConfig hook to get config + /* --------------------------------------------------------------------- */ + /* initial hooks */ + /* --------------------------------------------------------------------- */ const config = useConfig(); - - // useAccount hook to get account const account = useAccount(); - - // useMediaQuery hook to check if the screen is desktop const isDesktop = useMediaQuery("(min-width: 768px)"); - // useState hook to open/close dialog/drawer const [open, setOpen] = useState(false); - - // get the address from session storage const address = useAtomValue(addressAtom); - // useWriteContract hook to write contract + /* --------------------------------------------------------------------- */ + /* write contract helpers */ + /* --------------------------------------------------------------------- */ const { data: hash, error, @@ -123,15 +121,16 @@ export default function MintRedeemLstBifrost() { config: address ? localConfig : config, }); + /* --------------------------------------------------------------------- */ + /* constants */ + /* --------------------------------------------------------------------- */ const XCDOT_CONTRACT_ADDRESS = "0xFfFFfFff1FcaCBd218EDc0EbA20Fc2308C778080"; const XCASTR_CONTRACT_ADDRESS = "0xFfFFFfffA893AD19e540E172C10d78D4d479B5Cf"; - // GLMR is both the native token of Moonbeam and an ERC20 token const GLMR_CONTRACT_ADDRESS = "0x0000000000000000000000000000000000000802"; const BIFROST_SLPX_CONTRACT_ADDRESS = "0xF1d4797E51a4640a76769A50b57abE7479ADd3d8"; - // Get the contract address based on selected token const getContractAddress = (token: string) => { switch (token) { case "xcdot": @@ -145,13 +144,13 @@ export default function MintRedeemLstBifrost() { } }; - // form schema for sending transaction + /* --------------------------------------------------------------------- */ + /* form setup */ + /* --------------------------------------------------------------------- */ const formSchema = z.object({ - // token is a required field selected from a list token: z.enum(["xcdot", "glmr", "xcastr"], { required_error: "Please select a token", }), - // amount is a required field amount: z .string() .refine((val) => !isNaN(parseFloat(val)) && parseFloat(val) > 0, { @@ -162,9 +161,7 @@ export default function MintRedeemLstBifrost() { }) .superRefine((val, ctx) => { if (!maxBalance || !decimals) return; - const inputAmount = parseUnits(val, decimals as number); - if (inputAmount > (maxBalance as bigint)) { ctx.addIssue({ code: z.ZodIssueCode.custom, @@ -174,47 +171,38 @@ export default function MintRedeemLstBifrost() { }), }); - // 1. Define your form. const form = useForm>({ - // resolver is zodResolver resolver: zodResolver(formSchema), - // default values for address and amount defaultValues: { token: "xcdot", amount: "", }, }); - - // Extract the token value using watch instead of getValues const selectedToken = form.watch("token"); - - - // useReadContracts hook to read contract + /* --------------------------------------------------------------------- */ + /* read-only contracts */ + /* --------------------------------------------------------------------- */ const { data, refetch: refetchBalance } = useReadContracts({ contracts: [ { - // get the balance of the selected token address: getContractAddress(selectedToken), abi: erc20Abi, functionName: "balanceOf", args: [address ? address : account.address], }, { - // get the symbol of the selected token address: getContractAddress(selectedToken), abi: erc20Abi, functionName: "symbol", }, { - // get the decimals of the selected token address: getContractAddress(selectedToken), abi: erc20Abi, functionName: "decimals", }, { - // get the allowance of the selected token address: getContractAddress(selectedToken), abi: erc20Abi, functionName: "allowance", @@ -227,133 +215,93 @@ export default function MintRedeemLstBifrost() { config: address ? localConfig : config, }); + const maxBalance = data?.[0]?.result as bigint | undefined; + const symbol = data?.[1]?.result as string | undefined; + const decimals = data?.[2]?.result as number | undefined; + const mintAllowance = data?.[3]?.result as bigint | undefined; - // extract the data from the read contracts hook - const maxBalance = data?.[0]?.result as bigint | undefined; // balance of the selected token - const symbol = data?.[1]?.result as string | undefined; // symbol of the selected token - const decimals = data?.[2]?.result as number | undefined; // decimals of the selected token - const mintAllowance = data?.[3]?.result as bigint | undefined; // allowance of the selected token - - // extract the amount value from the form const amount = form.watch("amount"); - - // check if the amount is greater than the mint allowance - const needsApprove = mintAllowance !== undefined && - amount ? - mintAllowance < parseUnits(amount, decimals || 18) : - false; - - - // 2. Define a submit handler. + const needsApprove = + mintAllowance !== undefined && amount + ? mintAllowance < parseUnits(amount, decimals || 18) + : false; + + /* --------------------------------------------------------------------- */ + /* submit handler */ + /* --------------------------------------------------------------------- */ async function onSubmit(values: z.infer) { - // if the user has a sigpass wallet, and the token is not GLMR, approve the token - if (address) { - if (needsApprove) { - writeContractAsync({ - account: await getSigpassWallet(), - address: getContractAddress(values.token), - abi: erc20Abi, - functionName: "approve", - args: [BIFROST_SLPX_CONTRACT_ADDRESS, parseUnits(values.amount, decimals as number)], - }); - } - } - - // if the user does not have a sigpass wallet, and the token is not GLMR, mint the token - if (!address) { - if (needsApprove) { - writeContractAsync({ - address: getContractAddress(values.token), - abi: erc20Abi, - functionName: "approve", - args: [BIFROST_SLPX_CONTRACT_ADDRESS, parseUnits(values.amount, decimals as number)], - }); - } - } - - /** - * @dev Create order to mint vAsset or redeem vAsset on bifrost chain - * @param assetAddress The address of the asset to mint or redeem - * @param amount The amount of the asset to mint or redeem - * @param dest_chain_id When order is executed on Bifrost, Asset/vAsset will be transferred to this chain - * @param receiver The receiver address on the destination chain, 20 bytes for EVM, 32 bytes for Substrate - * @param remark The remark of the order, less than 32 bytes. For example, "OmniLS" - * @param channel_id The channel id of the order, you can set it. Bifrost chain will use it to share reward. - **/ - if (!address && !needsApprove && selectedToken !== "glmr") { - writeContractAsync({ - address: BIFROST_SLPX_CONTRACT_ADDRESS, - abi: moonbeamSlpxAbi, - functionName: "create_order", + if (needsApprove) { + await writeContractAsync({ + ...(address && { account: await getSigpassWallet() }), + address: getContractAddress(values.token), + abi: erc20Abi, + functionName: "approve", args: [ - getContractAddress(values.token), + BIFROST_SLPX_CONTRACT_ADDRESS, parseUnits(values.amount, decimals as number), - 1284, // Moonbeam chain id - account.address, // receiver - "dotui", // remark - 0, // channel_id ], }); + return; } - if (!address && !needsApprove && selectedToken === "glmr") { - writeContractAsync({ - address: BIFROST_SLPX_CONTRACT_ADDRESS, - abi: moonbeamSlpxAbi, - functionName: "create_order", - args: [ - getContractAddress(values.token), - parseUnits(values.amount, decimals as number), - 1284, // Moonbeam chain id - account.address, // receiver - "dotui", // remark - 0, // channel_id - ], + const orderArgs = [ + getContractAddress(values.token), + parseUnits(values.amount, decimals as number), + 1284, // Moonbeam chain id + account.address, // receiver + "dotui", // remark + 0, // channel_id + ] as const; + + await writeContractAsync({ + ...(address && { account: await getSigpassWallet() }), + address: BIFROST_SLPX_CONTRACT_ADDRESS, + abi: moonbeamSlpxAbi, + functionName: "create_order", + args: orderArgs, + ...(selectedToken === "glmr" && { value: parseUnits(values.amount, decimals as number), - }); - } + }), + }); } - // Watch for transaction hash and open dialog/drawer when received + /* --------------------------------------------------------------------- */ + /* tx status + side effects */ + /* --------------------------------------------------------------------- */ useEffect(() => { - if (hash) { - setOpen(true); - } + if (hash) setOpen(true); }, [hash]); - // useWaitForTransactionReceipt hook to wait for transaction receipt const { isLoading: isConfirming, isSuccess: isConfirmed } = useWaitForTransactionReceipt({ hash, config: address ? localConfig : config, }); - // when isConfirmed, refetch the balance of the address useEffect(() => { - if (isConfirmed) { - refetchBalance(); - } + if (isConfirmed) refetchBalance(); }, [isConfirmed, refetchBalance]); - // Find the chain ID from the connected account - const chainId = account.chainId; - - // Get the block explorer URL for the current chain using the config object - function getBlockExplorerUrl(chainId: number | undefined): string | undefined { - const chain = config.chains?.find(chain => chain.id === chainId); - return chain?.blockExplorers?.default?.url || config.chains?.[0]?.blockExplorers?.default?.url; - } + const explorerUrl = + config.chains?.find((c) => c.id === account.chainId)?.blockExplorers + ?.default?.url || config.chains?.[0]?.blockExplorers?.default?.url; + /* --------------------------------------------------------------------- */ + /* render */ + /* --------------------------------------------------------------------- */ return ( - + Mint Redeem + + {/* ------------------------------- Mint ------------------------------ */} -
+
+ {/* token selector */} )} /> + + {/* amount input */} ( -
+
Amount -
- {" "} - { - maxBalance !== undefined ? ( - formatUnits(maxBalance as bigint, decimals as number) - ) : ( - - ) - }{" "} - { - symbol ? ( - symbol - ) : ( - - ) - } +
+ + {maxBalance !== undefined ? ( + formatUnits(maxBalance, decimals as number) + ) : ( + + )}{" "} + {symbol ?? }
@@ -428,222 +370,229 @@ export default function MintRedeemLstBifrost() { )} - The amount of {selectedToken === "glmr" ? "GLMR" : symbol} to mint + The amount of{" "} + {selectedToken === "glmr" ? "GLMR" : symbol ?? "token"} to + mint )} /> -
-

Token allowance

-
- {" "} - { - mintAllowance !== undefined ? ( - formatUnits(mintAllowance as bigint, decimals as number) - ) : ( - - ) - }{" "} - { - symbol ? ( - symbol - ) : ( - - ) - } + + {/* allowance & preview */} +
+

Token allowance

+
+ + {mintAllowance !== undefined ? ( + formatUnits(mintAllowance, decimals as number) + ) : ( + + )}{" "} + {symbol ?? }
-
-

You are about to mint this token

-
- { - selectedToken === "glmr" ? ( - "xcvGLMR" - ) : selectedToken === "xcdot" ? ( - "xcvDOT" - ) : selectedToken === "xcastr" ? ( - "xcvASTR" - ) : ( - - ) - } -
+ +
+

You will receive

+ + {selectedToken === "glmr" + ? "xcvGLMR" + : selectedToken === "xcdot" + ? "xcvDOT" + : "xcvASTR"} +
-
- { - isPending ? ( - - ) : needsApprove ? ( - + + {/* action buttons */} +
+ - ) - } - {isPending ? ( - - ) : needsApprove ? ( - - ) : ( - - )} + "Approve" + )} + +
- - { - // Desktop would be using dialog - isDesktop ? ( - - - - - - - Transaction status - - - Follow the transaction status below. - -
- {hash ? ( -
- - Transaction Hash - - {truncateHash(hash)} - - - -
- ) : ( -
- - No transaction hash -
- )} - {!isPending && !isConfirmed && !isConfirming && ( -
- No transaction submitted -
- )} - {isConfirming && ( -
- {" "} - Waiting for confirmation... -
- )} - {isConfirmed && ( -
- Transaction - confirmed! -
- )} - {error && ( -
- Error:{" "} - {(error as BaseError).shortMessage || error.message} -
- )} -
- - - - - -
-
- ) : ( - // Mobile would be using drawer - - - - - - - Transaction status - - Follow the transaction status below. - - -
- {hash ? ( -
- - Transaction Hash - - {truncateHash(hash)} - - - -
- ) : ( -
- - No transaction hash -
- )} - {!isPending && !isConfirmed && !isConfirming && ( -
- No transaction submitted -
- )} - {isConfirming && ( -
- {" "} - Waiting for confirmation... -
- )} - {isConfirmed && ( -
- Transaction - confirmed! -
- )} - {error && ( -
- Error:{" "} - {(error as BaseError).shortMessage || error.message} -
- )} -
- - - - - -
-
- ) - } + + {/* status panel */} + {isDesktop ? ( + + + + + + + Transaction status + + + Follow every step—from wallet signature to final confirmation. + + + + + + + + + + ) : ( + + + + + + + Transaction status + + Follow every step—from wallet signature to final + confirmation. + + +
+ +
+ + + + + +
+
+ )} +
+ + + {/* ------------------------------ Redeem ----------------------------- */} + +
+ Redeem flow coming soon…
- placeholder ); } +/* --------------------------------------------------------------------- */ +/* helpers */ +/* --------------------------------------------------------------------- */ + +type StatusProps = { + hash?: `0x${string}`; + isPending: boolean; + isConfirming: boolean; + isConfirmed: boolean; + error: BaseError | WriteContractErrorType | null | undefined; + explorerUrl?: string; +}; + +function StatusBody({ + hash, + isPending, + isConfirming, + isConfirmed, + error, + explorerUrl, +}: StatusProps) { + return ( +
+ {hash ? ( + + ) : ( +
+ No transaction hash +
+ )} + + {isPending && ( +
+ + Awaiting signature in wallet… +
+ )} + + {!isPending && !isConfirming && !isConfirmed && ( +
+ No transaction submitted +
+ )} + + {isConfirming && ( +
+ + Broadcast to network—waiting for confirmations… +
+ )} + + {isConfirmed && ( +
+ + Confirmed on-chain! +
+ )} + + {error && ( +
+ + {"shortMessage" in (error as BaseError) + ? (error as BaseError).shortMessage + : (error as Error).message} +
+ )} +
+ ); +} diff --git a/challenge-3-frontend/components/navbar.tsx b/challenge-3-frontend/components/navbar.tsx index d212169..a30aa3f 100644 --- a/challenge-3-frontend/components/navbar.tsx +++ b/challenge-3-frontend/components/navbar.tsx @@ -1,32 +1,230 @@ +"use client"; + +import { useState } from "react"; import Link from "next/link"; +import { usePathname } from "next/navigation"; +import { + Home, + Wallet as WalletIcon, + Send, + PenLine, + Coins, + Boxes, + ChevronDown, + Menu, + Sparkles, +} from "lucide-react"; +import * as DropdownMenu from "@radix-ui/react-dropdown-menu"; +import { cn } from "@/lib/utils"; +import SigpassKit from "@/components/sigpasskit"; +import { + Drawer, + DrawerTrigger, + DrawerContent, + DrawerClose, +} from "@/components/ui/drawer"; +import { Button } from "@/components/ui/button"; +import CreateWalletDialog from "@/components/create-wallet-dialog"; + +/* -------------------------------------------------------------------------- */ +/* Primary routes */ +/* -------------------------------------------------------------------------- */ + +const primaryNav = [ + { href: "/", label: "Home", icon: Home }, + { href: "/yield-farm", label: "Yield Farm", icon: Coins }, + { href: "/vesting", label: "Vesting", icon: Boxes }, + { href: "/send-transaction", label: "Send Tx", icon: Send }, + { href: "/write-contract", label: "Write", icon: PenLine }, +]; + +/* -------------------------------------------------------------------------- */ +/* Navbar */ +/* -------------------------------------------------------------------------- */ export default function Navbar() { + const pathname = usePathname(); + const [walletDrawerOpen, setWalletDrawerOpen] = useState(false); + + /* -------------------------------- render -------------------------------- */ return ( -
- - Home - - - Wallet - - - Send transaction - - - Write contract - - +
+
+ {/* Brand */} + + + Open Encode + + + {/* Desktop nav */} + + + {/* Wallet actions */} +
+ {/* Wallet drawer */} + + + + + + { + // Close the wallet drawer whenever any button inside is clicked + const target = e.target as HTMLElement; + if (target.closest("button")) setWalletDrawerOpen(false); + }} + className="border-0 bg-gradient-to-br from-pink-500 via-fuchsia-600 to-violet-600 text-white shadow-2xl" + > +
+ +

+ Polkadot Wallet +

+

+ Create or connect a passkey wallet to unlock the multichain + power of the Polkadot ecosystem. +

+ + + + + + +
+
+
+ + {/* Mobile menu */} + +
+
+
+ + {/* Mount the global create-wallet dialog once, outside the header */} + + + ); +} + +/* -------------------------------------------------------------------------- */ +/* Helper components */ +/* -------------------------------------------------------------------------- */ + +function NavItem({ + href, + active, + children, +}: { + href: string; + active: boolean; + children: React.ReactNode; +}) { + return ( + + {children} + + ); +} + +function DropdownLink({ + href, + external = false, + children, +}: { + href: string; + external?: boolean; + children: React.ReactNode; +}) { + const common = + "flex items-center rounded-sm px-3 py-2 text-sm hover:bg-accent hover:text-accent-foreground"; + return external ? ( + + + {children} + + + ) : ( + + {children} + + ); +} + +function MobileMenu({ pathname }: { pathname: string | null }) { + return ( + + + + + - Mint/Redeem LST Bifrost - -
+ {primaryNav.map(({ href, label }) => ( + + {label} + + ))} + + + Mint / Redeem Bifrost + + + ); } diff --git a/challenge-3-frontend/components/send-transaction.tsx b/challenge-3-frontend/components/send-transaction.tsx index edff6a0..08c989e 100644 --- a/challenge-3-frontend/components/send-transaction.tsx +++ b/challenge-3-frontend/components/send-transaction.tsx @@ -5,18 +5,10 @@ import { type BaseError, useSendTransaction, useWaitForTransactionReceipt, - useConfig + useConfig, } from "wagmi"; import { parseEther, isAddress, Address } from "viem"; -import { - Ban, - ExternalLink, - ChevronDown, - X, - Hash, - LoaderCircle, - CircleCheck, -} from "lucide-react"; +import { ChevronDown, LoaderCircle } from "lucide-react"; import { z } from "zod"; import { zodResolver } from "@hookform/resolvers/zod"; import { useForm } from "react-hook-form"; @@ -52,17 +44,15 @@ import { DrawerTitle, DrawerTrigger, } from "@/components/ui/drawer"; -import { truncateHash } from "@/lib/utils"; -import CopyButton from "@/components/copy-button"; +import TransactionStatus from "@/components/transaction-status"; import { getSigpassWallet } from "@/lib/sigpass"; import { westendAssetHub } from "@/app/providers"; -import { useAtomValue } from 'jotai'; -import { addressAtom } from '@/components/sigpasskit'; -import { localConfig } from '@/app/providers'; +import { useAtomValue } from "jotai"; +import { addressAtom } from "@/components/sigpasskit"; +import { localConfig } from "@/app/providers"; // form schema for sending transaction const formSchema = z.object({ - // address is a required field address: z .string() .min(2) @@ -70,7 +60,6 @@ const formSchema = z.object({ .refine((val) => val === "" || isAddress(val), { message: "Invalid Ethereum address format", }) as z.ZodType
, - // amount is a required field amount: z .string() .refine((val) => !isNaN(parseFloat(val)) && parseFloat(val) > 0, { @@ -82,19 +71,11 @@ const formSchema = z.object({ }); export default function SendTransaction() { - - // useConfig hook to get config const config = useConfig(); - - // useMediaQuery hook to check if the screen is desktop const isDesktop = useMediaQuery("(min-width: 768px)"); - // useState hook to open/close dialog/drawer const [open, setOpen] = useState(false); + const address = useAtomValue(addressAtom); - // get the address from session storage - const address = useAtomValue(addressAtom) - - // useSendTransaction hook to send transaction const { data: hash, error, @@ -104,55 +85,39 @@ export default function SendTransaction() { config: address ? localConfig : config, }); - - // 1. Define your form. const form = useForm>({ - // resolver is zodResolver resolver: zodResolver(formSchema), - // default values for address and amount - defaultValues: { - address: "", - amount: "", - }, + defaultValues: { address: "", amount: "" }, }); - - // 2. Define a submit handler. async function onSubmit(values: z.infer) { if (address) { - sendTransactionAsync({ + await sendTransactionAsync({ account: await getSigpassWallet(), to: values.address as Address, value: parseEther(values.amount), chainId: westendAssetHub.id, }); } else { - // Fallback to connected wallet - sendTransactionAsync({ + await sendTransactionAsync({ to: values.address as Address, value: parseEther(values.amount), }); } } - // Watch for transaction hash and open dialog/drawer when received useEffect(() => { - if (hash) { - setOpen(true); - } + if (hash) setOpen(true); }, [hash]); - - // useWaitForTransactionReceipt hook to wait for transaction receipt const { isLoading: isConfirming, isSuccess: isConfirmed } = useWaitForTransactionReceipt({ hash, config: address ? localConfig : config, }); - return ( -
+
Amount {isDesktop ? ( - + ) : ( )} /> - { - isPending ? ( - + - ) - } + "Send" + )} + - { - // Desktop would be using dialog - isDesktop ? ( - - - - - - - Transaction status - - + + {isDesktop ? ( + + + + + + + Transaction status + + + Follow the transaction status below. + + + + + + + + + + + + ) : ( + + + + + + + Transaction status + Follow the transaction status below. - -
- {hash ? ( -
- - Transaction Hash - - {truncateHash(hash)} - - - -
- ) : ( -
- - No transaction hash -
- )} - { - !isPending && !isConfirmed && !isConfirming && ( -
- No transaction submitted -
- ) - } - {isConfirming && ( -
- Waiting - for confirmation... -
- )} - {isConfirmed && ( -
- Transaction confirmed! -
- )} - {error && ( -
- Error:{" "} - {(error as BaseError).shortMessage || error.message} -
- )} -
- - - - - -
-
- ) : ( - // Mobile would be using drawer - - - - - - - Transaction status - - Follow the transaction status below. - - -
- {hash ? ( -
- - Transaction Hash - - {truncateHash(hash)} - - - -
- ) : ( -
- - No transaction hash -
- )} - { - !isPending && !isConfirmed && !isConfirming && ( -
- No transaction submitted -
- ) - } - {isConfirming && ( -
- Waiting - for confirmation... -
- )} - {isConfirmed && ( -
- Transaction confirmed! -
- )} - {error && ( -
- Error:{" "} - {(error as BaseError).shortMessage || error.message} -
- )} -
- - - - - -
-
- ) - } + + +
+ +
+ + + + + + + + )}
); } diff --git a/challenge-3-frontend/components/sigpasskit.tsx b/challenge-3-frontend/components/sigpasskit.tsx index d655b4a..e9e0ba4 100644 --- a/challenge-3-frontend/components/sigpasskit.tsx +++ b/challenge-3-frontend/components/sigpasskit.tsx @@ -1,15 +1,33 @@ "use client"; import { useState, useEffect } from "react"; -import '@rainbow-me/rainbowkit/styles.css'; +import "@rainbow-me/rainbowkit/styles.css"; import { useMediaQuery } from "@/hooks/use-media-query"; import { Skeleton } from "@/components/ui/skeleton"; import { Button } from "@/components/ui/button"; -import { Copy, Check, KeyRound, Ban, ExternalLink, LogOut, ChevronDown, X } from 'lucide-react'; -import { formatEther, Address } from 'viem'; -import { createSigpassWallet, getSigpassWallet, checkSigpassWallet, checkBrowserWebAuthnSupport } from "@/lib/sigpass"; -import { ConnectButton } from '@rainbow-me/rainbowkit'; -import { useAccount, useBalance, createConfig, http, useConfig } from 'wagmi'; +import { + Copy, + Check, + KeyRound, + ChevronDown, + LogOut, + ExternalLink, +} from "lucide-react"; +import { formatEther, Address } from "viem"; +import { + createSigpassWallet, + getSigpassWallet, + checkSigpassWallet, + checkBrowserWebAuthnSupport, +} from "@/lib/sigpass"; +import { ConnectButton } from "@rainbow-me/rainbowkit"; +import { + useAccount, + useBalance, + createConfig, + http, + useConfig, +} from "wagmi"; import { Dialog, DialogContent, @@ -18,7 +36,8 @@ import { DialogFooter, DialogTitle, DialogTrigger, -} from "@/components/ui/dialog" + DialogClose, +} from "@/components/ui/dialog"; import { Drawer, DrawerClose, @@ -28,354 +47,293 @@ import { DrawerHeader, DrawerTitle, DrawerTrigger, -} from "@/components/ui/drawer" -import Image from 'next/image'; -import { useAtom } from 'jotai'; -import { atomWithStorage, RESET } from 'jotai/utils'; -import { westendAssetHub } from '@/app/providers'; +} from "@/components/ui/drawer"; +import Image from "next/image"; +import { useAtom, useAtomValue, useSetAtom } from "jotai"; +import { atomWithStorage, RESET } from "jotai/utils"; +import { westendAssetHub } from "@/app/providers"; +import { createWalletDialogOpenAtom } from "@/lib/atoms"; +// Persistent address storage +export const addressAtom = atomWithStorage
( + "SIGPASS_ADDRESS", + undefined +); -// Set the string key and the initial value -export const addressAtom = atomWithStorage
('SIGPASS_ADDRESS', undefined) - -// create a local config for the wallet +// Local wagmi config for Sigpass‐only wallets const localConfig = createConfig({ chains: [westendAssetHub], - transports: { - [westendAssetHub.id]: http(), - }, + transports: { [westendAssetHub.id]: http() }, ssr: true, }); +/* -------------------------------------------------------------------------- */ +/* Custom ConnectButton UI */ +/* -------------------------------------------------------------------------- */ +function CustomConnectButton() { + return ( + + {({ + account, + chain, + openAccountModal, + openChainModal, + openConnectModal, + mounted, + }) => { + const ready = mounted; + const connected = + ready && + account && + chain && + !chain.unsupported; + + if (!connected) { + return ( + + ); + } + + return ( +
+ + + +
+ ); + }} +
+ ); +} + +/* -------------------------------------------------------------------------- */ +/* SigpassKit UI */ +/* -------------------------------------------------------------------------- */ export default function SigpassKit() { - const [wallet, setWallet] = useState(false); - const [open, setOpen] = useState(false); - const [webAuthnSupport, setWebAuthnSupport] = useState(false); - const isDesktop = useMediaQuery("(min-width: 768px)") - const account = useAccount(); - const [address, setAddress] = useAtom(addressAtom); - const [isCopied, setIsCopied] = useState(false); - const config = useConfig(); - const { data: balance } = useBalance({ - address: address, - chainId: westendAssetHub.id, - config: address ? localConfig : config, - }); + /* ------------------------------------------------------------------ */ + /* global & local state */ + /* ------------------------------------------------------------------ */ + const setCreateWalletOpen = useSetAtom(createWalletDialogOpenAtom); - // check if the wallet is already created - useEffect(() => { - async function fetchWalletStatus() { - const status = await checkSigpassWallet(); - setWallet(status); - } - fetchWalletStatus(); - }, []); + const [hasWallet, setHasWallet] = useState(false); // Sigpass created? + const [detailsOpen, setDetailsOpen] = useState(false); // Wallet-details modal + const [webAuthn, setWebAuthn] = useState(false); // Browser support + const [copied, setCopied] = useState(false); // Copy feedback + + const isDesktop = useMediaQuery("(min-width: 768px)"); + const account = useAccount(); + const wagmiConfig = useConfig(); + const [address, setAddress] = useAtom(addressAtom); - // check if the browser supports WebAuthn + /* ------------------------------------------------------------------ */ + /* effects */ + /* ------------------------------------------------------------------ */ useEffect(() => { - const support = checkBrowserWebAuthnSupport(); - setWebAuthnSupport(support); + checkSigpassWallet().then(setHasWallet); + setWebAuthn(checkBrowserWebAuthnSupport()); }, []); - // get the wallet - async function getWallet() { - const account = await getSigpassWallet(); - if (account) { - setAddress(account.address); - } else { - console.error('Issue getting wallet'); - } - } - - // create a wallet - async function createWallet() { - const account = await createSigpassWallet("dapp"); - if (account) { - setOpen(false); - setWallet(true); - } - } + const { data: balance } = useBalance({ + address, + chainId: westendAssetHub.id, + config: address ? localConfig : wagmiConfig, + }); - // truncate address to 6 characters and add ... at the end - function truncateAddress(address: Address, length: number = 4) { - return `${address.slice(0, length)}...${address.slice(-length)}`; - } + /* ------------------------------------------------------------------ */ + /* helper event handlers */ + /* ------------------------------------------------------------------ */ + // Retrieve stored account from WebAuthn + const handleGetWallet = async () => { + const acc = await getSigpassWallet(); + if (acc) setAddress(acc.address); + }; - // copy the address to the clipboard - function copyAddress() { - if (address) { - navigator.clipboard.writeText(address ? address : ""); - setIsCopied(true); - setTimeout(() => { - setIsCopied(false); - }, 1000); - } - } + // Copy address to clipboard + const copyAddress = () => { + if (!address) return; + navigator.clipboard.writeText(address); + setCopied(true); + setTimeout(() => setCopied(false), 1000); + }; - // disconnect the wallet - function disconnect() { + // Disconnect (local) wallet + const disconnect = () => { setAddress(undefined); - setOpen(false); + setDetailsOpen(false); setAddress(RESET); - } + }; + // Truncate address for display + const short = (addr: Address, len = 4) => + `${addr.slice(0, len)}…${addr.slice(-len)}`; - if (isDesktop) { - return ( -
- {!wallet && !account.isConnected && !address ? ( - - - - - - - Create Wallet - - Instantly get a wallet with Passkey - - -
-
-

What is a Wallet?

-
- icon-1 -
-

A Home for your Digital Assets

-

Wallets are used to send, receive, store, and display digital assets like Polkadot and NFTs.

-
-
-
- icon-2 -
-

A new way to Log In

-

Instead of creating new accounts and passwords on every website, just connect your wallet.

-
-
-
-
- -
- Learn more - { - webAuthnSupport ? ( - - ) : ( - - ) - } -
-
-
- Powered by Sigpass -
-
-
- ) : wallet && !account.isConnected && address === undefined ? ( - - ) : wallet && !account.isConnected && address ? - + /* ------------------------------------------------------------------ */ + /* rendered component */ + /* ------------------------------------------------------------------ */ + return ( +
+ {/* ----------------------------- NO WALLET CREATED ---------------------------- */} + {!hasWallet && !account.isConnected && !address ? ( + + ) : null} + + {/* ------------------------ WALLET EXISTS BUT NOT LOADED ---------------------- */} + {hasWallet && !account.isConnected && address === undefined ? ( + + ) : null} + + {/* -------------------------- LOCAL WALLET LOADED ----------------------------- */} + {hasWallet && !account.isConnected && address ? ( + /* Desktop uses Dialog; Mobile uses Drawer for wallet details */ + isDesktop ? ( + - + Wallet - - {truncateAddress(address, 4)} + + {short(address, 4)} -
- {balance ? `${formatEther(balance.value)} WND` : } -
-
- - -
-
-
- : null} - { - !address ? : null - } -
- ) - } - - return ( -
- {(!wallet && !account.isConnected && !address) ? ( - - - - - - - Create Wallet - - Instantly get a wallet with Passkey - - -
-
-

What is a Wallet?

-
- icon-1 -
-

A Home for your Digital Assets

-

Wallets are used to send, receive, store, and display digital assets like Polkadot and NFTs.

-
-
-
- icon-2 -
-

A new way to Log In

-

Instead of creating new accounts and passwords on every website, just connect your wallet.

-
-
- Learn more -
-
- - {webAuthnSupport ? ( + - ) : ( - - )} - - - -
- Powered by Sigpass +
-
-
-
- ) : wallet && !account.isConnected && address === undefined ? ( - - ) : wallet && !account.isConnected && address ? ( - - - - - - -
+ +
+ ) : ( + + + + + + Wallet - - - -
- - {truncateAddress(address, 4)} - - -
-
- {balance ? `${formatEther(balance.value)} WND` : } -
-
- -
-
- - + + + ) ) : null} - {!address ? : null} + + {/* ------------------------------ CONNECT BUTTON ------------------------------ */} + {!address ? : null}
- ) + ); } - diff --git a/challenge-3-frontend/components/trans-status.tsx b/challenge-3-frontend/components/trans-status.tsx new file mode 100644 index 0000000..6743e15 --- /dev/null +++ b/challenge-3-frontend/components/trans-status.tsx @@ -0,0 +1,85 @@ +"use client"; + +import { + Ban, + CircleCheck, + ExternalLink, + Hash, + LoaderCircle, + X, +} from "lucide-react"; +import { type BaseError } from "wagmi"; +import { truncateHash } from "@/lib/utils"; +import CopyButton from "@/components/copy-button"; + +export interface TransactionStatusProps { + hash?: `0x${string}`; + isPending: boolean; + isConfirming: boolean; + isConfirmed: boolean; + error?: BaseError | null; + explorerUrl?: string; +} + +export default function TransactionStatus({ + hash, + isPending, + isConfirming, + isConfirmed, + error, + explorerUrl, +}: TransactionStatusProps) { + return ( +
+ {hash ? ( +
+ + Transaction Hash + + {truncateHash(hash)} + + + +
+ ) : ( +
+ + No transaction hash +
+ )} + + {!isPending && !isConfirming && !isConfirmed && ( +
+ + No transaction submitted +
+ )} + + {isConfirming && ( +
+ + Waiting for confirmation… +
+ )} + + {isConfirmed && ( +
+ + Transaction confirmed! +
+ )} + + {error && ( +
+ + Error: {(error as BaseError).shortMessage || error.message} +
+ )} +
+ ); +} diff --git a/challenge-3-frontend/components/ui/button.tsx b/challenge-3-frontend/components/ui/button.tsx index 36496a2..4561322 100644 --- a/challenge-3-frontend/components/ui/button.tsx +++ b/challenge-3-frontend/components/ui/button.tsx @@ -18,6 +18,8 @@ const buttonVariants = cva( "bg-secondary text-secondary-foreground hover:bg-secondary/80", ghost: "hover:bg-accent hover:text-accent-foreground", link: "text-primary underline-offset-4 hover:underline", + polkadot: + "bg-gradient-to-r from-pink-500 via-fuchsia-500 to-violet-500 text-white shadow-md hover:opacity-90", }, size: { default: "h-10 px-4 py-2", @@ -53,4 +55,4 @@ const Button = React.forwardRef( ) Button.displayName = "Button" -export { Button, buttonVariants } +export { Button, buttonVariants } \ No newline at end of file diff --git a/challenge-3-frontend/components/ui/card.tsx b/challenge-3-frontend/components/ui/card.tsx new file mode 100644 index 0000000..f6189f0 --- /dev/null +++ b/challenge-3-frontend/components/ui/card.tsx @@ -0,0 +1,59 @@ +import * as React from "react"; +import { cn } from "@/lib/utils"; + +const Card = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ) +); +Card.displayName = "Card"; + +const CardHeader = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ) +); +CardHeader.displayName = "CardHeader"; + +const CardTitle = React.forwardRef< + HTMLHeadingElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)); +CardTitle.displayName = "CardTitle"; + +const CardDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

+)); +CardDescription.displayName = "CardDescription"; + +const CardContent = React.forwardRef>( + ({ className, ...props }, ref) => ( +

+ ) +); +CardContent.displayName = "CardContent"; + +const CardFooter = React.forwardRef>( + ({ className, ...props }, ref) => ( +
+ ) +); +CardFooter.displayName = "CardFooter"; + +export { Card, CardHeader, CardTitle, CardDescription, CardContent, CardFooter }; \ No newline at end of file diff --git a/challenge-3-frontend/components/vesting /create-form.tsx b/challenge-3-frontend/components/vesting /create-form.tsx new file mode 100644 index 0000000..38e1fbc --- /dev/null +++ b/challenge-3-frontend/components/vesting /create-form.tsx @@ -0,0 +1,303 @@ +"use client"; + +import { useState, useEffect } from "react"; +import { + useWriteContract, + useWaitForTransactionReceipt, + useConfig, +} from "wagmi"; +import { parseUnits, Address, isAddress } from "viem"; +import { z } from "zod"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import { + Form, + FormField, + FormItem, + FormLabel, + FormControl, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardHeader, + CardTitle, + CardDescription, + CardContent, + CardFooter, +} from "@/components/ui/card"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogFooter, + DialogTitle, + DialogTrigger, + DialogClose, +} from "@/components/ui/dialog"; +import { + Drawer, + DrawerClose, + DrawerContent, + DrawerDescription, + DrawerFooter, + DrawerHeader, + DrawerTitle, + DrawerTrigger, +} from "@/components/ui/drawer"; +import { ChevronDown } from "lucide-react"; +import TransactionStatus from "@/components/transaction-status"; +import { tokenVestingAbi } from "@/lib/abi"; +import { TOKEN_VESTING_CONTRACT_ADDRESS } from "@/lib/config"; +import { useAtomValue } from "jotai"; +import { addressAtom } from "@/components/sigpasskit"; +import { getSigpassWallet } from "@/lib/sigpass"; +import { westendAssetHub, localConfig } from "@/app/providers"; +import { useMediaQuery } from "@/hooks/use-media-query"; + +const formSchema = z.object({ + beneficiary: z + .string() + .refine((val) => isAddress(val), { message: "Invalid address" }) as z.ZodType
, + amount: z + .string() + .refine((val) => !isNaN(parseFloat(val)) && parseFloat(val) > 0, { + message: "Must be positive", + }), + startTime: z.string().min(1, { message: "Required" }), + cliff: z.string().min(1, { message: "Required" }), + duration: z.string().min(1, { message: "Required" }), + slicePeriod: z.string().min(1, { message: "Required" }), + revocable: z.boolean(), +}); + +export default function CreateForm() { + const config = useConfig(); + const address = useAtomValue(addressAtom); + const isDesktop = useMediaQuery("(min-width: 768px)"); + const [open, setOpen] = useState(false); + + const { + data: hash, + error, + isPending, + writeContractAsync, + } = useWriteContract({ + config: address ? localConfig : config, + }); + + const { isLoading: isConfirming, isSuccess: isConfirmed } = + useWaitForTransactionReceipt({ + hash, + config: address ? localConfig : config, + }); + + const form = useForm>({ + resolver: zodResolver(formSchema), + defaultValues: { + beneficiary: "", + amount: "", + startTime: Math.floor(Date.now() / 1000).toString(), + cliff: "0", + duration: "0", + slicePeriod: "1", + revocable: false, + }, + }); + + async function onSubmit(values: z.infer) { + await writeContractAsync({ + ...(address && { account: await getSigpassWallet() }), + address: TOKEN_VESTING_CONTRACT_ADDRESS, + abi: tokenVestingAbi, + functionName: "createVestingSchedule", + args: [ + values.beneficiary as `0x${string}`, + parseUnits(values.amount, 18), + BigInt(values.startTime), + BigInt(values.cliff), + BigInt(values.duration), + BigInt(values.slicePeriod), + values.revocable, + ], + chainId: westendAssetHub.id, + }); + } + + /* Open status panel automatically when hash appears */ + useEffect(() => { + if (hash) setOpen(true); + }, [hash]); + + return ( + + + Create Vesting Schedule + + Lock tokens with optional slice period and revocability. + + + + +
+ + {/* beneficiary */} + ( + + Beneficiary + + + + + + )} + /> + {/* amount */} + ( + + Amount + + + + + + )} + /> + {/* timing */} +
+ {["startTime","cliff","duration"].map((n)=>( + ( + + {n.replace(/([A-Z])/g," $1")} + + + + + + )} + /> + ))} +
+ {/* slice */} + ( + + Slice Period (s) + + + + + + )} + /> + {/* revocable */} + ( + + + field.onChange(e.currentTarget.checked)} + className="h-4 w-4 accent-pink-500" + /> + + Revocable by creator + + )} + /> + + + +
+ + + + UNIX seconds are used for all timestamps; ensure your wallet signs accurate values. + + + {/* transaction status trigger */} + {isDesktop ? ( + + + + + + + Transaction status + + + Follow every step—from wallet signature to final confirmation. + + + + + + + + + + ) : ( + + + + + + + Transaction status + + Follow every step—from wallet signature to final confirmation. + + +
+ +
+ + + + + +
+
+ )} +
+
+ ); +} \ No newline at end of file diff --git a/challenge-3-frontend/components/vesting /index.tsx b/challenge-3-frontend/components/vesting /index.tsx new file mode 100644 index 0000000..3918ff1 --- /dev/null +++ b/challenge-3-frontend/components/vesting /index.tsx @@ -0,0 +1,13 @@ +"use client"; + +import CreateForm from "./create-form"; +import ScheduleCard from "./schedule-card"; + +export default function Vesting() { + return ( +
+ + +
+ ); +} \ No newline at end of file diff --git a/challenge-3-frontend/components/vesting /schedule-card.tsx b/challenge-3-frontend/components/vesting /schedule-card.tsx new file mode 100644 index 0000000..0c53537 --- /dev/null +++ b/challenge-3-frontend/components/vesting /schedule-card.tsx @@ -0,0 +1,272 @@ +"use client"; + +import { useState, useEffect } from "react"; +import { + useReadContracts, + useWriteContract, + useConfig, + useAccount, + useWaitForTransactionReceipt, + type BaseError, +} from "wagmi"; +import { formatUnits } from "viem"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardHeader, + CardTitle, + CardDescription, + CardContent, + CardFooter, +} from "@/components/ui/card"; +import { tokenVestingAbi } from "@/lib/abi"; +import { TOKEN_VESTING_CONTRACT_ADDRESS } from "@/lib/config"; +import { Skeleton } from "@/components/ui/skeleton"; +import { useAtomValue } from "jotai"; +import { addressAtom } from "@/components/sigpasskit"; +import { getSigpassWallet } from "@/lib/sigpass"; +import { westendAssetHub, localConfig } from "@/app/providers"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogDescription, + DialogTrigger, + DialogFooter, + DialogClose, +} from "@/components/ui/dialog"; +import { + Drawer, + DrawerContent, + DrawerHeader, + DrawerTitle, + DrawerDescription, + DrawerTrigger, + DrawerFooter, + DrawerClose, +} from "@/components/ui/drawer"; +import { ChevronDown } from "lucide-react"; +import TransactionStatus from "@/components/transaction-status"; +import { useMediaQuery } from "@/hooks/use-media-query"; + +export default function ScheduleCard() { + const config = useConfig(); + const account = useAccount(); + const address = useAtomValue(addressAtom); + const isDesktop = useMediaQuery("(min-width: 768px)"); + const [open, setOpen] = useState(false); + + /* --------------------------------------------------------------------- */ + /* Derive address */ + /* --------------------------------------------------------------------- */ + const beneficiary = (address ?? account.address) as + | `0x${string}` + | undefined; + + /* --------------------------------------------------------------------- */ + /* On-chain read */ + /* --------------------------------------------------------------------- */ + const { data, isLoading, refetch } = useReadContracts({ + contracts: [ + { + address: TOKEN_VESTING_CONTRACT_ADDRESS, + abi: tokenVestingAbi, + functionName: "getVestingSchedule", + args: [ + beneficiary ?? "0x0000000000000000000000000000000000000000", + ], + }, + ], + config, + }); + + const schedule = data?.[0]?.result as + | { + totalAmount: bigint; + startTime: bigint; + cliff: bigint; + duration: bigint; + releasedAmount: bigint; + revoked: boolean; + } + | undefined; + + /* --------------------------------------------------------------------- */ + /* Write tx */ + /* --------------------------------------------------------------------- */ + const { + data: hash, + error, + isPending, + writeContractAsync, + } = useWriteContract({ + config: address ? localConfig : config, + }); + + const { isLoading: isConfirming, isSuccess: isConfirmed } = + useWaitForTransactionReceipt({ + hash, + config: address ? localConfig : config, + }); + + const handleClaim = async () => { + if (!beneficiary) return; + await writeContractAsync({ + ...(address && { account: await getSigpassWallet() }), + address: TOKEN_VESTING_CONTRACT_ADDRESS, + abi: tokenVestingAbi, + functionName: "release", + args: [beneficiary], + chainId: westendAssetHub.id, + }); + }; + + /* --------------------------------------------------------------------- */ + /* UI side-effects */ + /* --------------------------------------------------------------------- */ + useEffect(() => { + const id = setInterval(refetch, 60_000); + return () => clearInterval(id); + }, [refetch]); + + useEffect(() => { + if (hash) setOpen(true); + }, [hash]); + + /* --------------------------------------------------------------------- */ + /* Render */ + /* --------------------------------------------------------------------- */ + return ( + + + Your Vesting Schedule + Track and claim your vested tokens. + + + + {isLoading ? ( +
+ + + + +
+ ) : schedule ? ( +
    +
  • + Total:{" "} + {formatUnits(schedule.totalAmount, 18)} tokens +
  • +
  • + Start:{" "} + {new Date(Number(schedule.startTime) * 1000).toLocaleString()} +
  • +
  • + Cliff:{" "} + {Number(schedule.cliff)} s +
  • +
  • + Duration:{" "} + {Number(schedule.duration)} s +
  • +
  • + Released:{" "} + {formatUnits(schedule.releasedAmount, 18)} tokens +
  • +
  • + Status:{" "} + {schedule.revoked ? "Revoked" : "Active"} +
  • +
+ ) : ( +

No vesting schedule found.

+ )} +
+ + {!schedule?.revoked && ( + + + + {/* ---------------------------- Status panel --------------------------- */} + {isDesktop ? ( + + + + + + + Transaction status + + + Follow every step—from wallet signature to final confirmation. + + + + + + + + + + ) : ( + + + + + + + Transaction status + + Follow every step—from wallet signature to final confirmation. + + +
+ +
+ + + + + +
+
+ )} +
+ )} +
+ ); +} diff --git a/challenge-3-frontend/components/write-contract.tsx b/challenge-3-frontend/components/write-contract.tsx index 1c0270b..2f589c0 100644 --- a/challenge-3-frontend/components/write-contract.tsx +++ b/challenge-3-frontend/components/write-contract.tsx @@ -10,8 +10,9 @@ import { useConfig, useWriteContract, useReadContracts, - useAccount + useAccount, } from "wagmi"; +import type { WriteContractErrorType } from "wagmi/actions"; // Viem imports import { parseUnits, formatUnits, isAddress, Address } from "viem"; @@ -25,7 +26,7 @@ import { Hash, LoaderCircle, CircleCheck, - WalletMinimal + WalletMinimal, } from "lucide-react"; // Zod imports @@ -80,66 +81,53 @@ import CopyButton from "@/components/copy-button"; // Library imports import { getSigpassWallet } from "@/lib/sigpass"; import { westendAssetHub } from "@/app/providers"; -import { useAtomValue } from 'jotai' -import { addressAtom } from '@/components/sigpasskit' -import { Skeleton } from "./ui/skeleton"; +import { useAtomValue } from "jotai"; +import { addressAtom } from "@/components/sigpasskit"; +import { Skeleton } from "@/components/ui/skeleton"; import { localConfig } from "@/app/providers"; // Abi for ERC20 Token import { erc20AbiExtend } from "@/lib/abi"; -export default function WriteContract() { - // useConfig hook to get config +export default function WriteContract() { const config = useConfig(); - - // useAccount hook to get account const account = useAccount(); - - // useMediaQuery hook to check if the screen is desktop const isDesktop = useMediaQuery("(min-width: 768px)"); - // useState hook to open/close dialog/drawer const [open, setOpen] = useState(false); + const address = useAtomValue(addressAtom); - // get the address from session storage - const address = useAtomValue(addressAtom) - - // useWriteContract hook to write contract const { data: hash, error, isPending, - writeContractAsync + writeContractAsync, } = useWriteContract({ config: address ? localConfig : config, - }) + }); const USDC_CONTRACT_ADDRESS = "0xc8576Fb6De558b313afe0302B3fedc6F6447BbEE"; - // useReadContracts hook to read contract - const { - data, - refetch - } = useReadContracts({ - contracts: [{ - address: USDC_CONTRACT_ADDRESS, - abi: erc20AbiExtend, - functionName: 'balanceOf', - args: [address ? address : account.address], - }, { - address: USDC_CONTRACT_ADDRESS, - abi: erc20AbiExtend, - functionName: 'decimals', - }], + const { data, refetch } = useReadContracts({ + contracts: [ + { + address: USDC_CONTRACT_ADDRESS, + abi: erc20AbiExtend, + functionName: "balanceOf", + args: [address ? address : account.address], + }, + { + address: USDC_CONTRACT_ADDRESS, + abi: erc20AbiExtend, + functionName: "decimals", + }, + ], config: address ? localConfig : config, - }) + }); - // get the max balance and decimals from the data const maxBalance = data?.[0]?.result as bigint | undefined; const decimals = data?.[1]?.result as number | undefined; - // form schema for sending transaction const formSchema = z.object({ - // address is a required field address: z .string() .min(2) @@ -147,7 +135,6 @@ export default function WriteContract() { .refine((val) => val === "" || isAddress(val), { message: "Invalid address format", }) as z.ZodType
, - // amount is a required field amount: z .string() .refine((val) => !isNaN(parseFloat(val)) && parseFloat(val) > 0, { @@ -158,7 +145,7 @@ export default function WriteContract() { }) .superRefine((val, ctx) => { if (!maxBalance || !decimals) return; - + const inputAmount = parseUnits(val, decimals as number); if (inputAmount > (maxBalance as bigint)) { @@ -170,66 +157,57 @@ export default function WriteContract() { }), }); - // 1. Define your form. const form = useForm>({ - // resolver is zodResolver resolver: zodResolver(formSchema), - // default values for address and amount defaultValues: { address: "", amount: "", }, }); - - // 2. Define a submit handler. async function onSubmit(values: z.infer) { if (address) { - writeContractAsync({ + await writeContractAsync({ account: await getSigpassWallet(), address: USDC_CONTRACT_ADDRESS, abi: erc20AbiExtend, - functionName: 'transfer', - args: [values.address as Address, parseUnits(values.amount, decimals as number)], + functionName: "transfer", + args: [ + values.address as Address, + parseUnits(values.amount, decimals as number), + ], chainId: westendAssetHub.id, }); } else { - // Fallback to connected wallet - writeContractAsync({ + await writeContractAsync({ address: USDC_CONTRACT_ADDRESS, abi: erc20AbiExtend, - functionName: 'transfer', - args: [values.address as Address, parseUnits(values.amount, decimals as number)], + functionName: "transfer", + args: [ + values.address as Address, + parseUnits(values.amount, decimals as number), + ], chainId: westendAssetHub.id, }); } } - // Watch for transaction hash and open dialog/drawer when received useEffect(() => { - if (hash) { - setOpen(true); - } + if (hash) setOpen(true); }, [hash]); - - // useWaitForTransactionReceipt hook to wait for transaction receipt const { isLoading: isConfirming, isSuccess: isConfirmed } = useWaitForTransactionReceipt({ hash, config: address ? localConfig : config, }); - // when isConfirmed, refetch the balance of the address useEffect(() => { - if (isConfirmed) { - refetch(); - } + if (isConfirmed) refetch(); }, [isConfirmed, refetch]); - return ( -
+
( - Receiving Address + Receiving Address - The address to send USDC to + + The address to send USDC to + )} @@ -251,20 +231,21 @@ export default function WriteContract() { name="amount" render={({ field }) => ( -
+
Amount -
- {maxBalance ? formatUnits(maxBalance as bigint, decimals as number) : } USDC +
+ + {maxBalance ? ( + formatUnits(maxBalance, decimals as number) + ) : ( + + )}{" "} + USDC
{isDesktop ? ( - + ) : ( )} /> - { - isPending ? ( - - ) : ( - - ) - } + + {isPending ? ( + + ) : ( + + )} - { - // Desktop would be using dialog - isDesktop ? ( - - - - - - - Transaction status - - - Follow the transaction status below. - -
- {hash ? ( -
- - Transaction Hash - - {truncateHash(hash)} - - - -
- ) : ( -
- - No transaction hash -
- )} - { - !isPending && !isConfirmed && !isConfirming && ( -
- No transaction submitted -
- ) - } - {isConfirming && ( -
- Waiting - for confirmation... -
- )} - {isConfirmed && ( -
- Transaction confirmed! -
- )} - {error && ( -
- Error:{" "} - {(error as BaseError).shortMessage || error.message} -
- )} -
- - - - - -
-
- ) : ( - // Mobile would be using drawer - - - - - - - Transaction status - - Follow the transaction status below. - - -
- {hash ? ( -
- - Transaction Hash - - {truncateHash(hash)} - - - -
- ) : ( -
- - No transaction hash -
- )} - { - !isPending && !isConfirmed && !isConfirming && ( -
- No transaction submitted -
- ) - } - {isConfirming && ( -
- Waiting - for confirmation... -
- )} - {isConfirmed && ( -
- Transaction confirmed! -
- )} - {error && ( -
- Error:{" "} - {(error as BaseError).shortMessage || error.message} -
- )} -
- - - - - -
-
- ) - } + + {isDesktop ? ( + + + + + + + Transaction status + + + Follow every step—from wallet signature to confirmation. + + + + + + + + + + ) : ( + + + + + + + Transaction status + + Follow every step—from wallet signature to confirmation. + + +
+ +
+ + + + + +
+
+ )}
); } + +/* --------------------------------------------------------------------- */ +/* helper component */ +/* --------------------------------------------------------------------- */ + +type StatusProps = { + hash?: `0x${string}`; + isPending: boolean; + isConfirming: boolean; + isConfirmed: boolean; + error: BaseError | WriteContractErrorType | null | undefined; + explorerUrl?: string; +}; + +function StatusBody({ + hash, + isPending, + isConfirming, + isConfirmed, + error, + explorerUrl, +}: StatusProps) { + return ( +
+ {hash ? ( +
+ + Tx Hash + + {truncateHash(hash)} + + + +
+ ) : ( +
+ + No hash +
+ )} + + {isPending && ( +
+ + Awaiting signature in wallet… +
+ )} + + {!isPending && !isConfirming && !isConfirmed && ( +
+ No transaction +
+ )} + + {isConfirming && ( +
+ + Broadcast to network—waiting for confirmations… +
+ )} + + {isConfirmed && ( +
+ + Confirmed on-chain! +
+ )} + + {error && ( +
+ + {"shortMessage" in (error as BaseError) + ? (error as BaseError).shortMessage + : (error as Error).message} +
+ )} +
+ ); +} \ No newline at end of file diff --git a/challenge-3-frontend/components/yield-farm/index.tsx b/challenge-3-frontend/components/yield-farm/index.tsx new file mode 100644 index 0000000..73e7ea7 --- /dev/null +++ b/challenge-3-frontend/components/yield-farm/index.tsx @@ -0,0 +1,107 @@ +"use client"; + +import { useMemo } from "react"; +import { formatUnits } from "viem"; +import { useReadContract } from "wagmi"; +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from "@/components/ui/tabs"; +import { + Card, + CardHeader, + CardTitle, + CardDescription, + CardContent, +} from "@/components/ui/card"; +import Stake from "./stake"; +import Withdraw from "./withdraw"; +import { + LIQUIDITY_POOL_TOKEN_CONTRACT_ADDRESS, + YIELD_FARMING_CONTRACT_ADDRESS, +} from "@/lib/config"; +import { mockErc20Abi, yieldFarmingAbi } from "@/lib/abi"; +import { Skeleton } from "@/components/ui/skeleton"; + +export default function YieldFarm() { + /* ------------------------------------------------------------ */ + /* On-chain pooled metrics */ + /* ------------------------------------------------------------ */ + const { data: tvlRaw } = useReadContract({ + address: LIQUIDITY_POOL_TOKEN_CONTRACT_ADDRESS, + abi: mockErc20Abi, + functionName: "totalSupply", + }); + + const { data: rewardRateRaw } = useReadContract({ + address: YIELD_FARMING_CONTRACT_ADDRESS, + abi: yieldFarmingAbi, + functionName: "rewardRate", + }); + + const tvl = useMemo( + () => (tvlRaw ? formatUnits(tvlRaw as bigint, 18) : null), + [tvlRaw] + ); + + const rewardRate = useMemo( + () => (rewardRateRaw ? formatUnits(rewardRateRaw as bigint, 18) : null), + [rewardRateRaw] + ); + + /* ------------------------------------------------------------ */ + /* UI */ + /* ------------------------------------------------------------ */ + return ( +
+ {/* Pool statistics */} + + + Pool Statistics + Updated live on-chain + + + + + + + + {/* Stake / Withdraw tabs */} + + + Stake + Withdraw + + + + + + + + + +
+ ); +} + +/* ------------------------------------------------------------ */ +/* Helper component */ +/* ------------------------------------------------------------ */ + +function Stat({ label, value }: { label: string; value?: string | null }) { + return ( +
+ {label} + {value ? ( + {value} + ) : ( + + )} +
+ ); +} \ No newline at end of file diff --git a/challenge-3-frontend/components/yield-farm/mint-lp-token.tsx b/challenge-3-frontend/components/yield-farm/mint-lp-token.tsx new file mode 100644 index 0000000..e016073 --- /dev/null +++ b/challenge-3-frontend/components/yield-farm/mint-lp-token.tsx @@ -0,0 +1,98 @@ +"use client"; + +import { useEffect } from "react"; +import { + useWaitForTransactionReceipt, + useConfig, + useWriteContract, + useAccount, + useReadContract, +} from "wagmi"; +import { parseUnits } from "viem"; +import { Loader2 } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { getSigpassWallet } from "@/lib/sigpass"; +import { useAtomValue } from "jotai"; +import { addressAtom } from "@/components/sigpasskit"; +import { localConfig, westendAssetHub } from "@/app/providers"; +import { LIQUIDITY_POOL_TOKEN_CONTRACT_ADDRESS } from "@/lib/config"; +import { mockErc20Abi } from "@/lib/abi"; + +type Props = { + label: string; +}; + +export default function MintLpToken({ label }: Props) { + const config = useConfig(); + const account = useAccount(); + const address = useAtomValue(addressAtom); + + const { + data: hash, + isPending, + writeContractAsync, + } = useWriteContract({ + config: address ? localConfig : config, + }); + + const { data: decimalsData, refetch } = useReadContract({ + address: LIQUIDITY_POOL_TOKEN_CONTRACT_ADDRESS, + abi: mockErc20Abi, + functionName: "decimals", + chainId: westendAssetHub.id, + config: address ? localConfig : config, + }); + + const decimals = decimalsData as number | undefined; + + const { isLoading: isConfirming, isSuccess: isConfirmed } = + useWaitForTransactionReceipt({ + hash, + config: address ? localConfig : config, + }); + + const handleMint = async () => { + try { + const args = [ + address ?? account.address, + parseUnits("1000", decimals as number), + ] as const; + + if (address) { + await writeContractAsync({ + account: await getSigpassWallet(), + address: LIQUIDITY_POOL_TOKEN_CONTRACT_ADDRESS, + abi: mockErc20Abi, + functionName: "mint", + args, + chainId: westendAssetHub.id, + }); + } else { + await writeContractAsync({ + address: LIQUIDITY_POOL_TOKEN_CONTRACT_ADDRESS, + abi: mockErc20Abi, + functionName: "mint", + args, + chainId: westendAssetHub.id, + }); + } + } catch (error) { + console.error(error); + } + }; + + useEffect(() => { + if (isConfirmed) { + refetch(); + } + }, [isConfirmed, refetch]); + + return ( +
+ +
+ ); +} \ No newline at end of file diff --git a/challenge-3-frontend/components/yield-farm/stake.tsx b/challenge-3-frontend/components/yield-farm/stake.tsx new file mode 100644 index 0000000..b0c084c --- /dev/null +++ b/challenge-3-frontend/components/yield-farm/stake.tsx @@ -0,0 +1,487 @@ +"use client"; + +import { useState, useEffect } from "react"; +import { + type BaseError, + useWaitForTransactionReceipt, + useConfig, + useWriteContract, + useReadContracts, + useAccount, +} from "wagmi"; +import type { WriteContractErrorType } from "wagmi/actions"; +import { parseUnits, formatUnits } from "viem"; +import { + Ban, + ExternalLink, + ChevronDown, + X, + Hash, + LoaderCircle, + CircleCheck, + WalletMinimal, + Lock, +} from "lucide-react"; +import { z } from "zod"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import { Button } from "@/components/ui/button"; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { + Select, + SelectTrigger, + SelectValue, + SelectContent, + SelectGroup, + SelectLabel, + SelectItem, +} from "@/components/ui/select"; +import { Input } from "@/components/ui/input"; +import { useMediaQuery } from "@/hooks/use-media-query"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogFooter, + DialogTitle, + DialogTrigger, + DialogClose, +} from "@/components/ui/dialog"; +import { + Drawer, + DrawerClose, + DrawerContent, + DrawerDescription, + DrawerFooter, + DrawerHeader, + DrawerTitle, + DrawerTrigger, +} from "@/components/ui/drawer"; +import { truncateHash } from "@/lib/utils"; +import CopyButton from "@/components/copy-button"; +import { getSigpassWallet } from "@/lib/sigpass"; +import { westendAssetHub, localConfig } from "@/app/providers"; +import { useAtomValue } from "jotai"; +import { addressAtom } from "@/components/sigpasskit"; +import { Skeleton } from "@/components/ui/skeleton"; +import { mockErc20Abi, yieldFarmingAbi } from "@/lib/abi"; +import { LIQUIDITY_POOL_TOKEN_CONTRACT_ADDRESS, YIELD_FARMING_CONTRACT_ADDRESS } from "@/lib/config"; + +export default function Stake() { + const config = useConfig(); + const account = useAccount(); + const isDesktop = useMediaQuery("(min-width: 768px)"); + const [open, setOpen] = useState(false); + const address = useAtomValue(addressAtom); + + /* ------------------------------- schema ------------------------------- */ + const formSchema = z.object({ + amount: z + .string() + .refine((val) => !isNaN(parseFloat(val)) && parseFloat(val) > 0, { + message: "Amount must be a positive number", + }) + .refine((val) => /^\d*\.?\d{0,18}$/.test(val), { + message: "Amount cannot have more than 18 decimal places", + }) + .superRefine((val, ctx) => { + if (!maxBalance || !decimals) return; + const inputAmount = parseUnits(val, decimals as number); + if (inputAmount > (maxBalance as bigint)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Amount exceeds available balance", + }); + } + }), + lockDays: z.enum(["0", "7", "30", "90"]), + }); + + const form = useForm>({ + resolver: zodResolver(formSchema), + defaultValues: { amount: "", lockDays: "0" }, + }); + + /* ------------------------- on-chain allowances ------------------------ */ + const { + data, + refetch: refetchBalances, + } = useReadContracts({ + contracts: [ + { + address: LIQUIDITY_POOL_TOKEN_CONTRACT_ADDRESS, + abi: mockErc20Abi, + functionName: "balanceOf", + args: [address ?? account.address], + }, + { + address: LIQUIDITY_POOL_TOKEN_CONTRACT_ADDRESS, + abi: mockErc20Abi, + functionName: "decimals", + }, + { + address: LIQUIDITY_POOL_TOKEN_CONTRACT_ADDRESS, + abi: mockErc20Abi, + functionName: "allowance", + args: [address ?? account.address, YIELD_FARMING_CONTRACT_ADDRESS], + }, + ], + config: address ? localConfig : config, + }); + + const maxBalance = data?.[0]?.result as bigint | undefined; + const decimals = data?.[1]?.result as number | undefined; + const allowance = data?.[2]?.result as bigint | undefined; + + const amountInput = form.watch("amount"); + const needsApprove = + allowance !== undefined && amountInput + ? allowance < parseUnits(amountInput, decimals || 18) + : false; + + /* --------------------------- write helpers --------------------------- */ + const { + data: hash, + error, + isPending, + writeContractAsync, + } = useWriteContract({ + config: address ? localConfig : config, + }); + + async function onSubmit(values: z.infer) { + const stakeAmount = parseUnits(values.amount, decimals as number); + + // off-chain analytics only use lockDays + const txArgs = [stakeAmount] as const; + + if (address) { + await writeOrApprove(txArgs, needsApprove, true); + } else { + await writeOrApprove(txArgs, needsApprove, false); + } + } + + async function writeOrApprove( + stakeArgs: readonly [bigint], + approveFirst: boolean, + isSigpass: boolean + ) { + if (approveFirst) { + await writeContractAsync({ + ...(isSigpass && { account: await getSigpassWallet() }), + address: LIQUIDITY_POOL_TOKEN_CONTRACT_ADDRESS, + abi: mockErc20Abi, + functionName: "approve", + args: [YIELD_FARMING_CONTRACT_ADDRESS, stakeArgs[0]], + chainId: westendAssetHub.id, + }); + } else { + await writeContractAsync({ + ...(isSigpass && { account: await getSigpassWallet() }), + address: YIELD_FARMING_CONTRACT_ADDRESS, + abi: yieldFarmingAbi, + functionName: "stake", + args: stakeArgs, + chainId: westendAssetHub.id, + }); + } + } + + /* --------------------------- tx lifecycle ---------------------------- */ + useEffect(() => { + if (hash) setOpen(true); + }, [hash]); + + const { isLoading: isConfirming, isSuccess: isConfirmed } = + useWaitForTransactionReceipt({ + hash, + config: address ? localConfig : config, + }); + + useEffect(() => { + if (isConfirmed) refetchBalances(); + }, [isConfirmed, refetchBalances]); + + /* ------------------------------ render ------------------------------- */ + return ( +
+
+ + {/* amount field */} + ( + +
+ Amount to stake +
+ + {maxBalance ? ( + formatUnits(maxBalance, decimals as number) + ) : ( + + )} +  LP +
+
+ + {isDesktop ? ( + + ) : ( + + )} + + + Flexible deposits earn the base APR; locking boosts rewards. + + +
+ )} + /> + + {/* lock-period selector */} + ( + + + Lock Period + + + + Longer locks receive a higher reward multiplier. + + + + )} + /> + + {/* submit */} + + + + + {/* status dialog / drawer */} + {isDesktop ? ( + + ) : ( + + )} +
+ ); +} + +/* --------------------------------------------------------------------- */ +/* helpers */ +/* --------------------------------------------------------------------- */ + +type StatusProps = { + hash?: `0x${string}`; + isPending: boolean; + isConfirming: boolean; + isConfirmed: boolean; + error: BaseError | WriteContractErrorType | null | undefined; + explorerUrl?: string; +}; + +function StatusBody({ + hash, + isPending, + isConfirming, + isConfirmed, + error, + explorerUrl, +}: StatusProps) { + return ( +
+ {hash ? ( +
+ + Tx Hash + + {truncateHash(hash)} + + + +
+ ) : ( +
+ + No hash +
+ )} + + {isPending && ( +
+ + Awaiting signature in wallet… +
+ )} + + {!isPending && !isConfirming && !isConfirmed && ( +
+ No transaction +
+ )} + + {isConfirming && ( +
+ + Broadcast to network—waiting for confirmations… +
+ )} + + {isConfirmed && ( +
+ + Confirmed on-chain! Funds are now active. +
+ )} + + {error && ( +
+ + {"shortMessage" in (error as BaseError) + ? (error as BaseError).shortMessage + : (error as Error).message} +
+ )} +
+ ); +} + +// StatusDialog and StatusDrawer remain identical except for updated StatusProps +function StatusDialog({ + open, + setOpen, + ...status +}: { open: boolean; setOpen: (v: boolean) => void } & StatusProps) { + return ( + + + + + + + Transaction status + + + Follow every step—from wallet signature to final confirmation. + + + + + + + + + + ); +} + +function StatusDrawer({ + open, + setOpen, + ...status +}: { open: boolean; setOpen: (v: boolean) => void } & StatusProps) { + return ( + + + + + + + Transaction status + + Follow every step—from wallet signature to final confirmation. + + +
+ +
+ + + + + +
+
+ ); +} \ No newline at end of file diff --git a/challenge-3-frontend/components/yield-farm/withdraw.tsx b/challenge-3-frontend/components/yield-farm/withdraw.tsx new file mode 100644 index 0000000..d21ccd4 --- /dev/null +++ b/challenge-3-frontend/components/yield-farm/withdraw.tsx @@ -0,0 +1,446 @@ +"use client"; + +import { useState, useEffect } from "react"; +import { + type BaseError, + useWaitForTransactionReceipt, + useConfig, + useWriteContract, + useReadContracts, + useAccount, +} from "wagmi"; +import type { WriteContractErrorType } from "wagmi/actions"; +import { parseUnits, formatUnits } from "viem"; +import { + Ban, + ExternalLink, + ChevronDown, + X, + Hash, + LoaderCircle, + CircleCheck, + WalletMinimal, +} from "lucide-react"; +import { z } from "zod"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useForm } from "react-hook-form"; +import { Button } from "@/components/ui/button"; +import { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; +import { useMediaQuery } from "@/hooks/use-media-query"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogFooter, + DialogTitle, + DialogTrigger, + DialogClose, +} from "@/components/ui/dialog"; +import { + Drawer, + DrawerClose, + DrawerContent, + DrawerDescription, + DrawerFooter, + DrawerHeader, + DrawerTitle, + DrawerTrigger, +} from "@/components/ui/drawer"; +import { truncateHash } from "@/lib/utils"; +import CopyButton from "@/components/copy-button"; +import { getSigpassWallet } from "@/lib/sigpass"; +import { westendAssetHub } from "@/app/providers"; +import { useAtomValue } from "jotai"; +import { addressAtom } from "@/components/sigpasskit"; +import { localConfig } from "@/app/providers"; +import { mockErc20Abi, yieldFarmingAbi } from "@/lib/abi"; +import { + LIQUIDITY_POOL_TOKEN_CONTRACT_ADDRESS, + YIELD_FARMING_CONTRACT_ADDRESS, +} from "@/lib/config"; +import { Skeleton } from "../ui/skeleton"; + +export default function Withdraw() { + const config = useConfig(); + const account = useAccount(); + const isDesktop = useMediaQuery("(min-width: 768px)"); + const [open, setOpen] = useState(false); + const address = useAtomValue(addressAtom); + const formSchema = z.object({ + amount: z + .string() + .refine((val) => !isNaN(parseFloat(val)) && parseFloat(val) > 0, { + message: "Amount must be a positive number", + }) + .refine((val) => /^\d*\.?\d{0,18}$/.test(val), { + message: "Amount cannot have more than 18 decimal places", + }) + .superRefine((val, ctx) => { + if (!maxBalance || !decimals) return; + + const inputAmount = parseUnits(val, decimals as number); + + if (inputAmount > (maxBalance as bigint)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: "Amount exceeds available balance", + }); + } + }), + }); + + const form = useForm>({ + resolver: zodResolver(formSchema), + defaultValues: { + amount: "", + }, + }); + + const { + data: hash, + error, + isPending, + writeContractAsync, + } = useWriteContract({ + config: address ? localConfig : config, + }); + + const { data, refetch } = useReadContracts({ + contracts: [ + { + address: YIELD_FARMING_CONTRACT_ADDRESS, + abi: yieldFarmingAbi, + functionName: "userInfo", + args: [address ? address : account.address], + }, + { + address: YIELD_FARMING_CONTRACT_ADDRESS, + abi: yieldFarmingAbi, + functionName: "pendingRewards", + args: [address ? address : account.address], + }, + { + address: LIQUIDITY_POOL_TOKEN_CONTRACT_ADDRESS, + abi: mockErc20Abi, + functionName: "decimals", + }, + ], + config: address ? localConfig : config, + }); + + const maxBalance = (data?.[0]?.result as [bigint] | undefined)?.[0]; + const pendingRewards = data?.[1]?.result as bigint | undefined; + const decimals = data?.[2]?.result as number | undefined; + + async function onSubmit(values: z.infer) { + if (address) { + writeContractAsync({ + account: await getSigpassWallet(), + address: YIELD_FARMING_CONTRACT_ADDRESS, + abi: yieldFarmingAbi, + functionName: "withdraw", + args: [parseUnits(values.amount, decimals as number)], + chainId: westendAssetHub.id, + }); + } else { + writeContractAsync({ + address: YIELD_FARMING_CONTRACT_ADDRESS, + abi: yieldFarmingAbi, + functionName: "withdraw", + args: [parseUnits(values.amount, decimals as number)], + chainId: westendAssetHub.id, + }); + } + } + + const handleClaim = async () => { + if (address) { + writeContractAsync({ + account: await getSigpassWallet(), + address: YIELD_FARMING_CONTRACT_ADDRESS, + abi: yieldFarmingAbi, + functionName: "claimRewards", + chainId: westendAssetHub.id, + }); + } else { + writeContractAsync({ + address: YIELD_FARMING_CONTRACT_ADDRESS, + abi: yieldFarmingAbi, + functionName: "claimRewards", + chainId: westendAssetHub.id, + }); + } + }; + + useEffect(() => { + if (hash) { + setOpen(true); + } + }, [hash]); + + const { isLoading: isConfirming, isSuccess: isConfirmed } = + useWaitForTransactionReceipt({ + hash, + config: address ? localConfig : config, + }); + + useEffect(() => { + if (isConfirmed) { + refetch(); + } + }, [isConfirmed, refetch]); + + return ( +
+ {pendingRewards && pendingRewards > 0 ? ( + <> + + Total reward:  + {formatUnits(pendingRewards as bigint, decimals as number)} + + + + ) : null} +
+ + ( + +
+ Amount to unstake +
+ {" "} + {maxBalance ? ( + formatUnits(maxBalance as bigint, decimals as number) + ) : ( + + )}{" "} + LP Token +
+
+ + {isDesktop ? ( + + ) : ( + + )} + + + The amount of LPToken to unstake + + +
+ )} + /> +
+ {isPending ? ( + + ) : ( + + )} +
+ + + { + // Desktop would be using dialog + isDesktop ? ( + + ) : ( + // Mobile would be using drawer + + ) + } +
+ ); +} + +/* --------------------------------------------------------------------- */ +/* helpers */ +/* --------------------------------------------------------------------- */ + +type StatusProps = { + hash?: `0x${string}`; + isPending: boolean; + isConfirming: boolean; + isConfirmed: boolean; + error: BaseError | WriteContractErrorType | null | undefined; + explorerUrl?: string; +}; + +function StatusBody({ + hash, + isPending, + isConfirming, + isConfirmed, + error, + explorerUrl, +}: StatusProps) { + return ( +
+ {hash ? ( +
+ + Transaction Hash + + {truncateHash(hash)} + + + +
+ ) : ( +
+ + No transaction hash +
+ )} + + {isPending && ( +
+ Awaiting + signature in wallet… +
+ )} + + {!isPending && !isConfirmed && !isConfirming && ( +
+ No transaction submitted +
+ )} + {isConfirming && ( +
+ Broadcast to + network—waiting for confirmations… +
+ )} + {isConfirmed && ( +
+ Transaction confirmed! +
+ )} + {error && ( +
+ {" "} + {"shortMessage" in (error as BaseError) + ? (error as BaseError).shortMessage + : (error as Error).message} +
+ )} +
+ ); +} + +function StatusDialog({ + open, + setOpen, + ...status +}: { open: boolean; setOpen: (v: boolean) => void } & StatusProps) { + return ( + + + + + + + Transaction status + + + Follow every step—from wallet signature to final confirmation. + + + + + + + + + + ); +} + +function StatusDrawer({ + open, + setOpen, + ...status +}: { open: boolean; setOpen: (v: boolean) => void } & StatusProps) { + return ( + + + + + + + Transaction status + + Follow every step—from wallet signature to final confirmation. + + +
+ +
+ + + + + +
+
+ ); +} \ No newline at end of file diff --git a/challenge-3-frontend/lib/abi.ts b/challenge-3-frontend/lib/abi.ts index 78ac757..d1f64a9 100644 --- a/challenge-3-frontend/lib/abi.ts +++ b/challenge-3-frontend/lib/abi.ts @@ -1,2419 +1,3699 @@ // ERC-20 token ABI export const erc20Abi = [ - { - inputs: [ - { - internalType: "address", - name: "initialOwner", - type: "address", - }, - ], - stateMutability: "nonpayable", - type: "constructor", - }, - { - inputs: [], - name: "ECDSAInvalidSignature", - type: "error", - }, - { - inputs: [ - { - internalType: "uint256", - name: "length", - type: "uint256", - }, - ], - name: "ECDSAInvalidSignatureLength", - type: "error", - }, - { - inputs: [ - { - internalType: "bytes32", - name: "s", - type: "bytes32", - }, - ], - name: "ECDSAInvalidSignatureS", - type: "error", - }, - { - inputs: [ - { - internalType: "address", - name: "spender", - type: "address", - }, - { - internalType: "uint256", - name: "allowance", - type: "uint256", - }, - { - internalType: "uint256", - name: "needed", - type: "uint256", - }, - ], - name: "ERC20InsufficientAllowance", - type: "error", - }, - { - inputs: [ - { - internalType: "address", - name: "sender", - type: "address", - }, - { - internalType: "uint256", - name: "balance", - type: "uint256", - }, - { - internalType: "uint256", - name: "needed", - type: "uint256", - }, - ], - name: "ERC20InsufficientBalance", - type: "error", - }, - { - inputs: [ - { - internalType: "address", - name: "approver", - type: "address", - }, - ], - name: "ERC20InvalidApprover", - type: "error", - }, - { - inputs: [ - { - internalType: "address", - name: "receiver", - type: "address", - }, - ], - name: "ERC20InvalidReceiver", - type: "error", - }, - { - inputs: [ - { - internalType: "address", - name: "sender", - type: "address", - }, - ], - name: "ERC20InvalidSender", - type: "error", - }, - { - inputs: [ - { - internalType: "address", - name: "spender", - type: "address", - }, - ], - name: "ERC20InvalidSpender", - type: "error", - }, - { - inputs: [ - { - internalType: "uint256", - name: "deadline", - type: "uint256", - }, - ], - name: "ERC2612ExpiredSignature", - type: "error", - }, - { - inputs: [ - { - internalType: "address", - name: "signer", - type: "address", - }, - { - internalType: "address", - name: "owner", - type: "address", - }, - ], - name: "ERC2612InvalidSigner", - type: "error", - }, - { - inputs: [ - { - internalType: "uint256", - name: "maxLoan", - type: "uint256", - }, - ], - name: "ERC3156ExceededMaxLoan", - type: "error", - }, - { - inputs: [ - { - internalType: "address", - name: "receiver", - type: "address", - }, - ], - name: "ERC3156InvalidReceiver", - type: "error", - }, - { - inputs: [ - { - internalType: "address", - name: "token", - type: "address", - }, - ], - name: "ERC3156UnsupportedToken", - type: "error", - }, - { - inputs: [], - name: "EnforcedPause", - type: "error", - }, - { - inputs: [], - name: "ExpectedPause", - type: "error", - }, - { - inputs: [ - { - internalType: "address", - name: "account", - type: "address", - }, - { - internalType: "uint256", - name: "currentNonce", - type: "uint256", - }, - ], - name: "InvalidAccountNonce", - type: "error", - }, - { - inputs: [], - name: "InvalidShortString", - type: "error", - }, - { - inputs: [ - { - internalType: "address", - name: "owner", - type: "address", - }, - ], - name: "OwnableInvalidOwner", - type: "error", - }, - { - inputs: [ - { - internalType: "address", - name: "account", - type: "address", - }, - ], - name: "OwnableUnauthorizedAccount", - type: "error", - }, - { - inputs: [ - { - internalType: "string", - name: "str", - type: "string", - }, - ], - name: "StringTooLong", - type: "error", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "address", - name: "owner", - type: "address", - }, - { - indexed: true, - internalType: "address", - name: "spender", - type: "address", - }, - { - indexed: false, - internalType: "uint256", - name: "value", - type: "uint256", - }, - ], - name: "Approval", - type: "event", - }, - { - anonymous: false, - inputs: [], - name: "EIP712DomainChanged", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "address", - name: "previousOwner", - type: "address", - }, - { - indexed: true, - internalType: "address", - name: "newOwner", - type: "address", - }, - ], - name: "OwnershipTransferred", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: "address", - name: "account", - type: "address", - }, - ], - name: "Paused", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: true, - internalType: "address", - name: "from", - type: "address", - }, - { - indexed: true, - internalType: "address", - name: "to", - type: "address", - }, - { - indexed: false, - internalType: "uint256", - name: "value", - type: "uint256", - }, - ], - name: "Transfer", - type: "event", - }, - { - anonymous: false, - inputs: [ - { - indexed: false, - internalType: "address", - name: "account", - type: "address", - }, - ], - name: "Unpaused", - type: "event", - }, - { - inputs: [], - name: "DOMAIN_SEPARATOR", - outputs: [ - { - internalType: "bytes32", - name: "", - type: "bytes32", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "owner", - type: "address", - }, - { - internalType: "address", - name: "spender", - type: "address", - }, - ], - name: "allowance", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "spender", - type: "address", - }, - { - internalType: "uint256", - name: "value", - type: "uint256", - }, - ], - name: "approve", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "account", - type: "address", - }, - ], - name: "balanceOf", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "uint256", - name: "value", - type: "uint256", - }, - ], - name: "burn", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "account", - type: "address", - }, - { - internalType: "uint256", - name: "value", - type: "uint256", - }, - ], - name: "burnFrom", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [], - name: "decimals", - outputs: [ - { - internalType: "uint8", - name: "", - type: "uint8", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "eip712Domain", - outputs: [ - { - internalType: "bytes1", - name: "fields", - type: "bytes1", - }, - { - internalType: "string", - name: "name", - type: "string", - }, - { - internalType: "string", - name: "version", - type: "string", - }, - { - internalType: "uint256", - name: "chainId", - type: "uint256", - }, - { - internalType: "address", - name: "verifyingContract", - type: "address", - }, - { - internalType: "bytes32", - name: "salt", - type: "bytes32", - }, - { - internalType: "uint256[]", - name: "extensions", - type: "uint256[]", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "token", - type: "address", - }, - { - internalType: "uint256", - name: "value", - type: "uint256", - }, - ], - name: "flashFee", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "contract IERC3156FlashBorrower", - name: "receiver", - type: "address", - }, - { - internalType: "address", - name: "token", - type: "address", - }, - { - internalType: "uint256", - name: "value", - type: "uint256", - }, - { - internalType: "bytes", - name: "data", - type: "bytes", - }, - ], - name: "flashLoan", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "token", - type: "address", - }, - ], - name: "maxFlashLoan", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "to", - type: "address", - }, - { - internalType: "uint256", - name: "amount", - type: "uint256", - }, - ], - name: "mint", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [], - name: "name", - outputs: [ - { - internalType: "string", - name: "", - type: "string", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "owner", - type: "address", - }, - ], - name: "nonces", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "owner", - outputs: [ - { - internalType: "address", - name: "", - type: "address", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "pause", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [], - name: "paused", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "owner", - type: "address", - }, - { - internalType: "address", - name: "spender", - type: "address", - }, - { - internalType: "uint256", - name: "value", - type: "uint256", - }, - { - internalType: "uint256", - name: "deadline", - type: "uint256", - }, - { - internalType: "uint8", - name: "v", - type: "uint8", - }, - { - internalType: "bytes32", - name: "r", - type: "bytes32", - }, - { - internalType: "bytes32", - name: "s", - type: "bytes32", - }, - ], - name: "permit", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [], - name: "renounceOwnership", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [], - name: "symbol", - outputs: [ - { - internalType: "string", - name: "", - type: "string", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [], - name: "totalSupply", - outputs: [ - { - internalType: "uint256", - name: "", - type: "uint256", - }, - ], - stateMutability: "view", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "to", - type: "address", - }, - { - internalType: "uint256", - name: "value", - type: "uint256", - }, - ], - name: "transfer", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "from", - type: "address", - }, - { - internalType: "address", - name: "to", - type: "address", - }, - { - internalType: "uint256", - name: "value", - type: "uint256", - }, - ], - name: "transferFrom", - outputs: [ - { - internalType: "bool", - name: "", - type: "bool", - }, - ], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [ - { - internalType: "address", - name: "newOwner", - type: "address", - }, - ], - name: "transferOwnership", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, - { - inputs: [], - name: "unpause", - outputs: [], - stateMutability: "nonpayable", - type: "function", - }, + { + inputs: [ + { + internalType: "address", + name: "initialOwner", + type: "address", + }, + ], + stateMutability: "nonpayable", + type: "constructor", + }, + { + inputs: [], + name: "ECDSAInvalidSignature", + type: "error", + }, + { + inputs: [ + { + internalType: "uint256", + name: "length", + type: "uint256", + }, + ], + name: "ECDSAInvalidSignatureLength", + type: "error", + }, + { + inputs: [ + { + internalType: "bytes32", + name: "s", + type: "bytes32", + }, + ], + name: "ECDSAInvalidSignatureS", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "spender", + type: "address", + }, + { + internalType: "uint256", + name: "allowance", + type: "uint256", + }, + { + internalType: "uint256", + name: "needed", + type: "uint256", + }, + ], + name: "ERC20InsufficientAllowance", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "sender", + type: "address", + }, + { + internalType: "uint256", + name: "balance", + type: "uint256", + }, + { + internalType: "uint256", + name: "needed", + type: "uint256", + }, + ], + name: "ERC20InsufficientBalance", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "approver", + type: "address", + }, + ], + name: "ERC20InvalidApprover", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "receiver", + type: "address", + }, + ], + name: "ERC20InvalidReceiver", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "sender", + type: "address", + }, + ], + name: "ERC20InvalidSender", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "spender", + type: "address", + }, + ], + name: "ERC20InvalidSpender", + type: "error", + }, + { + inputs: [ + { + internalType: "uint256", + name: "deadline", + type: "uint256", + }, + ], + name: "ERC2612ExpiredSignature", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "signer", + type: "address", + }, + { + internalType: "address", + name: "owner", + type: "address", + }, + ], + name: "ERC2612InvalidSigner", + type: "error", + }, + { + inputs: [ + { + internalType: "uint256", + name: "maxLoan", + type: "uint256", + }, + ], + name: "ERC3156ExceededMaxLoan", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "receiver", + type: "address", + }, + ], + name: "ERC3156InvalidReceiver", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + ], + name: "ERC3156UnsupportedToken", + type: "error", + }, + { + inputs: [], + name: "EnforcedPause", + type: "error", + }, + { + inputs: [], + name: "ExpectedPause", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address", + }, + { + internalType: "uint256", + name: "currentNonce", + type: "uint256", + }, + ], + name: "InvalidAccountNonce", + type: "error", + }, + { + inputs: [], + name: "InvalidShortString", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "owner", + type: "address", + }, + ], + name: "OwnableInvalidOwner", + type: "error", + }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "OwnableUnauthorizedAccount", + type: "error", + }, + { + inputs: [ + { + internalType: "string", + name: "str", + type: "string", + }, + ], + name: "StringTooLong", + type: "error", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "owner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "spender", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "Approval", + type: "event", + }, + { + anonymous: false, + inputs: [], + name: "EIP712DomainChanged", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "previousOwner", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "newOwner", + type: "address", + }, + ], + name: "OwnershipTransferred", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "Paused", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: "address", + name: "from", + type: "address", + }, + { + indexed: true, + internalType: "address", + name: "to", + type: "address", + }, + { + indexed: false, + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "Transfer", + type: "event", + }, + { + anonymous: false, + inputs: [ + { + indexed: false, + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "Unpaused", + type: "event", + }, + { + inputs: [], + name: "DOMAIN_SEPARATOR", + outputs: [ + { + internalType: "bytes32", + name: "", + type: "bytes32", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "owner", + type: "address", + }, + { + internalType: "address", + name: "spender", + type: "address", + }, + ], + name: "allowance", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "spender", + type: "address", + }, + { + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "approve", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address", + }, + ], + name: "balanceOf", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "burn", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "account", + type: "address", + }, + { + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "burnFrom", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "decimals", + outputs: [ + { + internalType: "uint8", + name: "", + type: "uint8", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "eip712Domain", + outputs: [ + { + internalType: "bytes1", + name: "fields", + type: "bytes1", + }, + { + internalType: "string", + name: "name", + type: "string", + }, + { + internalType: "string", + name: "version", + type: "string", + }, + { + internalType: "uint256", + name: "chainId", + type: "uint256", + }, + { + internalType: "address", + name: "verifyingContract", + type: "address", + }, + { + internalType: "bytes32", + name: "salt", + type: "bytes32", + }, + { + internalType: "uint256[]", + name: "extensions", + type: "uint256[]", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + { + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "flashFee", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "contract IERC3156FlashBorrower", + name: "receiver", + type: "address", + }, + { + internalType: "address", + name: "token", + type: "address", + }, + { + internalType: "uint256", + name: "value", + type: "uint256", + }, + { + internalType: "bytes", + name: "data", + type: "bytes", + }, + ], + name: "flashLoan", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "token", + type: "address", + }, + ], + name: "maxFlashLoan", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "to", + type: "address", + }, + { + internalType: "uint256", + name: "amount", + type: "uint256", + }, + ], + name: "mint", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "name", + outputs: [ + { + internalType: "string", + name: "", + type: "string", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "owner", + type: "address", + }, + ], + name: "nonces", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "owner", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "pause", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "paused", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "owner", + type: "address", + }, + { + internalType: "address", + name: "spender", + type: "address", + }, + { + internalType: "uint256", + name: "value", + type: "uint256", + }, + { + internalType: "uint256", + name: "deadline", + type: "uint256", + }, + { + internalType: "uint8", + name: "v", + type: "uint8", + }, + { + internalType: "bytes32", + name: "r", + type: "bytes32", + }, + { + internalType: "bytes32", + name: "s", + type: "bytes32", + }, + ], + name: "permit", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "renounceOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "symbol", + outputs: [ + { + internalType: "string", + name: "", + type: "string", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [], + name: "totalSupply", + outputs: [ + { + internalType: "uint256", + name: "", + type: "uint256", + }, + ], + stateMutability: "view", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "to", + type: "address", + }, + { + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "transfer", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "from", + type: "address", + }, + { + internalType: "address", + name: "to", + type: "address", + }, + { + internalType: "uint256", + name: "value", + type: "uint256", + }, + ], + name: "transferFrom", + outputs: [ + { + internalType: "bool", + name: "", + type: "bool", + }, + ], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [ + { + internalType: "address", + name: "newOwner", + type: "address", + }, + ], + name: "transferOwnership", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, + { + inputs: [], + name: "unpause", + outputs: [], + stateMutability: "nonpayable", + type: "function", + }, ]; -// ERC-20 token ABI Extend +// ERC-20 token ABI Extend export const erc20AbiExtend = [ - { - "inputs": [ - { - "internalType": "address", - "name": "initialOwner", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [], - "name": "ECDSAInvalidSignature", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "length", - "type": "uint256" - } - ], - "name": "ECDSAInvalidSignatureLength", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "ECDSAInvalidSignatureS", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "allowance", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "needed", - "type": "uint256" - } - ], - "name": "ERC20InsufficientAllowance", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "balance", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "needed", - "type": "uint256" - } - ], - "name": "ERC20InsufficientBalance", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "approver", - "type": "address" - } - ], - "name": "ERC20InvalidApprover", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "ERC20InvalidReceiver", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "sender", - "type": "address" - } - ], - "name": "ERC20InvalidSender", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - } - ], - "name": "ERC20InvalidSpender", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - } - ], - "name": "ERC2612ExpiredSignature", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "signer", - "type": "address" - }, - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "ERC2612InvalidSigner", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "maxLoan", - "type": "uint256" - } - ], - "name": "ERC3156ExceededMaxLoan", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "ERC3156InvalidReceiver", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - } - ], - "name": "ERC3156UnsupportedToken", - "type": "error" - }, - { - "inputs": [], - "name": "EnforcedPause", - "type": "error" - }, - { - "inputs": [], - "name": "ExpectedPause", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "uint256", - "name": "currentNonce", - "type": "uint256" - } - ], - "name": "InvalidAccountNonce", - "type": "error" - }, - { - "inputs": [], - "name": "InvalidShortString", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "OwnableInvalidOwner", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "OwnableUnauthorizedAccount", - "type": "error" - }, - { - "inputs": [ - { - "internalType": "string", - "name": "str", - "type": "string" - } - ], - "name": "StringTooLong", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Approval", - "type": "event" - }, - { - "anonymous": false, - "inputs": [], - "name": "EIP712DomainChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Paused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "Transfer", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Unpaused", - "type": "event" - }, - { - "inputs": [], - "name": "DOMAIN_SEPARATOR", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - } - ], - "name": "allowance", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "approve", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "balanceOf", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "burn", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "account", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "burnFrom", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "decimals", - "outputs": [ - { - "internalType": "uint8", - "name": "", - "type": "uint8" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "eip712Domain", - "outputs": [ - { - "internalType": "bytes1", - "name": "fields", - "type": "bytes1" - }, - { - "internalType": "string", - "name": "name", - "type": "string" - }, - { - "internalType": "string", - "name": "version", - "type": "string" - }, - { - "internalType": "uint256", - "name": "chainId", - "type": "uint256" - }, - { - "internalType": "address", - "name": "verifyingContract", - "type": "address" - }, - { - "internalType": "bytes32", - "name": "salt", - "type": "bytes32" - }, - { - "internalType": "uint256[]", - "name": "extensions", - "type": "uint256[]" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "flashFee", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "contract IERC3156FlashBorrower", - "name": "receiver", - "type": "address" - }, - { - "internalType": "address", - "name": "token", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "flashLoan", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "token", - "type": "address" - } - ], - "name": "maxFlashLoan", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - } - ], - "name": "mint", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "name", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - } - ], - "name": "nonces", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "pause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "paused", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "owner", - "type": "address" - }, - { - "internalType": "address", - "name": "spender", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "deadline", - "type": "uint256" - }, - { - "internalType": "uint8", - "name": "v", - "type": "uint8" - }, - { - "internalType": "bytes32", - "name": "r", - "type": "bytes32" - }, - { - "internalType": "bytes32", - "name": "s", - "type": "bytes32" - } - ], - "name": "permit", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "symbol", - "outputs": [ - { - "internalType": "string", - "name": "", - "type": "string" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "totalSupply", - "outputs": [ - { - "internalType": "uint256", - "name": "", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transfer", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "from", - "type": "address" - }, - { - "internalType": "address", - "name": "to", - "type": "address" - }, - { - "internalType": "uint256", - "name": "value", - "type": "uint256" - } - ], - "name": "transferFrom", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "unpause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } + { + "inputs": [ + { + "internalType": "address", + "name": "initialOwner", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "ECDSAInvalidSignature", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "length", + "type": "uint256" + } + ], + "name": "ECDSAInvalidSignatureLength", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "ECDSAInvalidSignatureS", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "allowance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "ERC20InsufficientAllowance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "ERC20InsufficientBalance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "approver", + "type": "address" + } + ], + "name": "ERC20InvalidApprover", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "ERC20InvalidReceiver", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "ERC20InvalidSender", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "ERC20InvalidSpender", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + } + ], + "name": "ERC2612ExpiredSignature", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "signer", + "type": "address" + }, + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "ERC2612InvalidSigner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "maxLoan", + "type": "uint256" + } + ], + "name": "ERC3156ExceededMaxLoan", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "ERC3156InvalidReceiver", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "ERC3156UnsupportedToken", + "type": "error" + }, + { + "inputs": [], + "name": "EnforcedPause", + "type": "error" + }, + { + "inputs": [], + "name": "ExpectedPause", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "currentNonce", + "type": "uint256" + } + ], + "name": "InvalidAccountNonce", + "type": "error" + }, + { + "inputs": [], + "name": "InvalidShortString", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnableInvalidOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "OwnableUnauthorizedAccount", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "str", + "type": "string" + } + ], + "name": "StringTooLong", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [], + "name": "EIP712DomainChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [], + "name": "DOMAIN_SEPARATOR", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "burn", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "burnFrom", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "eip712Domain", + "outputs": [ + { + "internalType": "bytes1", + "name": "fields", + "type": "bytes1" + }, + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "version", + "type": "string" + }, + { + "internalType": "uint256", + "name": "chainId", + "type": "uint256" + }, + { + "internalType": "address", + "name": "verifyingContract", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "salt", + "type": "bytes32" + }, + { + "internalType": "uint256[]", + "name": "extensions", + "type": "uint256[]" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "flashFee", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IERC3156FlashBorrower", + "name": "receiver", + "type": "address" + }, + { + "internalType": "address", + "name": "token", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "flashLoan", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "token", + "type": "address" + } + ], + "name": "maxFlashLoan", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "nonces", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "deadline", + "type": "uint256" + }, + { + "internalType": "uint8", + "name": "v", + "type": "uint8" + }, + { + "internalType": "bytes32", + "name": "r", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "s", + "type": "bytes32" + } + ], + "name": "permit", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } ]; // Moonbeam SLpX ABI Contract export const moonbeamSlpxAbi = [ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "previousAdmin", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "AdminChanged", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "beacon", - "type": "address" - } - ], - "name": "BeaconUpgraded", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "implementation", - "type": "address" - } - ], - "name": "Upgraded", - "type": "event" - }, - { - "stateMutability": "payable", - "type": "fallback" - }, - { - "inputs": [], - "name": "admin", - "outputs": [ - { - "internalType": "address", - "name": "admin_", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newAdmin", - "type": "address" - } - ], - "name": "changeAdmin", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "implementation", - "outputs": [ - { - "internalType": "address", - "name": "implementation_", - "type": "address" - } - ], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - } - ], - "name": "upgradeTo", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newImplementation", - "type": "address" - }, - { - "internalType": "bytes", - "name": "data", - "type": "bytes" - } - ], - "name": "upgradeToAndCall", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "stateMutability": "payable", - "type": "receive" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "assetAddress", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint128", - "name": "amount", - "type": "uint128" - }, - { - "indexed": false, - "internalType": "uint64", - "name": "dest_chain_id", - "type": "uint64" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "receiver", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "string", - "name": "remark", - "type": "string" - }, - { - "indexed": false, - "internalType": "uint32", - "name": "channel_id", - "type": "uint32" - } - ], - "name": "CreateOrder", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint8", - "name": "version", - "type": "uint8" - } - ], - "name": "Initialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "minter", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "assetAddress", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "callcode", - "type": "bytes" - }, - { - "indexed": false, - "internalType": "string", - "name": "remark", - "type": "string" - } - ], - "name": "Mint", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Paused", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "redeemer", - "type": "address" - }, - { - "indexed": false, - "internalType": "address", - "name": "assetAddress", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "callcode", - "type": "bytes" - } - ], - "name": "Redeem", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "address", - "name": "account", - "type": "address" - } - ], - "name": "Unpaused", - "type": "event" - }, - { - "inputs": [], - "name": "BNCAddress", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "addressToAssetInfo", - "outputs": [ - { - "internalType": "bytes2", - "name": "currencyId", - "type": "bytes2" - }, - { - "internalType": "uint256", - "name": "operationalMin", - "type": "uint256" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "bifrostParaId", - "outputs": [ - { - "internalType": "uint32", - "name": "", - "type": "uint32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "assetAddress", - "type": "address" - }, - { - "internalType": "uint128", - "name": "amount", - "type": "uint128" - }, - { - "internalType": "uint64", - "name": "dest_chain_id", - "type": "uint64" - }, - { - "internalType": "bytes", - "name": "receiver", - "type": "bytes" - }, - { - "internalType": "string", - "name": "remark", - "type": "string" - }, - { - "internalType": "uint32", - "name": "channel_id", - "type": "uint32" - } - ], - "name": "create_order", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "", - "type": "uint64" - } - ], - "name": "destChainInfo", - "outputs": [ - { - "internalType": "bool", - "name": "is_evm", - "type": "bool" - }, - { - "internalType": "bool", - "name": "is_substrate", - "type": "bool" - }, - { - "internalType": "bytes1", - "name": "raw_chain_index", - "type": "bytes1" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_BNCAddress", - "type": "address" - }, - { - "internalType": "uint32", - "name": "_bifrostParaId", - "type": "uint32" - }, - { - "internalType": "bytes2", - "name": "_nativeCurrencyId", - "type": "bytes2" - } - ], - "name": "initialize", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "assetAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "string", - "name": "remark", - "type": "string" - } - ], - "name": "mintVAsset", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "assetAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "string", - "name": "remark", - "type": "string" - }, - { - "internalType": "uint32", - "name": "channel_id", - "type": "uint32" - } - ], - "name": "mintVAssetWithChannelId", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "string", - "name": "remark", - "type": "string" - } - ], - "name": "mintVNativeAsset", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "receiver", - "type": "address" - }, - { - "internalType": "string", - "name": "remark", - "type": "string" - }, - { - "internalType": "uint32", - "name": "channel_id", - "type": "uint32" - } - ], - "name": "mintVNativeAssetWithChannelId", - "outputs": [], - "stateMutability": "payable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "enum MoonbeamSlpx.Operation", - "name": "", - "type": "uint8" - } - ], - "name": "operationToFeeInfo", - "outputs": [ - { - "internalType": "uint64", - "name": "transactRequiredWeightAtMost", - "type": "uint64" - }, - { - "internalType": "uint256", - "name": "feeAmount", - "type": "uint256" - }, - { - "internalType": "uint64", - "name": "overallWeight", - "type": "uint64" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "pause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "paused", - "outputs": [ - { - "internalType": "bool", - "name": "", - "type": "bool" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "vAssetAddress", - "type": "address" - }, - { - "internalType": "uint256", - "name": "amount", - "type": "uint256" - }, - { - "internalType": "address", - "name": "receiver", - "type": "address" - } - ], - "name": "redeemAsset", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "assetAddress", - "type": "address" - }, - { - "internalType": "bytes2", - "name": "currencyId", - "type": "bytes2" - }, - { - "internalType": "uint256", - "name": "minimumValue", - "type": "uint256" - } - ], - "name": "setAssetAddressInfo", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "dest_chain_id", - "type": "uint64" - }, - { - "internalType": "bool", - "name": "is_evm", - "type": "bool" - }, - { - "internalType": "bool", - "name": "is_substrate", - "type": "bool" - }, - { - "internalType": "bytes1", - "name": "raw_chain_index", - "type": "bytes1" - } - ], - "name": "setDestChainInfo", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "enum MoonbeamSlpx.Operation", - "name": "_operation", - "type": "uint8" - }, - { - "internalType": "uint64", - "name": "_transactRequiredWeightAtMost", - "type": "uint64" - }, - { - "internalType": "uint64", - "name": "_overallWeight", - "type": "uint64" - }, - { - "internalType": "uint256", - "name": "_feeAmount", - "type": "uint256" - } - ], - "name": "setOperationToFeeInfo", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "unpause", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_logic", - "type": "address" - }, - { - "internalType": "address", - "name": "admin_", - "type": "address" - }, - { - "internalType": "bytes", - "name": "_data", - "type": "bytes" - } - ], - "stateMutability": "payable", - "type": "constructor" - } -]; \ No newline at end of file + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "previousAdmin", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "AdminChanged", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beacon", + "type": "address" + } + ], + "name": "BeaconUpgraded", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "implementation", + "type": "address" + } + ], + "name": "Upgraded", + "type": "event" + }, + { + "stateMutability": "payable", + "type": "fallback" + }, + { + "inputs": [], + "name": "admin", + "outputs": [ + { + "internalType": "address", + "name": "admin_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newAdmin", + "type": "address" + } + ], + "name": "changeAdmin", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "implementation", + "outputs": [ + { + "internalType": "address", + "name": "implementation_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + } + ], + "name": "upgradeTo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newImplementation", + "type": "address" + }, + { + "internalType": "bytes", + "name": "data", + "type": "bytes" + } + ], + "name": "upgradeToAndCall", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "assetAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint128", + "name": "amount", + "type": "uint128" + }, + { + "indexed": false, + "internalType": "uint64", + "name": "dest_chain_id", + "type": "uint64" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "receiver", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "string", + "name": "remark", + "type": "string" + }, + { + "indexed": false, + "internalType": "uint32", + "name": "channel_id", + "type": "uint32" + } + ], + "name": "CreateOrder", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint8", + "name": "version", + "type": "uint8" + } + ], + "name": "Initialized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "minter", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "assetAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "callcode", + "type": "bytes" + }, + { + "indexed": false, + "internalType": "string", + "name": "remark", + "type": "string" + } + ], + "name": "Mint", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "redeemer", + "type": "address" + }, + { + "indexed": false, + "internalType": "address", + "name": "assetAddress", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "indexed": false, + "internalType": "bytes", + "name": "callcode", + "type": "bytes" + } + ], + "name": "Redeem", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "inputs": [], + "name": "BNCAddress", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "addressToAssetInfo", + "outputs": [ + { + "internalType": "bytes2", + "name": "currencyId", + "type": "bytes2" + }, + { + "internalType": "uint256", + "name": "operationalMin", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "bifrostParaId", + "outputs": [ + { + "internalType": "uint32", + "name": "", + "type": "uint32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "assetAddress", + "type": "address" + }, + { + "internalType": "uint128", + "name": "amount", + "type": "uint128" + }, + { + "internalType": "uint64", + "name": "dest_chain_id", + "type": "uint64" + }, + { + "internalType": "bytes", + "name": "receiver", + "type": "bytes" + }, + { + "internalType": "string", + "name": "remark", + "type": "string" + }, + { + "internalType": "uint32", + "name": "channel_id", + "type": "uint32" + } + ], + "name": "create_order", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "", + "type": "uint64" + } + ], + "name": "destChainInfo", + "outputs": [ + { + "internalType": "bool", + "name": "is_evm", + "type": "bool" + }, + { + "internalType": "bool", + "name": "is_substrate", + "type": "bool" + }, + { + "internalType": "bytes1", + "name": "raw_chain_index", + "type": "bytes1" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_BNCAddress", + "type": "address" + }, + { + "internalType": "uint32", + "name": "_bifrostParaId", + "type": "uint32" + }, + { + "internalType": "bytes2", + "name": "_nativeCurrencyId", + "type": "bytes2" + } + ], + "name": "initialize", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "assetAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "string", + "name": "remark", + "type": "string" + } + ], + "name": "mintVAsset", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "assetAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "string", + "name": "remark", + "type": "string" + }, + { + "internalType": "uint32", + "name": "channel_id", + "type": "uint32" + } + ], + "name": "mintVAssetWithChannelId", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "string", + "name": "remark", + "type": "string" + } + ], + "name": "mintVNativeAsset", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + }, + { + "internalType": "string", + "name": "remark", + "type": "string" + }, + { + "internalType": "uint32", + "name": "channel_id", + "type": "uint32" + } + ], + "name": "mintVNativeAssetWithChannelId", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum MoonbeamSlpx.Operation", + "name": "", + "type": "uint8" + } + ], + "name": "operationToFeeInfo", + "outputs": [ + { + "internalType": "uint64", + "name": "transactRequiredWeightAtMost", + "type": "uint64" + }, + { + "internalType": "uint256", + "name": "feeAmount", + "type": "uint256" + }, + { + "internalType": "uint64", + "name": "overallWeight", + "type": "uint64" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "vAssetAddress", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "redeemAsset", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "assetAddress", + "type": "address" + }, + { + "internalType": "bytes2", + "name": "currencyId", + "type": "bytes2" + }, + { + "internalType": "uint256", + "name": "minimumValue", + "type": "uint256" + } + ], + "name": "setAssetAddressInfo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "dest_chain_id", + "type": "uint64" + }, + { + "internalType": "bool", + "name": "is_evm", + "type": "bool" + }, + { + "internalType": "bool", + "name": "is_substrate", + "type": "bool" + }, + { + "internalType": "bytes1", + "name": "raw_chain_index", + "type": "bytes1" + } + ], + "name": "setDestChainInfo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "enum MoonbeamSlpx.Operation", + "name": "_operation", + "type": "uint8" + }, + { + "internalType": "uint64", + "name": "_transactRequiredWeightAtMost", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "_overallWeight", + "type": "uint64" + }, + { + "internalType": "uint256", + "name": "_feeAmount", + "type": "uint256" + } + ], + "name": "setOperationToFeeInfo", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_logic", + "type": "address" + }, + { + "internalType": "address", + "name": "admin_", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_data", + "type": "bytes" + } + ], + "stateMutability": "payable", + "type": "constructor" + } +]; + + +export const mockErc20Abi = [ + { + "inputs": [ + { + "internalType": "string", + "name": "name", + "type": "string" + }, + { + "internalType": "string", + "name": "symbol", + "type": "string" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "allowance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "ERC20InsufficientAllowance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "balance", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "needed", + "type": "uint256" + } + ], + "name": "ERC20InsufficientBalance", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "approver", + "type": "address" + } + ], + "name": "ERC20InvalidApprover", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "receiver", + "type": "address" + } + ], + "name": "ERC20InvalidReceiver", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "ERC20InvalidSender", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "ERC20InvalidSpender", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnableInvalidOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "OwnableUnauthorizedAccount", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Approval", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "Transfer", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + }, + { + "internalType": "address", + "name": "spender", + "type": "address" + } + ], + "name": "allowance", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "spender", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "approve", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "balanceOf", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "decimals", + "outputs": [ + { + "internalType": "uint8", + "name": "", + "type": "uint8" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "mint", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "name", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "symbol", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "totalSupply", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "transfer", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "from", + "type": "address" + }, + { + "internalType": "address", + "name": "to", + "type": "address" + }, + { + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "transferFrom", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +]; + +export const tokenVestingAbi = [ + { + "inputs": [ + { + "internalType": "address", + "name": "tokenAddress", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "EnforcedPause", + "type": "error" + }, + { + "inputs": [], + "name": "ExpectedPause", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnableInvalidOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "OwnableUnauthorizedAccount", + "type": "error" + }, + { + "inputs": [], + "name": "ReentrancyGuardReentrantCall", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beneficiary", + "type": "address" + } + ], + "name": "BeneficiaryRemovedFromWhitelist", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beneficiary", + "type": "address" + } + ], + "name": "BeneficiaryWhitelisted", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Paused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "TokensClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "Unpaused", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beneficiary", + "type": "address" + } + ], + "name": "VestingRevoked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "VestingScheduleCreated", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "beneficiary", + "type": "address" + } + ], + "name": "addToWhitelist", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "beneficiary", + "type": "address" + } + ], + "name": "calculateVestedAmount", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "claimVestedTokens", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cliffDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "vestingDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "startTime", + "type": "uint256" + } + ], + "name": "createVestingSchedule", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "pause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "paused", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "beneficiary", + "type": "address" + } + ], + "name": "removeFromWhitelist", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "beneficiary", + "type": "address" + } + ], + "name": "revokeVesting", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "token", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "unpause", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "vestingSchedules", + "outputs": [ + { + "internalType": "uint256", + "name": "totalAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "startTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cliffDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "vestingDuration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "amountClaimed", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "revoked", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "whitelist", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + } +]; + +export const yieldFarmingAbi = [ + { + "inputs": [ + { + "internalType": "address", + "name": "_lpToken", + "type": "address" + }, + { + "internalType": "address", + "name": "_rewardToken", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_rewardRate", + "type": "uint256" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "owner", + "type": "address" + } + ], + "name": "OwnableInvalidOwner", + "type": "error" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "account", + "type": "address" + } + ], + "name": "OwnableUnauthorizedAccount", + "type": "error" + }, + { + "inputs": [], + "name": "ReentrancyGuardReentrantCall", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "EmergencyWithdrawn", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "previousOwner", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "OwnershipTransferred", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "RewardsClaimed", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Staked", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "user", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "amount", + "type": "uint256" + } + ], + "name": "Withdrawn", + "type": "event" + }, + { + "inputs": [], + "name": "BOOST_THRESHOLD_1", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "BOOST_THRESHOLD_2", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "BOOST_THRESHOLD_3", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_user", + "type": "address" + } + ], + "name": "calculateBoostMultiplier", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "claimRewards", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_user", + "type": "address" + } + ], + "name": "earned", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "emergencyWithdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "lastUpdateTime", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "lpToken", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_user", + "type": "address" + } + ], + "name": "pendingRewards", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "rewardPerToken", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rewardPerTokenStored", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rewardRate", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "rewardToken", + "outputs": [ + { + "internalType": "contract IERC20", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "stake", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "totalStaked", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_newRate", + "type": "uint256" + } + ], + "name": "updateRewardRate", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "name": "userInfo", + "outputs": [ + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "startTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "rewardDebt", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "pendingRewards", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_amount", + "type": "uint256" + } + ], + "name": "withdraw", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +]; diff --git a/challenge-3-frontend/lib/atoms.ts b/challenge-3-frontend/lib/atoms.ts new file mode 100644 index 0000000..275369c --- /dev/null +++ b/challenge-3-frontend/lib/atoms.ts @@ -0,0 +1,7 @@ +import { atom } from "jotai"; + +/** + * Global open-state for the "Create Wallet” modal. + * Any component can toggle this to show / hide the dialog. + */ +export const createWalletDialogOpenAtom = atom(false); \ No newline at end of file diff --git a/challenge-3-frontend/lib/config.ts b/challenge-3-frontend/lib/config.ts new file mode 100644 index 0000000..78172ab --- /dev/null +++ b/challenge-3-frontend/lib/config.ts @@ -0,0 +1,8 @@ +export const LIQUIDITY_POOL_TOKEN_CONTRACT_ADDRESS = + "0xE5f2A565Ee0Aa9836B4c80a07C8b32aAd7978e22"; +export const REWARD_TOKEN_CONTRACT_ADDRESS = + "0xEc29164D68c4992cEdd1D386118A47143fdcF142"; +export const YIELD_FARMING_CONTRACT_ADDRESS = + "0x9396B453Fad71816cA9f152Ae785276a1D578492"; +export const TOKEN_VESTING_CONTRACT_ADDRESS = + "0xd7Ca4e99F7C171B9ea2De80d3363c47009afaC5F"; diff --git a/challenge-3-frontend/package-lock.json b/challenge-3-frontend/package-lock.json index dec4c63..41ba9f0 100644 --- a/challenge-3-frontend/package-lock.json +++ b/challenge-3-frontend/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@hookform/resolvers": "^3.9.1", "@radix-ui/react-dialog": "^1.1.3", + "@radix-ui/react-dropdown-menu": "^2.1.12", "@radix-ui/react-label": "^2.1.1", "@radix-ui/react-select": "^2.1.4", "@radix-ui/react-separator": "^1.1.1", @@ -1274,6 +1275,164 @@ } } }, + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.12.tgz", + "integrity": "sha512-VJoMs+BWWE7YhzEQyVwvF9n22Eiyr83HotCVrMQzla/OwRovXCgah7AcaEr4hMNj4gJxSdtIbcHGvmJXOoJVHA==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.12", + "@radix-ui/react-primitive": "2.1.0", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/primitive": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz", + "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-primitive": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.0.tgz", + "integrity": "sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-slot": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.0.tgz", + "integrity": "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-dropdown-menu/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-focus-guards": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.1.tgz", @@ -1355,6 +1514,517 @@ } } }, + "node_modules/@radix-ui/react-menu": { + "version": "2.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.12.tgz", + "integrity": "sha512-+qYq6LfbiGo97Zz9fioX83HCiIYYFNs8zAsVCMQrIakoNYylIzWuoD/anAD3UzvvR6cnswmfRFJFq/zYYq/k7Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.7", + "@radix-ui/react-focus-guards": "1.1.2", + "@radix-ui/react-focus-scope": "1.1.4", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.4", + "@radix-ui/react-portal": "1.1.6", + "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-primitive": "2.1.0", + "@radix-ui/react-roving-focus": "1.1.7", + "@radix-ui/react-slot": "1.2.0", + "@radix-ui/react-use-callback-ref": "1.1.1", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/primitive": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz", + "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-arrow": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.4.tgz", + "integrity": "sha512-qz+fxrqgNxG0dYew5l7qR3c7wdgRu1XVUHGnGYX7rg5HM4p9SWaRmJwfgR3J0SgyUKayLmzQIun+N6rWRgiRKw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-collection": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.4.tgz", + "integrity": "sha512-cv4vSf7HttqXilDnAnvINd53OTl1/bjUYVZrkFnA7nwmY9Ob2POUy0WY0sfqBAe1s5FyKsyceQlqiEGPYNTadg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.0", + "@radix-ui/react-slot": "1.2.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-direction": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.7.tgz", + "integrity": "sha512-j5+WBUdhccJsmH5/H0K6RncjDtoALSEr6jbkaZu+bjw6hOPOhHycr6vEUujl+HBK8kjUfWcoCJXxP6e4lUlMZw==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.0", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz", + "integrity": "sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.4.tgz", + "integrity": "sha512-r2annK27lIW5w9Ho5NyQgqs0MmgZSTIKXWpVCJaLC1q2kZrZkcqnmHkCHMEmv8XLvsLlurKMPT+kbKkRkm/xVA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.0", + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-id": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-popper": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.4.tgz", + "integrity": "sha512-3p2Rgm/a1cK0r/UVkx5F/K9v/EplfjAeIFCGOPYPO4lZ0jtg4iSQXt/YGTSLWaf4x7NG6Z4+uKFcylcTZjeqDA==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.0", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-portal": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.6.tgz", + "integrity": "sha512-XmsIl2z1n/TsYFLIdYam2rmFwf9OC/Sh2avkbmVMDuBZIe7hSpM0cYnWPAo7nHOVx8zTuwDZGByfcqLdnzp3Vw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-presence": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz", + "integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-primitive": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.0.tgz", + "integrity": "sha512-/J/FhLdK0zVcILOwt5g+dH4KnkonCtkVJsa2G6JmvbbtZfBEI1gMsO3QMjseL4F/SwfAMt1Vc/0XKYKq+xJ1sw==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-slot": "1.2.0" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.7.tgz", + "integrity": "sha512-C6oAg451/fQT3EGbWHbCQjYTtbyjNO1uzQgMzwyivcHT3GKNEmu1q3UuREhN+HzHAVtv3ivMVK08QlC+PkYw9Q==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.2", + "@radix-ui/react-collection": "1.1.4", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.0", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-slot": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.0.tgz", + "integrity": "sha512-ujc+V6r0HNDviYqIK3rW4ffgYiZ8g5DEHrGJVk4x7kTlLXRDILnKX9vAUYeIsLOoDpDJ0ujpqMkjH4w2ofuo6w==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "1.1.2" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-use-rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", + "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-menu/node_modules/@radix-ui/rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-menu/node_modules/react-remove-scroll": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.3.tgz", + "integrity": "sha512-pnAi91oOk8g8ABQKGF5/M9qxmmOPxaAnopyTHYfqYEwJhyFrbbBtHuSgtKEoH0jpcxx5o3hXqH1mNd9/Oi+8iQ==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-popper": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.1.tgz", @@ -1670,6 +2340,39 @@ } } }, + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-effect-event/node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-use-escape-keydown": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz", @@ -9740,4 +10443,4 @@ } } } -} +} \ No newline at end of file diff --git a/challenge-3-frontend/package.json b/challenge-3-frontend/package.json index f4b780e..8dbaed0 100644 --- a/challenge-3-frontend/package.json +++ b/challenge-3-frontend/package.json @@ -11,6 +11,7 @@ "dependencies": { "@hookform/resolvers": "^3.9.1", "@radix-ui/react-dialog": "^1.1.3", + "@radix-ui/react-dropdown-menu": "^2.1.12", "@radix-ui/react-label": "^2.1.1", "@radix-ui/react-select": "^2.1.4", "@radix-ui/react-separator": "^1.1.1", @@ -44,4 +45,4 @@ "tailwindcss": "^3.4.1", "typescript": "^5" } -} +} \ No newline at end of file diff --git a/dotui b/dotui new file mode 160000 index 0000000..dd6220b --- /dev/null +++ b/dotui @@ -0,0 +1 @@ +Subproject commit dd6220b66a8a40ee089e1241a17efe563a3be760