diff --git a/README.md b/README.md index ee62858..7472a85 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ git clone https://github.com/openguild-labs/open-encode-challenges.git Go to **Participant Registration** section and register to be the workshop participants. Add the below to the list, replace any placeholder with your personal information. ``` -| 🦄 | Name | Github username | Your current occupation | +| 🦄 | Emmanuel Bagoole | ManuelPrhyme | Solidity Smart Contracts Instructor/Auditor | ``` - Step 5: `Commit` your code and push to the forked Github repository diff --git a/challenge-1-vesting/README.md b/challenge-1-vesting/README.md index 9cc7a2c..7296e27 100644 --- a/challenge-1-vesting/README.md +++ b/challenge-1-vesting/README.md @@ -11,6 +11,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 | +| 🎅 | Manuel | [ManuelPrhyme](https://github.com/ManuelPrhyme) | Smart-Contracts Engineer | ## 💻 Local development environment setup diff --git a/challenge-1-vesting/contracts/TokenVesting.sol b/challenge-1-vesting/contracts/TokenVesting.sol index 43d4c3a..03bfde0 100644 --- a/challenge-1-vesting/contracts/TokenVesting.sol +++ b/challenge-1-vesting/contracts/TokenVesting.sol @@ -1,148 +1,196 @@ -// Challenge: Token Vesting Contract -/* -Create a token vesting contract with the following requirements: - -1. The contract should allow an admin to create vesting schedules for different beneficiaries -2. Each vesting schedule should have: - - Total amount of tokens to be vested - - Cliff period (time before any tokens can be claimed) - - Vesting duration (total time for all tokens to vest) - - Start time -3. After the cliff period, tokens should vest linearly over time -4. Beneficiaries should be able to claim their vested tokens at any time -5. Admin should be able to revoke unvested tokens from a beneficiary - -Bonus challenges: -- Add support for multiple token types -- Implement a whitelist for beneficiaries -- Add emergency pause functionality - -Here's your starter code: -*/ - // SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; +pragma solidity ^0.8.25; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/Pausable.sol"; import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; +// Token Address +// Vesting ["VST"] -> 0xD2f45381d4aAd3B29C26E9FD86dAb8B98E2FE238 +// Staked ["SKT"] -> 0xcac8028b3361da8729a6ce521503ce88a50a4806 +// Vested ["VES"] -> 0x14574a3d70554722a14c0cbc50ab0e7834ac66a5 + contract TokenVesting is Ownable(msg.sender), Pausable, ReentrancyGuard { - struct VestingSchedule { - // TODO: Define the vesting schedule struct - } + address Owner; + // Token being vested - // TODO: Add state variables + IERC20 public Vestings; + IERC20 internal Staked; + IERC20 internal Vested; + //Vesting schedule for each beneficiary + struct VestingSchedule { + uint256 totalAmount; + uint256 startTime; + uint256 cliffDuration; + uint256 vestingDuration; + uint256 amountClaimed; + string Token; + bool revokedStatus; + } - // Mapping from beneficiary to vesting schedule - // TODO: Add state variables + //Mapping from beneficiary to vesting schedule created + mapping(address=>VestingSchedule) public beneficiaryScheduled; - // Whitelist of beneficiaries - // TODO: Add state variables + //Whitelist of beneficiaries + mapping(address=>bool) public beneficiaryWhitelist; // Events - event VestingScheduleCreated(address indexed beneficiary, uint256 amount); + event VestingScheduleCreated(address indexed beneficiary, string token, uint256 amount); event TokensClaimed(address indexed beneficiary, uint256 amount); event VestingRevoked(address indexed beneficiary); - event BeneficiaryWhitelisted(address indexed beneficiary); - event BeneficiaryRemovedFromWhitelist(address indexed beneficiary); + event BeneficiaryWhitelisted(address indexed beneficiary); + event BeneficiaryRemovedFromWhitelist(address indexed beneficiary); - constructor(address tokenAddress) { - // TODO: Initialize the contract + //constructor functions assigns the actual token addresses to the instances created + constructor(address _vst, address _stk, address _ves){ + Vestings = IERC20(_vst); + Staked = IERC20(_stk); + Vested = IERC20(_ves); + Owner = msg.sender; } // Modifier to check if beneficiary is whitelisted modifier onlyWhitelisted(address beneficiary) { - require(whitelist[beneficiary], "Beneficiary not whitelisted"); + require(beneficiaryWhitelist[beneficiary], "Beneficiary not whitelisted"); _; } function addToWhitelist(address beneficiary) external onlyOwner { require(beneficiary != address(0), "Invalid address"); - whitelist[beneficiary] = true; + beneficiaryWhitelist[beneficiary] = true; emit BeneficiaryWhitelisted(beneficiary); } function removeFromWhitelist(address beneficiary) external onlyOwner { - whitelist[beneficiary] = false; + beneficiaryWhitelist[beneficiary] = false; emit BeneficiaryRemovedFromWhitelist(beneficiary); } + function createVestingSchedule( address beneficiary, uint256 amount, uint256 cliffDuration, uint256 vestingDuration, - uint256 startTime + uint256 startTime, + string calldata tokenChoice ) external onlyOwner onlyWhitelisted(beneficiary) whenNotPaused { - // TODO: Implement vesting schedule creation + //Validation + require(amount > 0,'Stake amount greater than 0'); + require( beneficiary != address(0), 'Enter correct address'); + require( vestingDuration > cliffDuration, "Enter a valid Vesting duration [Vesting duration must be greater than Cliff duration]"); + require(vestingDuration > 0,"Vesting duration must be greater that 0"); + + //Effects + if(startTime == 0 || startTime <= block.timestamp){ + startTime = block.timestamp; + } + + //Interactions + //For mutiple token transfer I used an implict references for each token => ['USDT','USDC','DAI']. They could be picked fron a list on the + // interface and then a transaction is senn to this function with that string in calldata, to enable with the conditional logic of calling + // the trasferFrom method from the correct ERC20 contract + if(bytes32(bytes(tokenChoice)) == bytes32('VST')) { + Vestings.transferFrom(msg.sender, address(this),amount); + }else if(bytes32(bytes(tokenChoice)) == bytes32('STK')){ + Staked.transferFrom(msg.sender, address(this), amount); + } else if(bytes32(bytes(tokenChoice)) == bytes32('VES')) { + Vested.transferFrom(msg.sender, address(this),amount); + } else { + revert('Please choose one of these ["VST","STK","VES"]'); + } + + //Note: This is an effect (simply a state mutability statemet) but it is necessary that it comes after an interaction of the contract with external + // signers, because its records determine how much tokens to a particular beneficiary is released later on. Even though it might jeopardise the + // reentracy guard of the contract coming after transfer, the risk of registering a Schedule and not sending actual tokens is just as high. So just incase a + // wrong token's transfer is attempted or somehow the transfer fails, the contract shouldn't create a Vesting Schedule, instead it should revert without the line below being executed. + + beneficiaryScheduled[beneficiary] = VestingSchedule(amount,startTime,cliffDuration,vestingDuration,0,tokenChoice,false); + + emit VestingScheduleCreated(beneficiary, tokenChoice, amount); } - function calculateVestedAmount( - address beneficiary - ) public view returns (uint256) { - // TODO: Implement vested amount calculation + function calculateVestedAmount() public view returns (uint256) { + require(beneficiaryWhitelist[msg.sender],"Please connect with the vesting address"); + require(!beneficiaryScheduled[msg.sender].revokedStatus,"Please initiate a vesting schedule"); + + address beneficiary = msg.sender; + + if(block.timestamp <= beneficiaryScheduled[beneficiary].startTime + beneficiaryScheduled[beneficiary].cliffDuration){ + return 0; + } + + if(block.timestamp >= beneficiaryScheduled[beneficiary].startTime + beneficiaryScheduled[beneficiary].vestingDuration){ + return beneficiaryScheduled[beneficiary].totalAmount; + + } + + uint timeCount = block.timestamp - beneficiaryScheduled[beneficiary].cliffDuration; + + return (beneficiaryScheduled[beneficiary].totalAmount * timeCount) / beneficiaryScheduled[beneficiary].vestingDuration; + } function claimVestedTokens() external nonReentrant whenNotPaused { - // TODO: Implement token claiming + require(beneficiaryWhitelist[msg.sender],"Please connect with the vesting address"); + require(!beneficiaryScheduled[msg.sender].revokedStatus,"Please initiate a vesting schedule"); + require(beneficiaryScheduled[msg.sender].amountClaimed < beneficiaryScheduled[msg.sender].totalAmount ,"All claimable amount has been withdrawn"); + + uint claimableAmount = calculateVestedAmount() - beneficiaryScheduled[msg.sender].amountClaimed; + beneficiaryScheduled[msg.sender].amountClaimed = claimableAmount; + + require(claimableAmount > 0,"All claimble tokens have been claimed"); + + string memory VestedToken = beneficiaryScheduled[msg.sender].Token; + + if(bytes32(bytes(VestedToken)) == bytes32('VST')){ + require(Vestings.transfer(msg.sender,claimableAmount),'Transaction failed'); + + } else if(bytes32(bytes(VestedToken)) == bytes32('STK')){ + require(Staked.transfer(msg.sender,claimableAmount),'Transaction failed'); + + } else { + require(Vested.transfer(msg.sender,claimableAmount),'Transaction failed'); + + } + + emit TokensClaimed(msg.sender, claimableAmount); } - function revokeVesting(address beneficiary) external onlyOwner { - // TODO: Implement vesting revocation + function revokeVesting() external onlyOwner { + require(beneficiaryWhitelist[msg.sender],"Please connect with the vesting address"); + require(!beneficiaryScheduled[msg.sender].revokedStatus,"No vesting schedule found"); + + uint Unvested = beneficiaryScheduled[msg.sender].totalAmount - calculateVestedAmount(); + string memory VestedToken = beneficiaryScheduled[msg.sender].Token; + + if (Unvested > 0){ + if(bytes32(bytes(VestedToken)) == bytes32('VST')){ + require(Vestings.transfer(msg.sender,Unvested),'Transaction failed'); + + } else if(bytes32(bytes(VestedToken)) == bytes32('STK')){ + require(Staked.transfer(msg.sender,Unvested),'Transaction failed'); + + } else { + require(Vested.transfer(msg.sender,Unvested),'Transaction failed'); } + } + beneficiaryScheduled[msg.sender].revokedStatus = true; + + emit VestingRevoked(msg.sender); } - function pause() external onlyOwner { + function Pause() external onlyOwner { _pause(); } - function unpause() external onlyOwner { + function Unpause() external onlyOwner { _unpause(); } + } -/* -Solution template (key points to implement): - -1. VestingSchedule struct should contain: - - Total amount - - Start time - - Cliff duration - - Vesting duration - - Amount claimed - - Revoked status - -2. State variables needed: - - Mapping of beneficiary address to VestingSchedule - - ERC20 token reference - - Owner/admin address - -3. createVestingSchedule should: - - Validate input parameters - - Create new vesting schedule - - Transfer tokens to contract - - Emit event - -4. calculateVestedAmount should: - - Check if cliff period has passed - - Calculate linear vesting based on time passed - - Account for already claimed tokens - - Handle revoked status - -5. claimVestedTokens should: - - Calculate claimable amount - - Update claimed amount - - Transfer tokens - - Emit event - -6. revokeVesting should: - - Only allow admin - - Calculate and transfer unvested tokens back - - Mark schedule as revoked - - Emit event -*/ \ No newline at end of file diff --git a/challenge-2-yield-farm/contracts/yeild.sol b/challenge-2-yield-farm/contracts/yeild.sol deleted file mode 100644 index 421496a..0000000 --- a/challenge-2-yield-farm/contracts/yeild.sol +++ /dev/null @@ -1,185 +0,0 @@ -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; -import "@openzeppelin/contracts/access/Ownable.sol"; - -/** - * @title YieldFarm - * @notice Challenge: Implement a yield farming contract with the following requirements: - * - * 1. Users can stake LP tokens and earn reward tokens - * 2. Rewards are distributed based on time and amount staked - * 3. Implement reward boosting mechanism for long-term stakers - * 4. Add emergency withdrawal functionality - * 5. Implement reward rate adjustment mechanism - */ - -contract YieldFarm is ReentrancyGuard, Ownable { - // LP token that users can stake - IERC20 public lpToken; - - // 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; - - // 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 - } - - // Mapping of user address to their info - mapping(address => UserInfo) public userInfo; - - // Boost multiplier thresholds (in seconds) - 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 - 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 - } - - function updateReward(address _user) internal { - rewardPerTokenStored = rewardPerToken(); - lastUpdateTime = block.timestamp; - - if (_user != address(0)) { - UserInfo storage user = userInfo[_user]; - user.pendingRewards = earned(_user); - user.rewardDebt = (user.amount * rewardPerTokenStored) / 1e18; - } - } - - 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 - } - - 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 - } - - /** - * @notice Stake LP tokens into the farm - * @param _amount Amount of LP tokens to stake - */ - 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 - } - - /** - * @notice Withdraw staked LP tokens - * @param _amount Amount of LP tokens to withdraw - */ - 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 - } - - /** - * @notice 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 - } - - /** - * @notice Emergency withdraw without caring about rewards - */ - 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 - } - - /** - * @notice Calculate boost multiplier based on staking duration - * @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 - } - - /** - * @notice Update reward rate - * @param _newRate New reward rate per second - */ - function updateRewardRate(uint256 _newRate) external onlyOwner { - // TODO: Implement reward rate update logic - // Requirements: - // 1. Update rewards before changing rate - // 2. Set new reward rate - } - - /** - * @notice View function to see pending rewards for a user - * @param _user Address of the user - * @return Pending reward amount - */ - function pendingRewards(address _user) external view returns (uint256) { - return earned(_user); - } -} diff --git a/challenge-2-yield-farm/contracts/yield.sol b/challenge-2-yield-farm/contracts/yield.sol new file mode 100644 index 0000000..4e28d82 --- /dev/null +++ b/challenge-2-yield-farm/contracts/yield.sol @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.25; + +import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; +import "@openzeppelin/contracts/access/Ownable.sol"; + +contract YieldFarm is ReentrancyGuard, Ownable { + + IERC20 public LPToken; + IERC20 public rewardToken; + + uint256 public rewardRate; + uint256 public lastUpdateTime; + uint256 public rewardPerTokenStored; + uint256 public totalStaked; + + struct UserInfo { + uint256 amount; // Amount of LP tokens staked by user + uint256 startTime; // Timestamp when user started staking or last reset + uint256 rewardDebt; // Reward debt to track already accounted rewards + uint256 pendingRewards; // Rewards accrued but not yet claimed + } + + mapping(address => UserInfo) public userInfo; + + 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 + 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); + event RewardRateUpdated(uint256 oldRate, uint256 newRate); + + // LP Tokens [LP] -> 0x0474b473a1c7bcf9a5706e71e894033157e85248 + // Reward [RD] -> 0xcd961fde084836941e6f6470d70b5bddfb2739bd + + constructor( + address _lpToken, + address _rewardToken, + uint256 _rewardRate + ) { + require(_lpToken != address(0), "LP token address zero"); + require(_rewardToken != address(0), "Reward token address zero"); + require(_rewardRate > 0, "Reward rate must be > 0"); + + LPToken = IERC20(_lpToken); + rewardToken = IERC20(_rewardToken); + rewardRate = _rewardRate; + lastUpdateTime = block.timestamp; + } + + function updateReward(address _user) internal { + rewardPerTokenStored = rewardPerToken(); + lastUpdateTime = block.timestamp; + + if (_user != address(0)) { + UserInfo storage user = userInfo[_user]; + user.pendingRewards = earned(_user); + user.rewardDebt = (user.amount * rewardPerTokenStored) / 1e18; + } + } + + function rewardPerToken() public view returns (uint256) { + if (totalStaked == 0) { + return rewardPerTokenStored; + } + uint256 timeElapsed = block.timestamp - lastUpdateTime; + uint256 rewardAccrued = timeElapsed * rewardRate * 1e18 / totalStaked; + return rewardPerTokenStored + rewardAccrued; +} + + + + + function earned(address _user) public view returns (uint256) { + UserInfo storage user = userInfo[_user]; + uint256 currentRewardPerToken = rewardPerToken(); + uint256 baseReward = (user.amount * (currentRewardPerToken - user.rewardDebt)) / 1e18; + uint256 totalReward = user.pendingRewards + baseReward; + + uint256 boostMultiplier = calculateBoostMultiplier(_user); + return (totalReward * boostMultiplier) / 100; +} + + + function stake(uint256 _amount) external nonReentrant { + require(_amount > 0, "Cannot stake zero"); + + updateReward(msg.sender); + + UserInfo storage user = userInfo[msg.sender]; + + // If first time staking or after emergency withdraw, reset startTime + if (user.amount == 0) { + user.startTime = block.timestamp; + } + + // Transfer LP tokens from user to contract + require(LPToken.transferFrom(msg.sender, address(this), _amount), "LP transfer failed"); + + user.amount += _amount; + totalStaked += _amount; + + // Update reward debt after stake + user.rewardDebt = (user.amount * rewardPerTokenStored) / 1e18; + + emit Staked(msg.sender, _amount); + } + + function withdraw(uint256 _amount) external nonReentrant { + UserInfo storage user = userInfo[msg.sender]; + require(_amount > 0, "Cannot withdraw zero"); + require(user.amount >= _amount, "Withdraw amount exceeds balance"); + + updateReward(msg.sender); + + user.amount -= _amount; + totalStaked -= _amount; + + require(LPToken.transfer(msg.sender, _amount), "LP transfer failed"); + + if (user.amount == 0) { + user.startTime = 0; + } + + user.rewardDebt = (user.amount * rewardPerTokenStored) / 1e18; + + emit Withdrawn(msg.sender, _amount); + } + + function claimRewards() external nonReentrant { + updateReward(msg.sender); + + UserInfo storage user = userInfo[msg.sender]; + uint256 reward = user.pendingRewards; + require(reward > 0, "No rewards to claim"); + + user.pendingRewards = 0; + user.rewardDebt = (user.amount * rewardPerTokenStored) / 1e18; + + require(rewardToken.transfer(msg.sender, reward), "Reward transfer failed"); + + emit RewardsClaimed(msg.sender, reward); + } + + function emergencyWithdraw() external nonReentrant { + UserInfo storage user = userInfo[msg.sender]; + uint256 amount = user.amount; + require(amount > 0, "Nothing to withdraw"); + + user.amount = 0; + user.rewardDebt = 0; + user.pendingRewards = 0; + user.startTime = 0; + + totalStaked -= amount; + + require(LPToken.transfer(msg.sender, amount), "LP transfer failed"); + + emit EmergencyWithdrawn(msg.sender, amount); + } + + function calculateBoostMultiplier(address _user) public view returns (uint256) { + UserInfo storage user = userInfo[_user]; + if (user.startTime == 0 || user.amount == 0) { + return 100; // No boost if not staking + } + + uint256 stakingDuration = block.timestamp - user.startTime; + + if (stakingDuration >= BOOST_THRESHOLD_3) { + return 150; // 1.5x boost + } else if (stakingDuration >= BOOST_THRESHOLD_2) { + return 130; // 1.3x boost + } else if (stakingDuration >= BOOST_THRESHOLD_1) { + return 110; // 1.1x boost + } else { + return 100; // No boost + } + } + + function updateRewardRate(uint256 _newRate) external onlyOwner { + require(_newRate > 0, "Reward rate must be > 0"); + updateReward(address(0)); // Update global rewards before changing rate + uint256 oldRate = rewardRate; + rewardRate = _newRate; + emit RewardRateUpdated(oldRate, _newRate); + } + + function pendingRewards(address _user) external view returns (uint256) { + return earned(_user); + } +} diff --git a/challenge-3-frontend/README.md b/challenge-3-frontend/README.md index 7b8d41f..0ab5c8f 100644 --- a/challenge-3-frontend/README.md +++ b/challenge-3-frontend/README.md @@ -1,4 +1,4 @@ -# DOT UI Kit +# DOT UI Kit. An open-source, up-to-date, opinionated UI scaffolding kit for the Polkadot ecosystem (starting with Asset Hub). The technical stack is: diff --git a/challenge-3-frontend/app/page.tsx b/challenge-3-frontend/app/page.tsx index fb01185..d042d92 100644 --- a/challenge-3-frontend/app/page.tsx +++ b/challenge-3-frontend/app/page.tsx @@ -1,110 +1,5 @@ -import Image from "next/image"; -import Link from "next/link"; +import { redirect } from "next/navigation"; export default function Home() { - 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 - - - Read our docs - -
-
- -
- ); + return redirect("/yield-farm"); } diff --git a/challenge-3-frontend/app/providers.tsx b/challenge-3-frontend/app/providers.tsx index 91243fe..e1414d7 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 { + LP_ADDRESS, + REWARD_ADDRESS, + YIELD_FARM_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: LP_ADDRESS, + }, + rewardToken: { + address: REWARD_ADDRESS, + }, + yieldToken: { + address: YIELD_FARM_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/vesting/page.tsx b/challenge-3-frontend/app/vesting/page.tsx new file mode 100644 index 0000000..fd8090a --- /dev/null +++ b/challenge-3-frontend/app/vesting/page.tsx @@ -0,0 +1,15 @@ +"use client"; +import Navbar from "@/components/navbar"; +import SigpassKit from "@/components/sigpasskit"; +import Vesting from "@/components/vesting"; + +export default function VestingPage() { + return ( +
+ + +

Vesting

+ +
+ ); +} \ No newline at end of file diff --git a/challenge-3-frontend/app/yield-farm/loader.tsx b/challenge-3-frontend/app/yield-farm/loader.tsx new file mode 100644 index 0000000..e288aea --- /dev/null +++ b/challenge-3-frontend/app/yield-farm/loader.tsx @@ -0,0 +1,17 @@ +import { Skeleton } from "@/components/ui/skeleton" + +export default function Loading() { + // You can add any UI inside Loading, including a Skeleton. + return ( +
+ +
+ + + + +
+ +
+ ) +} \ No newline at end of file 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..adc6f4b --- /dev/null +++ b/challenge-3-frontend/app/yield-farm/page.tsx @@ -0,0 +1,14 @@ +import Navbar from "@/components/navbar"; +import SigpassKit from "@/components/sigpasskit"; +import YieldFarm from "@/components/yield-farm"; + +export default function YieldFarmPage() { + return ( +
+ + +

Yield Farming

+ +
+ ); +} \ No newline at end of file diff --git a/challenge-3-frontend/components/mint-mock-token.tsx b/challenge-3-frontend/components/mint-mock-token.tsx new file mode 100644 index 0000000..4dcddcf --- /dev/null +++ b/challenge-3-frontend/components/mint-mock-token.tsx @@ -0,0 +1,102 @@ +"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 { LP_ADDRESS } from "@/lib/config"; +import { mockErc20Abi } from "@/lib/abi"; +type Props = { + label: string; +}; +export default function MintMockToken({ label }: Props) { + + const config = useConfig(); + const account = useAccount(); + const address = useAtomValue(addressAtom); + const { + data: hash, + isPending, + writeContractAsync, + } = useWriteContract({ + config: address ? localConfig : config, + }); + + const { data, refetch } = useReadContract({ + address: LP_ADDRESS, + abi: mockErc20Abi, + functionName: "decimals", + chainId: westendAssetHub.id, + config: address ? localConfig : config, + }); + + // get the max balance and decimals from the data + const decimals = data as number | undefined; + + // useWaitForTransactionReceipt hook to wait for transaction receipt + const { isLoading: isConfirming, isSuccess: isConfirmed } = + useWaitForTransactionReceipt({ + hash, + config: address ? localConfig : config, + }); + + const handleMintToken = async () => { + try { + if (address) { + writeContractAsync({ + account: await getSigpassWallet(), + address: LP_ADDRESS, + abi: mockErc20Abi, + functionName: "mint", + args: [ + address ? address : account.address, + parseUnits("1000", decimals as number), + ], + chainId: westendAssetHub.id, + }); + } else { + writeContractAsync({ + address: LP_ADDRESS, + abi: mockErc20Abi, + functionName: "mint", + args: [ + address ? address : account.address, + parseUnits("1000", decimals as number), + ], + chainId: westendAssetHub.id, + }); + } + } catch (error) { + console.error(error); + } + }; + + // when isConfirmed, refetch the balance of the address + useEffect(() => { + if (isConfirmed) { + refetch(); + } + }, [isConfirmed, refetch]); + + return ( +
+ +
+ ); +} \ No newline at end of file diff --git a/challenge-3-frontend/components/navbar.tsx b/challenge-3-frontend/components/navbar.tsx index d212169..64b16fe 100644 --- a/challenge-3-frontend/components/navbar.tsx +++ b/challenge-3-frontend/components/navbar.tsx @@ -1,32 +1,47 @@ +"use client"; + import Link from "next/link"; +import { usePathname } from "next/navigation"; export default function Navbar() { + const pathname = usePathname(); + return ( -
- - Home - - - Wallet - - - Send transaction - - - Write contract - - - Mint/Redeem LST Bifrost - +
+ +
+ + Home + + + Wallet + + + Send transaction + + + Write contract + + + Mint/Redeem LST Bifrost + + + + Vesting + + + Yield Farm + +
); } diff --git a/challenge-3-frontend/components/stake.tsx b/challenge-3-frontend/components/stake.tsx new file mode 100644 index 0000000..64bab77 --- /dev/null +++ b/challenge-3-frontend/components/stake.tsx @@ -0,0 +1,439 @@ +"use client"; + +import { useState, useEffect } from "react"; +import { + type BaseError, + useWaitForTransactionReceipt, + useConfig, + useWriteContract, + useReadContracts, + useAccount, +} from "wagmi"; +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 { Skeleton } from "./ui/skeleton"; +import { localConfig } from "@/app/providers"; +import { mockErc20Abi, yieldFarmingAbi } from "@/lib/abi"; +import { + LP_ADDRESS, + YIELD_FARM_ADDRESS, +} from "@/lib/config"; +import MintMockToken from "./mint-mock-token"; + +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); + 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: LP_ADDRESS, + abi: mockErc20Abi, + functionName: "balanceOf", + args: [address ? address : account.address], + }, + { + address: LP_ADDRESS, + abi: mockErc20Abi, + functionName: "decimals", + }, + { + address: LP_ADDRESS, + abi: mockErc20Abi, + functionName: "allowance", + args: [address ? address : account.address, YIELD_FARM_ADDRESS], + }, + ], + config: address ? localConfig : config, + }); + + + const maxBalance = data?.[0]?.result as bigint | undefined; + const decimals = data?.[1]?.result as number | undefined; + const mintAllowance = data?.[2]?.result as bigint | undefined; + const amount = form.watch("amount"); + + const needsApprove = + mintAllowance !== undefined && amount + ? mintAllowance < parseUnits(amount, decimals || 18) + : false; + + async function onSubmit(values: z.infer) { + if (address) { + if (needsApprove) { + writeContractAsync({ + account: await getSigpassWallet(), + address: LP_ADDRESS, + abi: mockErc20Abi, + functionName: "approve", + args: [ + YIELD_FARM_ADDRESS, + parseUnits(values.amount, decimals as number), + ], + chainId: westendAssetHub.id, + }); + } else { + writeContractAsync({ + account: await getSigpassWallet(), + address: YIELD_FARM_ADDRESS, + abi: yieldFarmingAbi, + functionName: "stake", + args: [parseUnits(values.amount, decimals as number)], + chainId: westendAssetHub.id, + }); + } + } else { + + if (needsApprove) { + writeContractAsync({ + address: LP_ADDRESS, + abi: mockErc20Abi, + functionName: "approve", + args: [ + YIELD_FARM_ADDRESS, + parseUnits(values.amount, decimals as number), + ], + chainId: westendAssetHub.id, + }); + } else { + writeContractAsync({ + address: YIELD_FARM_ADDRESS, + abi: yieldFarmingAbi, + functionName: "stake", + args: [parseUnits(values.amount, decimals as number)], + 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 ( +
+ +
+ + ( + +
+ Amount to stake +
+ {" "} + {maxBalance ? ( + formatUnits(maxBalance as bigint, decimals as number) + ) : ( + + )}{" "} + LP Token +
+
+ + {isDesktop ? ( + + ) : ( + + )} + + + The amount of LPToken to stake + + +
+ )} + /> +
+ {isPending ? ( + + ) : needsApprove ? ( + + ) : ( + + )} + {isPending ? ( + + ) : needsApprove ? ( + + ) : ( + + )} +
+ + + { + // 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} +
+ )} +
+ + + + + +
+
+ ) + } +
+ ); +} \ No newline at end of file diff --git a/challenge-3-frontend/components/vesting.tsx b/challenge-3-frontend/components/vesting.tsx new file mode 100644 index 0000000..811b200 --- /dev/null +++ b/challenge-3-frontend/components/vesting.tsx @@ -0,0 +1,243 @@ +"use client"; + +import { useState } from "react"; +import { + useConfig, + useWriteContract, + useReadContracts, + useAccount, + useWaitForTransactionReceipt, +} from "wagmi"; +import { parseUnits, formatUnits } from "viem"; +import { + Form, + FormControl, + FormField, + FormItem, + FormLabel, + FormMessage, +} from "@/components/ui/form"; +import { Input } from "@/components/ui/input"; +import { Button } from "@/components/ui/button"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { z } from "zod"; +import { useAtomValue } from "jotai"; +import { addressAtom } from "@/components/sigpasskit"; +import { Skeleton } from "./ui/skeleton"; +import { vestingAbi } from "@/lib/abi"; +import { VESTING_ADDRESS } from "@/lib//config"; + +const formSchema = z.object({ + beneficiary: z.string().startsWith("0x"), + amount: z.string().refine((val) => !isNaN(parseFloat(val)) && parseFloat(val) > 0, { + message: "Amount must be a positive number", + }), + startTime: z.string().refine((val) => !isNaN(parseInt(val)), { + message: "Start time must be a valid timestamp", + }), + cliff: z.string().refine((val) => !isNaN(parseInt(val)) && parseInt(val) >= 0, { + message: "Cliff must be a non-negative number", + }), + duration: z.string().refine((val) => !isNaN(parseInt(val)) && parseInt(val) > 0, { + message: "Duration must be greater than 0", + }), +}); + +export default function Vesting() { + const config = useConfig(); + const account = useAccount(); + const address = useAtomValue(addressAtom); + const [isCreating, setIsCreating] = useState(false); + const [isClaiming, setIsClaiming] = useState(false); + + const form = useForm>({ + resolver: zodResolver(formSchema), + defaultValues: { + beneficiary: "", + amount: "", + startTime: Math.floor(Date.now() / 1000).toString(), + cliff: "0", + duration: "0", + }, + }); + + const { writeContractAsync } = useWriteContract({ + config: config, + }); + + const { data: vestingSchedule, isLoading: isLoadingSchedule } = useReadContracts({ + contracts: [ + { + address: VESTING_ADDRESS, + abi: vestingAbi, + functionName: "getVestingSchedule", + args: [account.address || "0x0000000000000000000000000000000000000000"], + } + ], + }); + + async function onSubmit(values: z.infer) { + try { + setIsCreating(true); + const tx = await writeContractAsync({ + address: VESTING_ADDRESS, + abi: vestingAbi, + functionName: 'createVestingSchedule', + args: [ + values.beneficiary as `0x${string}`, + parseUnits(values.amount, 18), + BigInt(values.startTime), + BigInt(values.cliff), + BigInt(values.duration), + ], + }); + + const receipt = await useWaitForTransactionReceipt({ + hash: tx, + }); + + form.reset(); + } catch (error) { + console.error('Error creating vesting schedule:', error); + } finally { + setIsCreating(false); + } + } + + const handleClaim = async () => { + try { + setIsClaiming(true); + const tx = await writeContractAsync({ + address: VESTING_ADDRESS, + abi: vestingAbi, + functionName: 'release', + args: [address as `0x${string}`], + }); + + await useWaitForTransactionReceipt({ + hash: tx, + }); + } catch (error) { + console.error('Error claiming tokens:', error); + } finally { + setIsClaiming(false); + } + }; + + const schedule = vestingSchedule?.[0]?.result; + + return ( +
+
+

Create Vesting Schedule

+
+ + ( + + Beneficiary Address + + + + + + )} + /> + ( + + Amount + + + + + + )} + /> + ( + + Start Time (Unix Timestamp) + + + + + + )} + /> + ( + + Cliff (seconds) + + + + + + )} + /> + ( + + Duration (seconds) + + + + + + )} + /> + + + +
+ +
+

