Skip to content

Instantly share code, notes, and snippets.

@Falilah
Created September 6, 2023 19:58
Show Gist options
  • Save Falilah/ce3c6010aac9f7fc962245b3b6aeaa8d to your computer and use it in GitHub Desktop.
Save Falilah/ce3c6010aac9f7fc962245b3b6aeaa8d to your computer and use it in GitHub Desktop.
import { ethers } from 'hardhat'
async function main() {
const currentTimestampInSeconds = Math.round(Date.now() / 1000)
const unlockTime = currentTimestampInSeconds + 60
const lockedAmount = ethers.parseEther('0.001')
const lock = await ethers.deployContract('Lock', [unlockTime], {
value: lockedAmount,
})
await lock.waitForDeployment()
console.log(
`Lock with ${ethers.formatEther(
lockedAmount
)}ETH and unlock timestamp ${unlockTime} deployed to ${lock.target}`
)
let [bal, time] = await lock.returnValues()
console.log(
` current Locked AMount:${ethers.formatEther(
bal
)}, The unlock Time is ${new Date(Number(time) * 1000)}`
)
}
// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main().catch((error) => {
console.error(error)
process.exitCode = 1
})
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.19;
// a multisig Wallet
// contract should accept ether
// array of signatories
// approving transaction
// mapping address to bool for valid Admins
//mapping uint => address => bool to track approval of each admin on each transaction
// transaction Detail
contract MultiSig {
struct Transaction {
address spender;
uint amount;
uint numberOfApproval;
bool isActive;
}
address[] Admins;
uint constant MINIMUM = 3;
uint transactionId;
mapping(address => bool) isAdmin;
mapping(uint => Transaction) transaction;
mapping(uint => mapping(address => bool)) hasApproved;
error InvalidAddress(uint position);
error InvalidAdminNumber(uint number);
error duplicate(address _addr);
event Create(address who, address spender, uint amount);
modifier onlyAdmin() {
require(isAdmin[msg.sender], "Not a Valid Admin");
_;
}
constructor(address[] memory _admins) payable {
if (_admins.length < MINIMUM) {
revert InvalidAdminNumber(MINIMUM);
}
for (uint i = 0; i < _admins.length; i++) {
if (_admins[i] == address(0)) {
revert InvalidAddress(i + 1);
}
if (isAdmin[_admins[i]]) {
revert duplicate(_admins[i]);
}
isAdmin[_admins[i]] = true;
}
Admins = _admins;
}
function createTransaction(
uint amount,
address _spender
) external onlyAdmin {
transactionId++;
Transaction storage _transaction = transaction[transactionId];
_transaction.amount = amount;
_transaction.spender = _spender;
_transaction.isActive = true;
emit Create(msg.sender, _spender, amount);
AprroveTransaction(transactionId);
}
function AprroveTransaction(uint id) public onlyAdmin {
//check if addmin has not approved yet;
require(!hasApproved[id][msg.sender], "Already Approved!!");
hasApproved[id][msg.sender] = true;
Transaction storage _transaction = transaction[id];
require(_transaction.isActive, "Not active");
_transaction.numberOfApproval += 1;
uint count = _transaction.numberOfApproval;
uint MinApp = calculateMinimumApproval();
if (count >= MinApp) {
sendtransaction(id);
}
}
function sendtransaction(uint id) internal {
Transaction storage _transaction = transaction[id];
payable(_transaction.spender).transfer(_transaction.amount);
_transaction.isActive = false;
}
function calculateMinimumApproval() public view returns (uint MinApp) {
uint size = Admins.length;
MinApp = (size * 70) / 100;
}
function getTransaction(
uint id
) external view returns (Transaction memory) {
return transaction[id];
}
receive() external payable {}
}
import { ethers } from 'hardhat'
async function main() {
const [Admin1, Admin2, Admin3, Admin4, Admin5, spender] =
await ethers.getSigners()
const Owners = [
Admin1.address,
Admin2.address,
Admin3.address,
Admin4.address,
Admin5.address,
]
const multisig = await ethers.deployContract('MultiSig', [Owners], {
value: ethers.parseEther('10'),
})
await multisig.waitForDeployment()
console.log(`Multisig deployed to ${multisig.target}`)
const amount = ethers.parseEther('5')
const receipt = await multisig.createTransaction(amount, spender.address)
const receipt2 = await multisig
.connect(Admin2)
.createTransaction(amount, spender.address)
const receipt3 = await multisig
.connect(Admin3)
.createTransaction(amount, spender.address)
const receipt4 = await multisig.createTransaction(amount, spender.address)
const receipt5 = await multisig.createTransaction(amount, spender.address)
//returns the event args
//@ts-ignore
console.log(await (await receipt.wait())?.logs[0]?.args)
await multisig.connect(Admin3).AprroveTransaction(1)
let balancebefore = await ethers.provider.getBalance(spender.address)
console.log(`balance before ${ethers.formatEther(balancebefore)}`)
await multisig.connect(Admin2).AprroveTransaction(1)
console.log(
`Spender Balance ${ethers.formatEther(
(await ethers.provider.getBalance(spender.address)) - balancebefore
)})`
)
let [add, _amount, approval, isActive] = await multisig.getTransaction(1)
console.log(
add,
ethers.formatEther(_amount),
parseInt(String(approval)),
isActive
)
}
// We recommend this pattern to be able to use async/await everywhere
// and properly handle errors.
main().catch((error) => {
console.error(error)
process.exitCode = 1
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment