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
78 changes: 78 additions & 0 deletions assignments/foundry test/src/CounterV3.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;

/**
* @title CounterV3
* @dev Version 3: Owner-only access + Privilege system
* Owner can grant/revoke privilege to non-owners to call state-changing functions
*/
contract CounterV3 {
uint public x;
address public owner;
mapping(address => bool) public privileged;

event Increment(uint by);
event Decrement(uint by);
event PrivilegeGranted(address indexed account);
event PrivilegeRevoked(address indexed account);

modifier onlyOwner() {
require(msg.sender == owner, "CounterV3: caller is not the owner");
_;
}

modifier onlyOwnerOrPrivileged() {
require(
msg.sender == owner || privileged[msg.sender],
"CounterV3: caller is not owner or privileged"
);
_;
}

constructor() {
owner = msg.sender;
}

function inc() public onlyOwnerOrPrivileged {
x++;
emit Increment(1);
}

function incBy(uint by) public onlyOwnerOrPrivileged {
require(by > 0, "incBy: increment should be positive");
x += by;
emit Increment(by);
}

/**
* @dev Decreases the counter by the specified amount
* @param by The amount to decrease (must be positive and not exceed current counter value)
*/
function decrease(uint by) public onlyOwnerOrPrivileged {
require(by > 0, "decrease: decrement should be positive");
require(x >= by, "decrease: counter cannot go below zero");
x -= by;
emit Decrement(by);
}

/**
* @dev Grants privilege to a non-owner to call state-changing functions
* @param account The address to grant privilege to
*/
function grantPrivilege(address account) public onlyOwner {
require(account != address(0), "CounterV3: invalid address");
require(account != owner, "CounterV3: owner is already privileged");
privileged[account] = true;
emit PrivilegeGranted(account);
}

/**
* @dev Revokes privilege from a non-owner
* @param account The address to revoke privilege from
*/
function revokePrivilege(address account) public onlyOwner {
require(privileged[account], "CounterV3: account is not privileged");
privileged[account] = false;
emit PrivilegeRevoked(account);
}
}
152 changes: 152 additions & 0 deletions assignments/foundry test/src/TimeLock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
//SPDX-License-Identifier: MIT
pragma solidity 0.8.28;

contract TimeLockV1 {

struct Vault {
uint balance;
uint unlockTime;
bool active;
}

mapping(address => Vault[]) private vaults;

event Deposited(address indexed user, uint vaultId, uint amount, uint unlockTime);
event Withdrawn(address indexed user, uint vaultId, uint amount);

function deposit(uint _unlockTime) external payable returns (uint) {
require(msg.value > 0, "Deposit must be greater than zero");
require(_unlockTime > block.timestamp, "Unlock time must be in the future");

// Create new vault
vaults[msg.sender].push(Vault({
balance: msg.value,
unlockTime: _unlockTime,
active: true
}));

uint vaultId = vaults[msg.sender].length - 1;
emit Deposited(msg.sender, vaultId, msg.value, _unlockTime);

return vaultId;
}
function withdraw(uint _vaultId) external {
require(_vaultId < vaults[msg.sender].length, "Invalid vault ID");

Vault storage userVault = vaults[msg.sender][_vaultId];
require(userVault.active, "Vault is not active");
require(userVault.balance > 0, "Vault has zero balance");
require(block.timestamp >= userVault.unlockTime, "Funds are still locked");

uint amount = userVault.balance;

// Mark vault as inactive and clear balance
userVault.balance = 0;
userVault.active = false;

(bool success, ) = payable(msg.sender).call{value: amount}("");
require(success, "Transfer failed");

emit Withdrawn(msg.sender, _vaultId, amount);
}
function withdrawAll() external returns (uint) {
uint totalWithdrawn = 0;
Vault[] storage userVaults = vaults[msg.sender];

for (uint i = 0; i < userVaults.length; i++) {
if (userVaults[i].active &&
userVaults[i].balance > 0 &&
block.timestamp >= userVaults[i].unlockTime) {

uint amount = userVaults[i].balance;
userVaults[i].balance = 0;
userVaults[i].active = false;

totalWithdrawn += amount;
emit Withdrawn(msg.sender, i, amount);
}
}

require(totalWithdrawn > 0, "No unlocked funds available");

(bool success, ) = payable(msg.sender).call{value: totalWithdrawn}("");
require(success, "Transfer failed");

return totalWithdrawn;
}
function getVaultCount(address _user) external view returns (uint) {
return vaults[_user].length;
}
function getVault(address _user, uint _vaultId) external view returns (
uint balance,
uint unlockTime,
bool active,
bool isUnlocked
) {
require(_vaultId < vaults[_user].length, "Invalid vault ID");

Vault storage vault = vaults[_user][_vaultId];
return (
vault.balance,
vault.unlockTime,
vault.active,
block.timestamp >= vault.unlockTime
);
}
function getAllVaults(address _user) external view returns (Vault[] memory) {
return vaults[_user];
}
function getActiveVaults(address _user) external view returns (
uint[] memory activeVaults,
uint[] memory balances,
uint[] memory unlockTimes
) {
Vault[] storage userVaults = vaults[_user];

// Count active vaults
uint activeCount = 0;
for (uint i = 0; i < userVaults.length; i++) {
if (userVaults[i].active && userVaults[i].balance > 0) {
activeCount++;
}
}

// Create arrays
activeVaults = new uint[](activeCount);
balances = new uint[](activeCount);
unlockTimes = new uint[](activeCount);

// Populate arrays
uint index = 0;
for (uint i = 0; i < userVaults.length; i++) {
if (userVaults[i].active && userVaults[i].balance > 0) {
activeVaults[index] = i;
balances[index] = userVaults[i].balance;
unlockTimes[index] = userVaults[i].unlockTime;
index++;
}
}

return (activeVaults, balances, unlockTimes);
}
function getTotalBalance(address _user) external view returns (uint total) {
Vault[] storage userVaults = vaults[_user];
for (uint i = 0; i < userVaults.length; i++) {
if (userVaults[i].active) {
total += userVaults[i].balance;
}
}
return total;
}
function getUnlockedBalance(address _user) external view returns (uint unlocked) {
Vault[] storage userVaults = vaults[_user];
for (uint i = 0; i < userVaults.length; i++) {
if (userVaults[i].active &&
userVaults[i].balance > 0 &&
block.timestamp >= userVaults[i].unlockTime) {
unlocked += userVaults[i].balance;
}
}
return unlocked;
}
}
Loading