Your Vesting Schedule

+ {isLoadingSchedule ? ( +
+ + + + + +
+ ) : schedule ? ( +
+

Total Amount: {formatUnits(schedule.totalAmount, 18)} tokens

+

Start Time: {new Date(Number(schedule.startTime) * 1000).toLocaleString()}

+

Cliff: {Number(schedule.cliff)} seconds

+

Duration: {Number(schedule.duration)} seconds

+

Released Amount: {formatUnits(schedule.releasedAmount, 18)} tokens

+

Status: {schedule.revoked ? 'Revoked' : 'Active'}

+ {!schedule.revoked && ( + + )} +
+ ) : ( +
+

No vesting schedule found

+
+ )} +
+
+ ); +} \ No newline at end of file diff --git a/challenge-3-frontend/components/withdraw.tsx b/challenge-3-frontend/components/withdraw.tsx new file mode 100644 index 0000000..8be1ab5 --- /dev/null +++ b/challenge-3-frontend/components/withdraw.tsx @@ -0,0 +1,434 @@ +"use client"; + +// React imports +import { useState, useEffect } from "react"; + +// Wagmi imports +import { + type BaseError, + useWaitForTransactionReceipt, + useConfig, + useWriteContract, + useReadContracts, + useAccount, +} from "wagmi"; + +// Viem imports +import { parseUnits, formatUnits } from "viem"; + +// Lucide imports (for icons) +import { + Ban, + ExternalLink, + ChevronDown, + X, + Hash, + LoaderCircle, + CircleCheck, + WalletMinimal, +} from "lucide-react"; + +// Zod imports +import { z } from "zod"; + +// Zod resolver imports +import { zodResolver } from "@hookform/resolvers/zod"; + +// React hook form imports +import { useForm } from "react-hook-form"; + +// UI imports +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"; + +// Utils imports +import { truncateHash } from "@/lib/utils"; + +// Component imports +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 { localConfig } from "@/app/providers"; +import { mockErc20Abi, yieldFarmingAbi } from "@/lib/abi"; +import { + LP_ADDRESS, + YIELD_FARM_ADDRESS, +} from "@/lib/config"; + +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_FARM_ADDRESS, + abi: yieldFarmingAbi, + functionName: "userInfo", + args: [address ? address : account.address], + }, + { + address: YIELD_FARM_ADDRESS, + abi: yieldFarmingAbi, + functionName: "pendingRewards", + args: [address ? address : account.address], + }, + { + address: LP_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_FARM_ADDRESS, + abi: yieldFarmingAbi, + functionName: "withdraw", + args: [parseUnits(values.amount, decimals as number)], + chainId: westendAssetHub.id, + }); + } else { + writeContractAsync({ + address: YIELD_FARM_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_FARM_ADDRESS, + abi: yieldFarmingAbi, + functionName: "claimRewards", + chainId: westendAssetHub.id, + }); + } else { + writeContractAsync({ + address: YIELD_FARM_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 ? ( + + + + + + + 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} +
+ )} +
+ + + + + +
+
+ ) + } +
+ ); +} \ No newline at end of file diff --git a/challenge-3-frontend/components/yield-farm.tsx b/challenge-3-frontend/components/yield-farm.tsx new file mode 100644 index 0000000..fec621c --- /dev/null +++ b/challenge-3-frontend/components/yield-farm.tsx @@ -0,0 +1,24 @@ +"use client"; + +import { Tabs, TabsContent, TabsList, TabsTrigger } from "./ui/tabs"; +import Stake from "./stake"; +import Withdraw from "./withdraw"; + +export default function YieldFarm() { + return ( +
+ + + Stake + Withdraw + + + + + + + + +
+ ); +} \ No newline at end of file diff --git a/challenge-3-frontend/lib/abi.ts b/challenge-3-frontend/lib/abi.ts index 78ac757..c52f4b0 100644 --- a/challenge-3-frontend/lib/abi.ts +++ b/challenge-3-frontend/lib/abi.ts @@ -1,2419 +1,3415 @@ -// 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 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 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", + }, +]; + +export const vestingAbi = [ + { + "inputs": [ + { + "internalType": "address", + "name": "token_", + "type": "address" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "beneficiary", + "type": "address" + }, + { + "internalType": "uint256", + "name": "amount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "startTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cliff", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + } + ], + "name": "createVestingSchedule", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "beneficiary", + "type": "address" + } + ], + "name": "getVestingSchedule", + "outputs": [ + { + "components": [ + { + "internalType": "uint256", + "name": "totalAmount", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "startTime", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "cliff", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "duration", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "releasedAmount", + "type": "uint256" + }, + { + "internalType": "bool", + "name": "revoked", + "type": "bool" + } + ], + "internalType": "struct TokenVesting.VestingSchedule", + "name": "", + "type": "tuple" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "beneficiary", + "type": "address" + } + ], + "name": "release", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "beneficiary", + "type": "address" + } + ], + "name": "revoke", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] as const; + +export const VESTING_CONTRACT_ADDRESS = "0x93bfafffe5911442f7bec0d9c186479dccff5443"; \ 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..d9f05d7 --- /dev/null +++ b/challenge-3-frontend/lib/config.ts @@ -0,0 +1,7 @@ +export const LP_ADDRESS = + "0x507704Ae184bf2fe699525f33aE3A577d7486437"; +export const REWARD_ADDRESS = + "0x439Bced6319443965D4479Ac97101fD8d8453596"; +export const YIELD_FARM_ADDRESS = + "0xc886861b6d5585C7590B1B6Ce4140a063d360627"; +export const VESTING_ADDRESS = "0x93bfafffe5911442f7bec0d9c186479dccff5443";