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
20 changes: 20 additions & 0 deletions assignments/Solidity/Todo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Node modules
/node_modules

# Compilation output
/dist

# pnpm deploy output
/bundle

# Hardhat Build Artifacts
/artifacts

# Hardhat compilation (v2) support directory
/cache

# Typechain output
/types

# Hardhat coverage reports
/coverage
117 changes: 117 additions & 0 deletions assignments/Solidity/Todo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Todo Smart Contract

A Solidity smart contract for managing personal TODO tasks with deadlines and status tracking.

---

## Overview

This contract allows users to:

* Create TODO tasks with a text description and deadline
* Track the status of tasks: Pending, Done, Cancelled, or Defaulted
* Mark tasks as completed, automatically setting them to Done or Defaulted based on deadline

---

## Contract Details

* **License**: MIT
* **Solidity Version**: ^0.8.28

---

## State Variables

| Variable | Type | Description |
| ------------- | ------------------------- | --------------------------------- |
| `todoCounter` | uint256 | Tracks the total number of TODOs |
| `todos` | mapping(uint => TodoList) | Stores all TODO items by their ID |

### TodoList Struct

| Variable | Type | Description |
| ---------- | ------- | ------------------------------------------------ |
| `id` | uint | Unique ID of the task |
| `owner` | address | Task creator |
| `text` | string | Task description |
| `status` | enum | Task status: Pending, Done, Cancelled, Defaulted |
| `deadline` | uint256 | Timestamp when the task is due |

---

## Functions

### createTodo(string _text, uint _deadline)

Creates a new TODO task.

**Access:** Public

**Requirements:**

* `_text` cannot be empty
* `_deadline` must be at least 10 minutes in the future
* Caller cannot be zero address

**Notes:**

* Increments `todoCounter`
* Saves the new TODO in `todos` mapping
* Emits `TodoCreated` event

---

### completedTodo(uint _id)

Marks a TODO as completed.

**Access:** Task owner only

**Requirements:**

* `_id` must exist
* TODO must be `Pending`
* Caller must be the task owner

**Notes:**

* If the deadline has passed, sets status to `Defaulted`
* Otherwise, sets status to `Done`

---

## Events

| Event | Description |
| ----------------------------------------- | ---------------------------------- |
| `TodoCreated(string text, uint deadline)` | Emitted when a new TODO is created |

---

## Important Notes

1. **Task Ownership**: Only the task creator can mark a TODO as completed.
2. **Deadline Handling**: If a task is completed after its deadline, its status is automatically set to `Defaulted`.
3. **Pending Tasks**: Only tasks with `Pending` status can be completed.

---

## Error Messages

| Message | Meaning |
| --------------------- | ----------------------------------------- |
| "Empty text" | TODO text is empty |
| "Invalid Deadline" | Deadline is less than 10 minutes from now |
| "Zero address" | Caller is the zero address |
| "Invalid id" | TODO ID does not exist |
| "Not pending" | TODO is not in Pending status |
| "Unauthorized Caller" | Caller is not the task owner |

---

## License

MIT

---
19 changes: 19 additions & 0 deletions assignments/Solidity/Todo/contracts/Counter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;

contract Counter {
uint public x;

event Increment(uint by);

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

function incBy(uint by) public {
require(by > 0, "incBy: increment should be positive");
x += by;
emit Increment(by);
}
}
32 changes: 32 additions & 0 deletions assignments/Solidity/Todo/contracts/Counter.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;

import {Counter} from "./Counter.sol";
import {Test} from "forge-std/Test.sol";

// Solidity tests are compatible with foundry, so they
// use the same syntax and offer the same functionality.

contract CounterTest is Test {
Counter counter;

function setUp() public {
counter = new Counter();
}

function test_InitialValue() public view {
require(counter.x() == 0, "Initial value should be 0");
}

function testFuzz_Inc(uint8 x) public {
for (uint8 i = 0; i < x; i++) {
counter.inc();
}
require(counter.x() == x, "Value after calling inc x times should be x");
}

function test_IncByZero() public {
vm.expectRevert();
counter.incBy(0);
}
}
60 changes: 60 additions & 0 deletions assignments/Solidity/Todo/contracts/Todo.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.28;

contract Todo {
uint256 todoCounter;

enum Status {
Pending,
Done,
Cancelled,
Defaulted
}

struct TodoList {
uint id;
address owner;
string text;
Status status;
uint256 deadline;
}
mapping(uint => TodoList) public todos;
event TodoCreated(string text, uint deadline);

function createTodo(
string memory _text,
uint _deadline
) external returns (uint) {
require(bytes(_text).length > 0, "Empty text");
require(_deadline > (block.timestamp + 600), "Invalid Deadline");
require(msg.sender != address(0), "Zero address");

todoCounter++;

todos[todoCounter] = TodoList(
todoCounter,
msg.sender,
_text,
Status.Pending,
_deadline
);

emit TodoCreated(_text, _deadline);
return todoCounter;
}

function completedTodo(uint _id) external {
// TodoList memory t = todos[todoCounter]
require((_id > 0) && (_id <= todoCounter), "Invalid id");

TodoList storage todo = todos[_id];
require(todo.status == Status.Pending, "Not pending");
require(msg.sender == todo.owner, "Unauthorized Caller");

if (block.timestamp > todo.deadline) {
todo.status = Status.Defaulted;
} else {
todo.status = Status.Done;
}
}
}
44 changes: 44 additions & 0 deletions assignments/Solidity/Todo/hardhat.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import "dotenv/config";
import hardhatToolboxMochaEthersPlugin from "@nomicfoundation/hardhat-toolbox-mocha-ethers";
import { configVariable, defineConfig } from "hardhat/config";

export default defineConfig({
plugins: [hardhatToolboxMochaEthersPlugin],
solidity: {
profiles: {
default: {
version: "0.8.28",
},
production: {
version: "0.8.28",
settings: {
optimizer: {
enabled: true,
runs: 200,
},
},
},
},
},
networks: {
hardhatMainnet: {
type: "edr-simulated",
chainType: "l1",
},
hardhatOp: {
type: "edr-simulated",
chainType: "op",
},
sepolia: {
type: "http",
chainType: "l1",
url: configVariable("SEPOLIA_RPC_URL"),
accounts: [configVariable("SEPOLIA_PRIVATE_KEY")],
},
},
verify: {
etherscan: {
apiKey: configVariable("ETHERSCAN_API_KEY"),
},
},
});
Loading