summaryrefslogtreecommitdiff
path: root/Year_3/Blockchain/MafiaToken/MafiaToken.sol
diff options
context:
space:
mode:
Diffstat (limited to 'Year_3/Blockchain/MafiaToken/MafiaToken.sol')
-rw-r--r--Year_3/Blockchain/MafiaToken/MafiaToken.sol278
1 files changed, 278 insertions, 0 deletions
diff --git a/Year_3/Blockchain/MafiaToken/MafiaToken.sol b/Year_3/Blockchain/MafiaToken/MafiaToken.sol
new file mode 100644
index 0000000..14723cc
--- /dev/null
+++ b/Year_3/Blockchain/MafiaToken/MafiaToken.sol
@@ -0,0 +1,278 @@
+// Cariotti 1000001948
+// SPDX-License-Identifier: MIT
+
+pragma solidity ^0.8.0;
+
+import "./exam-2022-06-24-specs.sol";
+
+contract MafiaToken is ERC20, MafiosoTokenSpecs {
+ enum Role { USER, PICCIOTTO, GODFATHER }
+ struct Mafioso {
+ address id;
+ uint tokens;
+ Role role;
+ bool active;
+ uint8 children;
+ }
+
+ struct Approve {
+ address owner;
+ uint amount;
+ }
+
+ mapping(address => Mafioso) mafiosi;
+ address[] address_users;
+ address public override immutable godfather;
+ mapping(address => Approve[]) approves;
+
+
+ uint public override totalSupply;
+
+ uint8 private pizzo; // Use `pizzoRate()`
+ uint private salary; // Use `picciottiSalary()`
+
+ uint immutable creation_time;
+ uint last_salary;
+
+ error GodfatherCantPay(uint min_tokens);
+
+ constructor(uint initialSupply) {
+ totalSupply = initialSupply;
+ godfather = msg.sender;
+
+ mafiosi[msg.sender] = Mafioso({
+ id: msg.sender,
+ tokens: initialSupply,
+ role: Role.GODFATHER,
+ active: true,
+ children: 0
+ });
+ address_users.push(msg.sender);
+ salary = 100; // Default initial salary
+
+ creation_time = block.timestamp;
+ last_salary = block.timestamp;
+ }
+
+ modifier MustBeAMafioso(address account) {
+ require(mafiosi[account].id != address(0), "This address is not a 'mafioso'");
+
+ _;
+ }
+
+ modifier MustBeTheGodfather() {
+ require(msg.sender == godfather, "This action is available only for the godfather.");
+
+ _;
+ }
+
+ modifier MustBeAtLeastAPicciotto(address account) {
+ require(
+ account == godfather || mafiosi[account].role == Role.PICCIOTTO,
+ "This action is available only for the godfather and picciottis."
+ );
+
+ _;
+ }
+
+ function balanceOf(address account) public view override MustBeAMafioso(account) returns (uint256) {
+ return mafiosi[account].tokens;
+ }
+
+ function _transfer_money(address sender, address recipient, uint amount) internal {
+ uint to_godfather = (
+ (sender == godfather) ?
+ 0 : amount - (amount * pizzo / 100)
+ );
+
+ mafiosi[sender].tokens -= amount;
+ mafiosi[recipient].tokens += (amount - to_godfather);
+ mafiosi[godfather].tokens += to_godfather;
+
+ emit Transfer(sender, recipient, (amount - to_godfather));
+ emit Transfer(recipient, godfather, to_godfather);
+ }
+
+ function transfer(address recipient, uint256 amount)
+ public
+ override
+ MustBeAMafioso(recipient) MustBeAMafioso(msg.sender)
+ returns (bool)
+ {
+ require(mafiosi[msg.sender].tokens >= amount, "You don't have enough tokens to make this transfer");
+
+ _transfer_money(msg.sender, recipient, amount);
+
+ // Always returns a true
+ return true;
+ }
+
+
+ function approve(address spender, uint256 amount)
+ public
+ override
+ MustBeAMafioso(msg.sender) MustBeAMafioso(spender)
+ returns (bool)
+ {
+ approves[spender].push(Approve({
+ owner: msg.sender,
+ amount: amount
+ }));
+
+
+ emit Approval(msg.sender, spender, amount);
+
+ // Always return a true
+ return true;
+ }
+
+ function transferFrom(address sender, address recipient, uint256 amount)
+ public
+ override
+ MustBeAMafioso(recipient) MustBeAMafioso(sender)
+ returns (bool)
+ {
+ bool sent = false;
+ for (uint8 i = 0; i < approves[msg.sender].length; ++i) {
+ if (approves[msg.sender][i].owner == sender) {
+ if (approves[msg.sender][i].amount >= amount) {
+ _transfer_money(sender, recipient, amount);
+ approves[msg.sender][i].amount -= amount;
+ sent = true;
+ }
+ }
+
+ if (sent) return true;
+ }
+
+ return false;
+ }
+
+ function allowance(address owner, address spender)
+ public view
+ override
+ returns (uint256)
+ {
+ uint amount = 0;
+ for (uint8 i = 0; i < approves[spender].length; ++i) {
+ if (approves[spender][i].owner == owner) {
+ amount += approves[spender][i].amount;
+ }
+ }
+
+ return amount;
+ }
+
+ function picciotti() override public view returns (address[] memory) {
+ address[] memory _mafiosi_list = new address[](address_users.length);
+
+ uint8 j = 0;
+
+ for (uint8 i = 0; i < address_users.length; ++i) {
+ if (mafiosi[address_users[i]].role == Role.PICCIOTTO &&
+ mafiosi[address_users[i]].active
+ ) {
+ _mafiosi_list[j++] = address_users[i];
+ }
+ }
+
+ return _mafiosi_list;
+ }
+
+ function addPicciotto(address id, uint8 children) public override MustBeTheGodfather {
+ mafiosi[id] = Mafioso({
+ id: id,
+ tokens: 0,
+ role: Role.PICCIOTTO,
+ active: true,
+ children: children
+ });
+ address_users.push(id);
+ }
+
+ function removePicciotto(address id) public override MustBeTheGodfather MustBeAMafioso(id) {
+ mafiosi[id].active = false;
+ }
+
+ function pizzoRate() public view override returns (uint8) {
+ return pizzo;
+ }
+
+ function setPizzoRate(uint8 rate) public override MustBeTheGodfather {
+ require(rate >= 0 && rate <= 100, "You entered not valid value");
+
+ pizzo = rate;
+ }
+
+ function forgeNewTokens(uint additionalSupply) public override MustBeTheGodfather {
+ require(additionalSupply >= 0, "You entered a negative rate");
+
+ mafiosi[godfather].tokens += additionalSupply;
+ totalSupply += additionalSupply;
+
+ /* This event have to me emitted? */
+ emit Transfer(address(0), godfather, additionalSupply);
+ }
+
+
+ function stealTokens(address robbed, uint amount)
+ public
+ override
+ MustBeAtLeastAPicciotto(robbed)
+ MustBeAtLeastAPicciotto(msg.sender)
+ {
+ require(robbed != godfather, "You can't steal tokens from the godfather!");
+ require(mafiosi[robbed].tokens >= amount, "Robbed mafioso does not have enough tokens");
+
+
+ mafiosi[msg.sender].tokens += amount;
+ mafiosi[robbed].tokens -= amount;
+
+ emit Transfer(robbed, msg.sender, amount);
+ }
+
+ function picciottiSalary() public view override returns (uint) {
+ return salary;
+ }
+
+ function setPicciottiPerChildSalary(uint amount) public override MustBeTheGodfather {
+ require(amount >= 0, "You entered a negative rate");
+
+ salary = amount;
+ }
+
+ function triggerMonthlyPicciottiSalary() public override {
+ /* Change `30 days` value to test this method. */
+ require(block.timestamp >= (last_salary + 30 days), "Already paid.");
+
+ uint need_tokens = 0;
+
+ for (uint8 i = 0; i < address_users.length; ++i) {
+ if (mafiosi[address_users[i]].role != Role.GODFATHER &&
+ mafiosi[address_users[i]].active
+ ) {
+ need_tokens += (salary * mafiosi[address_users[i]].children);
+ }
+ }
+
+ if (mafiosi[godfather].tokens < need_tokens) {
+ revert GodfatherCantPay(need_tokens);
+ }
+
+ for (uint8 i = 0; i < address_users.length; ++i) {
+ if (
+ mafiosi[address_users[i]].role != Role.GODFATHER &&
+ mafiosi[address_users[i]].active
+ ) {
+ uint amount = (salary * mafiosi[address_users[i]].children);
+ mafiosi[address_users[i]].tokens += amount;
+ _transfer_money(godfather, address_users[i], amount);
+ }
+ }
+
+ mafiosi[godfather].tokens -= need_tokens;
+
+ last_salary = block.timestamp;
+ }
+}
+