Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"wake.compiler.solc.remappings": []
}
Original file line number Diff line number Diff line change
@@ -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}}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 3 additions & 0 deletions challenge-1-vesting/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"wake.compiler.solc.remappings": []
}
81 changes: 81 additions & 0 deletions challenge-1-vesting/contracts/TokenVesting.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -52,6 +61,7 @@ contract TokenVesting is Ownable(msg.sender), Pausable, ReentrancyGuard {

constructor(address tokenAddress) {
// TODO: Initialize the contract
token = IERC20(tokenAddress);

}

Expand Down Expand Up @@ -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 {
Expand Down
2 changes: 1 addition & 1 deletion challenge-1-vesting/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
},
Expand Down
3 changes: 3 additions & 0 deletions challenge-2-yield-farm/contracts/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"wake.compiler.solc.remappings": []
}
Original file line number Diff line number Diff line change
@@ -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}}
90 changes: 90 additions & 0 deletions challenge-2-yield-farm/contracts/yeild.sol
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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) {
Expand All @@ -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;
}

/**
Expand All @@ -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);
}

/**
Expand All @@ -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);
}

/**
Expand All @@ -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);
}

/**
Expand All @@ -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);

}

/**
Expand All @@ -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;
}
}

/**
Expand All @@ -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;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion challenge-2-yield-farm/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
},
Expand Down
15 changes: 14 additions & 1 deletion challenge-2-yield-farm/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions challenge-2-yield-farm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
Loading