From f90afb860c02f6f63a903b9efdb017fba80916e2 Mon Sep 17 00:00:00 2001 From: AbuTuraab Date: Mon, 31 Mar 2025 09:24:03 +0100 Subject: [PATCH 1/4] registration --- .vscode/settings.json | 3 + ...-70d5e538-ca92-4743-bfb8-ef79176e875b.json | 1 + README.md | 1 + challenge-1-vesting/.vscode/settings.json | 3 + .../contracts/TokenVesting.sol | 81 +++++++++++++++++ challenge-1-vesting/hardhat.config.ts | 2 +- .../contracts/.vscode/settings.json | 3 + ...-365d6f08-2272-4784-816b-d579d3778672.json | 1 + challenge-2-yield-farm/contracts/yeild.sol | 90 +++++++++++++++++++ challenge-2-yield-farm/hardhat.config.ts | 2 +- challenge-2-yield-farm/package-lock.json | 15 +++- challenge-2-yield-farm/package.json | 5 +- challenge-3-frontend/app/providers.tsx | 2 +- 13 files changed, 203 insertions(+), 6 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 .wake/extension/local-local-chain-70d5e538-ca92-4743-bfb8-ef79176e875b.json create mode 100644 challenge-1-vesting/.vscode/settings.json create mode 100644 challenge-2-yield-farm/contracts/.vscode/settings.json create mode 100644 challenge-2-yield-farm/contracts/.wake/extension/local-local-chain-365d6f08-2272-4784-816b-d579d3778672.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..cd573be --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "wake.compiler.solc.remappings": [] +} \ No newline at end of file diff --git a/.wake/extension/local-local-chain-70d5e538-ca92-4743-bfb8-ef79176e875b.json b/.wake/extension/local-local-chain-70d5e538-ca92-4743-bfb8-ef79176e875b.json new file mode 100644 index 0000000..7c5aee3 --- /dev/null +++ b/.wake/extension/local-local-chain-70d5e538-ca92-4743-bfb8-ef79176e875b.json @@ -0,0 +1 @@ +{"type":"local_node","id":"local-chain-70d5e538-ca92-4743-bfb8-ef79176e875b","displayName":"Local Chain 1","state":{"accounts":[{"address":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","balance":1e+22},{"address":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","balance":1e+22},{"address":"0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc","balance":1e+22},{"address":"0x90f79bf6eb2c4f870365e785982e1f101e93b906","balance":1e+22},{"address":"0x15d34aaf54267db7d7c367839aaf71a00a2c6a65","balance":1e+22},{"address":"0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc","balance":1e+22},{"address":"0x976ea74026e726554db657fa54763abd0c3a0aa9","balance":1e+22},{"address":"0x14dc79964da2c08b23698b3d3cc7ca32193d9955","balance":1e+22},{"address":"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f","balance":1e+22},{"address":"0xa0ee7a142d267c1f36714e4a8f75612f20a79720","balance":1e+22}],"deployment":[],"history":[]},"network":{"wakeDump":{"metadata":{"labels":{},"deployedLibraries":{}},"chainDump":"0x1f8b08000000000000ffed56cd6e23370c7e9739e7a03fea27c7a0e8f6d04351604fc5c2a0282a1e743c637826dd1481dfbdd4d84991c05874d1b914a80c181a4ae24752d447be747998e8f7eefea51b9f0e994fdd7da79e5577d7d1d48f1967be08fee190734b7fe079c1c3713da845f288f36ee80ffd729150221bdbcea6bdf205c0e68484ab82d2d7dad3d3b0fcf966cbf1c47f9c702c387d9735dfb052bcce3b7e269ee75db34f94ef8ea79eb845e22a5ff7c86277afae07e4e3ba499fcf771d124d4fe332b733e2982b1452f2aea02115b3b13ec56c8b250a84d6e8644b4a006baca7b169697a71c0752e1a8c669d5851ca988d7b3595a6725996f9bc4c277c6c46367cc184621d6205677c28399440d6876893c88296788a291efda698e2978e1c35db0a546a1070b2c583cc3229cc15b2288d754b4c4bce5129257b4c4a55341922946292a8b1459b8ace249b694b4cc790b273d1856c43821021c6641461883557e3496597c07f03f31d42a8ff6e88a35e692f7647f9372a1a1ba2b2108dcc5c85a83468f0ca36537534b5408eb20b0ca8f693c34e4e53b5377c0d2aa5908222d0519b42169556148ad21914aba243cb6d8a5bc637a91a52ae9eb321576310ff8025ca291ad6552bcd72a349f94d3183670c4e19cfc17800271905a122b8e02de6a29ae7886953cc24402a148d0099c8f8040431a3f65512ab449db242e18e2d31513107d4ce14e105d25548413b76186b002fcfc52894eb366a4bcc6a532d9e41239618abaf8ed8638ed10423b923299c93317eb3fb14d02c9566b716b0dd87eab50a85987f7be9f68ca5adbc74473cf1b8fc84f37eab3232efd17e1e69e0f952db0a912b1c0b53801250bc870c3e644f549cc662b571a0737251b250dbaada1dd5e25471c9ba201a0ffdf8eac67798b1e0c2bf4ed3b2955f8b54db1969e9a7717ed30b5e58bfeaa0258b01d0d71aad03f649ca5d8d72f3d94516c69084272ca484ad8ca919d87a9b9d69adc08989fbe3326f69eb303dce0fc3341d3651f8fff86f8fdb0de40776903eeee71b0da9883fcf5cdeb6bd6f657d6093915a1af3b33c901f70c1575e3af4cf5bd2ca951e6f28bbb6cd3f32ffc2a74f387f6c9ebff6cbbe9cf02b0e9bbedbd6fd7efa109d4b97fc7059f9bb555f39f68191a6f1a191f0764ffdfc9e9784dcbfdc75d3e1c0a7757efe726b7ddfb79ad1130ebb9525453c3e0dc3f92f1ed5a33df90c0000"},"type":"Local Chain","config":{"sessionId":"local-chain-70d5e538-ca92-4743-bfb8-ef79176e875b","type":"anvil","uri":"ws://127.0.0.1:38109"}},"stateFingerprint":"3a82e3a6d1ac2e4daae286769e6107faa655d321408b0b1f9df23ede1a63b531","persistence":{"isDirty":false,"isAutosaveEnabled":true,"lastSaveTimestamp":1742912204383}} \ No newline at end of file diff --git a/README.md b/README.md index 2f03b34..3250727 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ Go to **Participant Registration** section and register to be the workshop parti ``` | 🦄 | Name | Github username | Your current occupation | +| 😊 | Aliyu Adeniji | AbuTuraab | Freelance Developer | ``` - Step 5: `Commit` your code and push to the forked Github repository diff --git a/challenge-1-vesting/.vscode/settings.json b/challenge-1-vesting/.vscode/settings.json new file mode 100644 index 0000000..cd573be --- /dev/null +++ b/challenge-1-vesting/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "wake.compiler.solc.remappings": [] +} \ No newline at end of file diff --git a/challenge-1-vesting/contracts/TokenVesting.sol b/challenge-1-vesting/contracts/TokenVesting.sol index 43d4c3a..6913372 100644 --- a/challenge-1-vesting/contracts/TokenVesting.sol +++ b/challenge-1-vesting/contracts/TokenVesting.sol @@ -31,17 +31,26 @@ import "@openzeppelin/contracts/utils/ReentrancyGuard.sol"; contract TokenVesting is Ownable(msg.sender), Pausable, ReentrancyGuard { struct VestingSchedule { // TODO: Define the vesting schedule struct + uint256 totalAmount; + uint256 startTime; + uint256 cliffDuration; + uint256 vestingDuration; + uint256 amountClaimed; + bool revoked; } // Token being vested // TODO: Add state variables + IERC20 public token; // Mapping from beneficiary to vesting schedule // TODO: Add state variables + mapping(address => VestingSchedule) public vestingSchedules; // Whitelist of beneficiaries // TODO: Add state variables + mapping(address => bool) public whitelist; // Events event VestingScheduleCreated(address indexed beneficiary, uint256 amount); @@ -52,6 +61,7 @@ contract TokenVesting is Ownable(msg.sender), Pausable, ReentrancyGuard { constructor(address tokenAddress) { // TODO: Initialize the contract + token = IERC20(tokenAddress); } @@ -80,21 +90,92 @@ contract TokenVesting is Ownable(msg.sender), Pausable, ReentrancyGuard { uint256 startTime ) external onlyOwner onlyWhitelisted(beneficiary) whenNotPaused { // TODO: Implement vesting schedule creation + require(vestingSchedules[beneficiary].totalAmount == 0, "Schedule already exists"); + require(amount > 0, "Amount is zero"); + require(vestingDuration > 0, "Duration is zero"); + require(cliffDuration < vestingDuration, "Cliff is too long"); + + VestingSchedule memory schedule = VestingSchedule({ + totalAmount: amount, + startTime: startTime, + cliffDuration: cliffDuration, + vestingDuration: vestingDuration, + amountClaimed: 0, + revoked: false + }); + + vestingSchedules[beneficiary] = schedule; + + require(token.transferFrom(owner(), address(this), amount), "Token transfer failed"); + + emit VestingScheduleCreated(beneficiary, amount); } function calculateVestedAmount( address beneficiary ) public view returns (uint256) { // TODO: Implement vested amount calculation + VestingSchedule memory schedule = vestingSchedules[beneficiary]; + + if (schedule.totalAmount == 0 || schedule.revoked) { + return 0; + } + + if (block.timestamp < schedule.startTime + schedule.cliffDuration) { + return 0; + } + + if (block.timestamp >= schedule.startTime + schedule.vestingDuration) { + return schedule.totalAmount; + } + + uint256 timeFromStart = block.timestamp - schedule.startTime; + + uint256 vestedAmount = (schedule.totalAmount * timeFromStart) / schedule.vestingDuration; + + return vestedAmount; + } function claimVestedTokens() external nonReentrant whenNotPaused { // TODO: Implement token claiming + VestingSchedule storage schedule = vestingSchedules[msg.sender]; + + require(schedule.totalAmount > 0, "No schedule found"); + require(!schedule.revoked, "Vesting revoked"); + + uint256 vestedAmount = calculateVestedAmount(msg.sender); + uint256 claimableAmount = vestedAmount - schedule.amountClaimed; + + require(claimableAmount > 0, "No tokens to claim"); + + schedule.amountClaimed = vestedAmount; + + require(token.transfer(msg.sender, claimableAmount), "Token transfer failed"); + + emit TokensClaimed(msg.sender, claimableAmount); + } function revokeVesting(address beneficiary) external onlyOwner { // TODO: Implement vesting revocation + VestingSchedule storage schedule = vestingSchedules[beneficiary]; + + require(schedule.totalAmount > 0, "No schedule found"); + require(!schedule.revoked, "Already revoked"); + + uint256 vestedAmount = calculateVestedAmount(beneficiary); + uint256 unclaimedAmount = schedule.totalAmount - vestedAmount; + + schedule.revoked = true; + + if (unclaimedAmount > 0) { + require(token.transfer(owner(), unclaimedAmount), "Token transfer failed"); + } + + emit VestingRevoked(beneficiary); + } function pause() external onlyOwner { diff --git a/challenge-1-vesting/hardhat.config.ts b/challenge-1-vesting/hardhat.config.ts index 24ee97a..f3cba0b 100644 --- a/challenge-1-vesting/hardhat.config.ts +++ b/challenge-1-vesting/hardhat.config.ts @@ -7,7 +7,7 @@ const config: HardhatUserConfig = { solidity: { version: "0.8.20", settings: { - optimizer: { + optimizer: { enabled: true, runs: 1, // Lower optimization runs for simpler bytecode }, diff --git a/challenge-2-yield-farm/contracts/.vscode/settings.json b/challenge-2-yield-farm/contracts/.vscode/settings.json new file mode 100644 index 0000000..cd573be --- /dev/null +++ b/challenge-2-yield-farm/contracts/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "wake.compiler.solc.remappings": [] +} \ No newline at end of file diff --git a/challenge-2-yield-farm/contracts/.wake/extension/local-local-chain-365d6f08-2272-4784-816b-d579d3778672.json b/challenge-2-yield-farm/contracts/.wake/extension/local-local-chain-365d6f08-2272-4784-816b-d579d3778672.json new file mode 100644 index 0000000..4d13452 --- /dev/null +++ b/challenge-2-yield-farm/contracts/.wake/extension/local-local-chain-365d6f08-2272-4784-816b-d579d3778672.json @@ -0,0 +1 @@ +{"type":"local_node","id":"local-chain-365d6f08-2272-4784-816b-d579d3778672","displayName":"Local Chain 1","state":{"accounts":[{"address":"0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266","balance":1e+22},{"address":"0x70997970c51812dc3a010c7d01b50e0d17dc79c8","balance":1e+22},{"address":"0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc","balance":1e+22},{"address":"0x90f79bf6eb2c4f870365e785982e1f101e93b906","balance":1e+22},{"address":"0x15d34aaf54267db7d7c367839aaf71a00a2c6a65","balance":1e+22},{"address":"0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc","balance":1e+22},{"address":"0x976ea74026e726554db657fa54763abd0c3a0aa9","balance":1e+22},{"address":"0x14dc79964da2c08b23698b3d3cc7ca32193d9955","balance":1e+22},{"address":"0x23618e81e3f5cdf7f54c3d65f7fbc0abf5b21e8f","balance":1e+22},{"address":"0xa0ee7a142d267c1f36714e4a8f75612f20a79720","balance":1e+22}],"deployment":[],"history":[]},"network":{"wakeDump":{"metadata":{"labels":{},"deployedLibraries":{}},"chainDump":"0x1f8b08000000000000ffed56cd6a24470c7e973efb507faa1f1f4dc8e6904308ec292c834a52d94d7abacd743beb60e6dda39e193bd80c4b96f425901a18aa5555fa2495ea935eba3a4cf47b77fbd28d4ffb2a87eeb633cfa6bbe968eac78ab39c05ff70e8b9a5dfcbbce0fef174d0aae41ee7ddd0effbe52ca1423eaf3b57ed4dce00be16243c29e0beb59e9e86e5cf375b1e0ff2c70147c6e9bbacf98695ea75ddc933c93cef56fb54f9eef1d093ac91b8c84f7b74b1bb359703fa71d9648fc79b0e89a6a77199d733ea58604aa5c4c0e8c8e4ea7c2cb97af64489d03b5b3c9702708af534ae5a56bd38e069ae1a9c155bc450a9585d783595263e2feb7c5ea603deaf46aef88a09ec036283e062e29a38918f29fba2b264359e6a4ac4b829a6fa65b3642bbe01714b0a4e9e23e8ac92c1daa0aad2dcb6c4f4140231738d588c69e82a64607645d578b6ae6170c557da123308941a420ea9fa542065c8b938439872abcd4532351488dfc07c8790dabf1bea683436aadd59ff9dc9cea76c3c64a7b3d0201b0b16a2f1aba936bbc650b3ee020766fde9e1a0a7a9f92bbe26534a2ac910d86c1d9347630d2536b68211c336adb94d79cbf816d352a92d4a75145a4eea1f8846b96427b65963456fb498b829668a8229181725b9081034a320358490a2c7ca66f51cb16c8a5914c824b60850895c2c40902bdad834b138db520d2a776c89894624a10d8e9517c83625051b24606e09a23e176750afdb992d319b2f8da38045e49c5b6c812462cdd925a7b9a3295c8b7371b3fb54d0aa9566772a60bb0fd5eb245462feeda57b10e475e5a57bc4838ccb4f383f6c5546e607f49f471a643ed736260a2c9985127042f51e2ac4542311078becad0b606b0959b3d0fa66d63b6a1c0c87e243528dfb7e7c75e33bcc5870915fa769d9caaf45abed8cb4f4d338bfe985a8acdf6cb29ac500185bcb3e80c4a2e5ae65bdf91ab2286368c2133219652be75a05f1d1d7e0d656e02024fde3326f69eb30ddcf77c334ed3751f8fff86f8feb0de40776d03eeee72b0da98a3fcfc26fdbdeb7b23149246faa2ec8b33e901f70c1575edaf7cf5bd2ca851eaf28bbb4cd3f8afc22874f387f6c9ebff6cb031ff02b0e9bbedbb5fbfdf4213ae72ef9eebcf277ab7ee2d83b419ac6bb9584b77beac7f7bca4e4fee5a69bf67b399ce6c72fd7d61ffab566f484c3eec4922a1e9f86e1f817dd6f73c4f90c0000"},"type":"Local Chain","config":{"sessionId":"local-chain-365d6f08-2272-4784-816b-d579d3778672","type":"anvil","uri":"ws://127.0.0.1:35161"}},"stateFingerprint":"3a82e3a6d1ac2e4daae286769e6107faa655d321408b0b1f9df23ede1a63b531","persistence":{"isDirty":false,"isAutosaveEnabled":true,"lastSaveTimestamp":1743176468522}} \ No newline at end of file diff --git a/challenge-2-yield-farm/contracts/yeild.sol b/challenge-2-yield-farm/contracts/yeild.sol index 421496a..3bd8582 100644 --- a/challenge-2-yield-farm/contracts/yeild.sol +++ b/challenge-2-yield-farm/contracts/yeild.sol @@ -71,6 +71,12 @@ contract YieldFarm is ReentrancyGuard, Ownable { uint256 _rewardRate ) Ownable(msg.sender) { // TODO: Initialize contract state + + lpToken = IERC20(_lpToken); + rewardToken = IERC20(_rewardToken); + rewardRate = _rewardRate; + + lastUpdateTime = block.timestamp; } function updateReward(address _user) internal { @@ -90,6 +96,16 @@ contract YieldFarm is ReentrancyGuard, Ownable { // 1. Calculate rewards since last update // 2. Apply boost multiplier // 3. Return total pending rewards + + if (totalStaked ==0){ + return rewardPerTokenStored; + } + + uint256 timeSinceLastUpdate = block.timestamp - lastUpdateTime; + uint256 rewardsSinceLastUpdate = timeSinceLastUpdate * rewardRate; + uint256 totalRewards = rewardPerTokenStored + (rewardsSinceLastUpdate * 1e18) / totalStaked; + + return totalRewards; } function earned(address _user) public view returns (uint256) { @@ -98,6 +114,14 @@ contract YieldFarm is ReentrancyGuard, Ownable { // 1. Calculate rewards since last update // 2. Apply boost multiplier // 3. Return total pending rewards + + UserInfo storage user = userInfo[_user]; + + + uint256 userRewardPerToken = rewardPerToken(); + uint256 rewards = (user.amount * userRewardPerToken) / 1e18; + + return rewards - user.rewardDebt + user.pendingRewards; } /** @@ -111,6 +135,19 @@ contract YieldFarm is ReentrancyGuard, Ownable { // 2. Transfer LP tokens from user // 3. Update user info and total staked amount // 4. Emit Staked event + + updateReward(msg.sender); + + lpToken.transferFrom(msg.sender, address(this), _amount); + + require(_amount > 0, "Cannot stake 0"); + + UserInfo storage user = userInfo[msg.sender]; + user.amount += _amount; + user.startTime = block.timestamp; + totalStaked += _amount; + + emit Staked(msg.sender, _amount); } /** @@ -124,6 +161,19 @@ contract YieldFarm is ReentrancyGuard, Ownable { // 2. Transfer LP tokens to user // 3. Update user info and total staked amount // 4. Emit Withdrawn event + + updateReward(msg.sender); + + UserInfo storage user = userInfo[msg.sender]; + require(user.amount >= _amount, "Insufficient balance"); + + user.amount -= _amount; + user.rewardDebt = (user.amount * rewardPerTokenStored) / 1e18; + totalStaked -= _amount; + + lpToken.transfer(msg.sender, _amount); + + emit Withdrawn(msg.sender, _amount); } /** @@ -136,6 +186,17 @@ contract YieldFarm is ReentrancyGuard, Ownable { // 2. Transfer rewards to user // 3. Update user reward debt // 4. Emit RewardsClaimed event + + updateReward(msg.sender); + + UserInfo storage user = userInfo[msg.sender]; + uint256 rewards = user.pendingRewards; + user.pendingRewards = 0; + user.rewardDebt = (user.amount * rewardPerTokenStored) / 1e18; + + rewardToken.transfer(msg.sender, rewards); + + emit RewardsClaimed(msg.sender, rewards); } /** @@ -147,6 +208,19 @@ contract YieldFarm is ReentrancyGuard, Ownable { // 1. Transfer all LP tokens back to user // 2. Reset user info // 3. Emit EmergencyWithdrawn event + + UserInfo storage user = userInfo[msg.sender]; + uint256 amount = user.amount; + user.amount = 0; + user.startTime = 0; + user.rewardDebt = 0; + user.pendingRewards = 0; + totalStaked -= amount; + + lpToken.transfer(msg.sender, amount); + + emit EmergencyWithdrawn(msg.sender, amount); + } /** @@ -161,6 +235,19 @@ contract YieldFarm is ReentrancyGuard, Ownable { // Requirements: // 1. Calculate staking duration // 2. Return appropriate multiplier based on duration thresholds + + UserInfo storage user = userInfo[_user]; + uint256 stakingDuration = block.timestamp - user.startTime; + + if (stakingDuration >= BOOST_THRESHOLD_3){ + return 200; + } else if (stakingDuration >= BOOST_THRESHOLD_2){ + return 150; + } else if (stakingDuration >= BOOST_THRESHOLD_1){ + return 125; + } else { + return 100; + } } /** @@ -172,6 +259,9 @@ contract YieldFarm is ReentrancyGuard, Ownable { // Requirements: // 1. Update rewards before changing rate // 2. Set new reward rate + + updateReward(address(0)); + rewardRate = _newRate; } /** diff --git a/challenge-2-yield-farm/hardhat.config.ts b/challenge-2-yield-farm/hardhat.config.ts index 24ee97a..f3cba0b 100644 --- a/challenge-2-yield-farm/hardhat.config.ts +++ b/challenge-2-yield-farm/hardhat.config.ts @@ -7,7 +7,7 @@ const config: HardhatUserConfig = { solidity: { version: "0.8.20", settings: { - optimizer: { + optimizer: { enabled: true, runs: 1, // Lower optimization runs for simpler bytecode }, diff --git a/challenge-2-yield-farm/package-lock.json b/challenge-2-yield-farm/package-lock.json index 4cbdfb0..e224581 100644 --- a/challenge-2-yield-farm/package-lock.json +++ b/challenge-2-yield-farm/package-lock.json @@ -9,7 +9,8 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@openzeppelin/contracts": "^5.1.0" + "@openzeppelin/contracts": "^5.1.0", + "dotenv": "^16.4.7" }, "devDependencies": { "@nomicfoundation/hardhat-toolbox": "^5.0.0", @@ -3383,6 +3384,18 @@ "node": ">=8" } }, + "node_modules/dotenv": { + "version": "16.4.7", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz", + "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/dunder-proto": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.0.tgz", diff --git a/challenge-2-yield-farm/package.json b/challenge-2-yield-farm/package.json index 5366ac8..99f1f7e 100644 --- a/challenge-2-yield-farm/package.json +++ b/challenge-2-yield-farm/package.json @@ -10,13 +10,14 @@ "license": "ISC", "description": "", "volta": { - "node": "22.12.0" + "node": "22.14.0" }, "devDependencies": { "@nomicfoundation/hardhat-toolbox": "^5.0.0", "hardhat": "^2.22.17" }, "dependencies": { - "@openzeppelin/contracts": "^5.1.0" + "@openzeppelin/contracts": "^5.1.0", + "dotenv": "^16.4.7" } } diff --git a/challenge-3-frontend/app/providers.tsx b/challenge-3-frontend/app/providers.tsx index 91243fe..aab70b8 100644 --- a/challenge-3-frontend/app/providers.tsx +++ b/challenge-3-frontend/app/providers.tsx @@ -41,7 +41,7 @@ export const westendAssetHub = defineChain({ }, contracts: { multicall3: { - address: '0x5545dec97cb957e83d3e6a1e82fabfacf9764cf1', + address: '0x8cf6dcbF49559ac5ad4e62334064E32BC438779F', blockCreated: 10174702, }, }, From e00fe636b46810e792c8ffe2907a9822cec48025 Mon Sep 17 00:00:00 2001 From: AbuTuraab Date: Mon, 14 Apr 2025 17:47:39 +0100 Subject: [PATCH 2/4] challenges-update --- challenge-3-frontend/app/page.tsx | 14 +- .../loading.tsx | 0 .../page.tsx | 4 +- challenge-3-frontend/app/wallet/page.tsx | 5 +- challenge-3-frontend/components/navbar.tsx | 10 +- .../components/send-transaction.tsx | 162 +- .../components/ui/calendar.tsx | 70 + .../components/ui/popover.tsx | 31 + challenge-3-frontend/lib/abi.ts | 2248 +---------------- challenge-3-frontend/package-lock.json | 345 ++- challenge-3-frontend/package.json | 5 +- 11 files changed, 701 insertions(+), 2193 deletions(-) rename challenge-3-frontend/app/{send-transaction => vest-tokens}/loading.tsx (100%) rename challenge-3-frontend/app/{send-transaction => vest-tokens}/page.tsx (82%) create mode 100644 challenge-3-frontend/components/ui/calendar.tsx create mode 100644 challenge-3-frontend/components/ui/popover.tsx diff --git a/challenge-3-frontend/app/page.tsx b/challenge-3-frontend/app/page.tsx index fb01185..36a9963 100644 --- a/challenge-3-frontend/app/page.tsx +++ b/challenge-3-frontend/app/page.tsx @@ -18,16 +18,16 @@ export default function Home() { Wallet
  • - Send transaction + Vest Tokens
  • -
  • - Write contract +
  • + Add Vesting Beneficiaries
  • - Mint/Redeem LST Bifrost -
  • + Remove Vesting Beneficiaries + -
    + {/*
    Read our docs -
    +
    */}