diff --git a/packages/foundry/script/DeployHelpers.s.sol b/packages/foundry/script/DeployHelpers.s.sol index 7338ac1..e2e9017 100644 --- a/packages/foundry/script/DeployHelpers.s.sol +++ b/packages/foundry/script/DeployHelpers.s.sol @@ -5,74 +5,72 @@ import "forge-std/Script.sol"; import "forge-std/Vm.sol"; contract ScaffoldETHDeploy is Script { - error InvalidChain(); + error InvalidChain(); - struct Deployment { - string name; - address addr; - } + struct Deployment { + string name; + address addr; + } - string root; - string path; - Deployment[] public deployments; + string root; + string path; + Deployment[] public deployments; - function setupLocalhostEnv() internal returns (uint256 localhostPrivateKey) { - if (block.chainid == 31337) { - root = vm.projectRoot(); - path = string.concat(root, "/localhost.json"); - string memory json = vm.readFile(path); - bytes memory mnemonicBytes = vm.parseJson(json, ".wallet.mnemonic"); - string memory mnemonic = abi.decode(mnemonicBytes, (string)); - return vm.deriveKey(mnemonic, 0); - } else { - return vm.envUint("DEPLOYER_PRIVATE_KEY"); + function setupLocalhostEnv() internal returns (uint256 localhostPrivateKey) { + if (block.chainid == 31337) { + root = vm.projectRoot(); + path = string.concat(root, "/localhost.json"); + string memory json = vm.readFile(path); + bytes memory mnemonicBytes = vm.parseJson(json, ".wallet.mnemonic"); + string memory mnemonic = abi.decode(mnemonicBytes, (string)); + return vm.deriveKey(mnemonic, 0); + } else { + return vm.envUint("DEPLOYER_PRIVATE_KEY"); + } } - } - function exportDeployments() internal { - // fetch already existing contracts - root = vm.projectRoot(); - path = string.concat(root, "/deployments/"); - string memory chainIdStr = vm.toString(block.chainid); - path = string.concat(path, string.concat(chainIdStr, ".json")); + function exportDeployments() internal { + // fetch already existing contracts + root = vm.projectRoot(); + path = string.concat(root, "/deployments/"); + string memory chainIdStr = vm.toString(block.chainid); + path = string.concat(path, string.concat(chainIdStr, ".json")); - string memory jsonWrite; + string memory jsonWrite; - uint256 len = deployments.length; + uint256 len = deployments.length; - for (uint256 i = 0; i < len; i++) { - vm.serializeString( - jsonWrite, vm.toString(deployments[i].addr), deployments[i].name - ); - } + for (uint256 i = 0; i < len; i++) { + vm.serializeString(jsonWrite, vm.toString(deployments[i].addr), deployments[i].name); + } - string memory chainName; + string memory chainName; - try this.getChain() returns (Chain memory chain) { - chainName = chain.name; - } catch { - chainName = findChainName(); + try this.getChain() returns (Chain memory chain) { + chainName = chain.name; + } catch { + chainName = findChainName(); + } + jsonWrite = vm.serializeString(jsonWrite, "networkName", chainName); + vm.writeJson(jsonWrite, path); } - jsonWrite = vm.serializeString(jsonWrite, "networkName", chainName); - vm.writeJson(jsonWrite, path); - } - function getChain() public returns (Chain memory) { - return getChain(block.chainid); - } + function getChain() public returns (Chain memory) { + return getChain(block.chainid); + } - function findChainName() public returns (string memory) { - uint256 thisChainId = block.chainid; - string[2][] memory allRpcUrls = vm.rpcUrls(); - for (uint256 i = 0; i < allRpcUrls.length; i++) { - try vm.createSelectFork(allRpcUrls[i][1]) { - if (block.chainid == thisChainId) { - return allRpcUrls[i][0]; + function findChainName() public returns (string memory) { + uint256 thisChainId = block.chainid; + string[2][] memory allRpcUrls = vm.rpcUrls(); + for (uint256 i = 0; i < allRpcUrls.length; i++) { + try vm.createSelectFork(allRpcUrls[i][1]) { + if (block.chainid == thisChainId) { + return allRpcUrls[i][0]; + } + } catch { + continue; + } } - } catch { - continue; - } + revert InvalidChain(); } - revert InvalidChain(); - } } diff --git a/packages/foundry/script/VerifyAll.s.sol b/packages/foundry/script/VerifyAll.s.sol index 75c6ab2..e8b88f8 100644 --- a/packages/foundry/script/VerifyAll.s.sol +++ b/packages/foundry/script/VerifyAll.s.sol @@ -11,129 +11,91 @@ import "solidity-bytes-utils/BytesLib.sol"; * @notice will be deleted once the forge/std is updated */ struct FfiResult { - int32 exit_code; - bytes stdout; - bytes stderr; + int32 exit_code; + bytes stdout; + bytes stderr; } interface tempVm { - function tryFfi( - string[] calldata - ) external returns (FfiResult memory); + function tryFfi(string[] calldata) external returns (FfiResult memory); } contract VerifyAll is Script { - uint96 currTransactionIdx; + uint96 currTransactionIdx; - function run() external { - string memory root = vm.projectRoot(); - string memory path = string.concat( - root, - "/broadcast/Deploy.s.sol/", - vm.toString(block.chainid), - "/run-latest.json" - ); - string memory content = vm.readFile(path); + function run() external { + string memory root = vm.projectRoot(); + string memory path = + string.concat(root, "/broadcast/Deploy.s.sol/", vm.toString(block.chainid), "/run-latest.json"); + string memory content = vm.readFile(path); - while (this.nextTransaction(content)) { - _verifyIfContractDeployment(content); - currTransactionIdx++; + while (this.nextTransaction(content)) { + _verifyIfContractDeployment(content); + currTransactionIdx++; + } } - } - function _verifyIfContractDeployment( - string memory content - ) internal { - string memory txType = abi.decode( - vm.parseJson(content, searchStr(currTransactionIdx, "transactionType")), - (string) - ); - if (keccak256(bytes(txType)) == keccak256(bytes("CREATE"))) { - _verifyContract(content); + function _verifyIfContractDeployment(string memory content) internal { + string memory txType = + abi.decode(vm.parseJson(content, searchStr(currTransactionIdx, "transactionType")), (string)); + if (keccak256(bytes(txType)) == keccak256(bytes("CREATE"))) { + _verifyContract(content); + } } - } - function _verifyContract( - string memory content - ) internal { - string memory contractName = abi.decode( - vm.parseJson(content, searchStr(currTransactionIdx, "contractName")), - (string) - ); - address contractAddr = abi.decode( - vm.parseJson(content, searchStr(currTransactionIdx, "contractAddress")), - (address) - ); - bytes memory deployedBytecode = abi.decode( - vm.parseJson(content, searchStr(currTransactionIdx, "transaction.data")), - (bytes) - ); - bytes memory compiledBytecode = abi.decode( - vm.parseJson(_getCompiledBytecode(contractName), ".bytecode.object"), - (bytes) - ); - bytes memory constructorArgs = BytesLib.slice( - deployedBytecode, - compiledBytecode.length, - deployedBytecode.length - compiledBytecode.length - ); + function _verifyContract(string memory content) internal { + string memory contractName = + abi.decode(vm.parseJson(content, searchStr(currTransactionIdx, "contractName")), (string)); + address contractAddr = + abi.decode(vm.parseJson(content, searchStr(currTransactionIdx, "contractAddress")), (address)); + bytes memory deployedBytecode = + abi.decode(vm.parseJson(content, searchStr(currTransactionIdx, "transaction.data")), (bytes)); + bytes memory compiledBytecode = + abi.decode(vm.parseJson(_getCompiledBytecode(contractName), ".bytecode.object"), (bytes)); + bytes memory constructorArgs = + BytesLib.slice(deployedBytecode, compiledBytecode.length, deployedBytecode.length - compiledBytecode.length); - string[] memory inputs = new string[](9); - inputs[0] = "forge"; - inputs[1] = "verify-contract"; - inputs[2] = vm.toString(contractAddr); - inputs[3] = contractName; - inputs[4] = "--chain"; - inputs[5] = vm.toString(block.chainid); - inputs[6] = "--constructor-args"; - inputs[7] = vm.toString(constructorArgs); - inputs[8] = "--watch"; + string[] memory inputs = new string[](9); + inputs[0] = "forge"; + inputs[1] = "verify-contract"; + inputs[2] = vm.toString(contractAddr); + inputs[3] = contractName; + inputs[4] = "--chain"; + inputs[5] = vm.toString(block.chainid); + inputs[6] = "--constructor-args"; + inputs[7] = vm.toString(constructorArgs); + inputs[8] = "--watch"; - FfiResult memory f = tempVm(address(vm)).tryFfi(inputs); + FfiResult memory f = tempVm(address(vm)).tryFfi(inputs); - if (f.stderr.length != 0) { - console.logString( - string.concat( - "Submitting verification for contract: ", vm.toString(contractAddr) - ) - ); - console.logString(string(f.stderr)); - } else { - console.logString(string(f.stdout)); + if (f.stderr.length != 0) { + console.logString(string.concat("Submitting verification for contract: ", vm.toString(contractAddr))); + console.logString(string(f.stderr)); + } else { + console.logString(string(f.stdout)); + } + return; } - return; - } - function nextTransaction( - string memory content - ) external view returns (bool) { - try this.getTransactionFromRaw(content, currTransactionIdx) { - return true; - } catch { - return false; + function nextTransaction(string memory content) external view returns (bool) { + try this.getTransactionFromRaw(content, currTransactionIdx) { + return true; + } catch { + return false; + } } - } - function _getCompiledBytecode( - string memory contractName - ) internal view returns (string memory compiledBytecode) { - string memory root = vm.projectRoot(); - string memory path = - string.concat(root, "/out/", contractName, ".sol/", contractName, ".json"); - compiledBytecode = vm.readFile(path); - } + function _getCompiledBytecode(string memory contractName) internal view returns (string memory compiledBytecode) { + string memory root = vm.projectRoot(); + string memory path = string.concat(root, "/out/", contractName, ".sol/", contractName, ".json"); + compiledBytecode = vm.readFile(path); + } - function getTransactionFromRaw( - string memory content, - uint96 idx - ) external pure { - abi.decode(vm.parseJson(content, searchStr(idx, "hash")), (bytes32)); - } + function getTransactionFromRaw(string memory content, uint96 idx) external pure { + abi.decode(vm.parseJson(content, searchStr(idx, "hash")), (bytes32)); + } - function searchStr( - uint96 idx, - string memory searchKey - ) internal pure returns (string memory) { - return string.concat(".transactions[", vm.toString(idx), "].", searchKey); - } + function searchStr(uint96 idx, string memory searchKey) internal pure returns (string memory) { + return string.concat(".transactions[", vm.toString(idx), "].", searchKey); + } } diff --git a/packages/nextjs/app/api/transactions/route.ts b/packages/nextjs/app/api/transactions/route.ts index ff4f444..177396e 100644 --- a/packages/nextjs/app/api/transactions/route.ts +++ b/packages/nextjs/app/api/transactions/route.ts @@ -1,28 +1,26 @@ +import { NextResponse } from "next/server"; import { TransactionType } from "~~/types/transaction"; let nextId = 0; let transactions: TransactionType[] = []; -export async function GET(request: Request) { - return Response.json(transactions) +export async function GET() { + return NextResponse.json(transactions); } export async function POST(request: Request) { - const body = await request.json(); - const newTx = body as TransactionType; - newTx.id = nextId; - transactions.push(newTx) - nextId++; - return Response.json(newTx); + const body = await request.json(); + const newTx = body as TransactionType; + newTx.id = nextId; + transactions.push(newTx); + nextId++; + return NextResponse.json(newTx); } export async function PUT(request: Request) { + const body = await request.json(); + const updatedTransaction = body as TransactionType; + transactions = transactions.map(tx => (tx.id === updatedTransaction.id ? { ...tx, ...updatedTransaction } : tx)); - const body = await request.json(); - const updatedTransaction = body as TransactionType; - transactions = transactions.map(tx => - tx.id === updatedTransaction.id ? { ...tx, ...updatedTransaction } : tx - ); - - return Response.json(updatedTransaction) + return NextResponse.json(updatedTransaction); } diff --git a/packages/nextjs/app/transactions/_components/Banner.tsx b/packages/nextjs/app/transactions/_components/Banner.tsx index 35a01a7..a747463 100644 --- a/packages/nextjs/app/transactions/_components/Banner.tsx +++ b/packages/nextjs/app/transactions/_components/Banner.tsx @@ -1,15 +1,16 @@ export const Banner = () => { - return ( - <> -
-

Transactions

-

- Select a type of transaction to create and wait for other signers to validate it. -
Then it will be executed automatically -

-
- - ) -} + return ( + <> +
+

Transactions

+

+ Select a type of transaction to create and wait for other signers to validate it. +
+ Then it will be executed automatically +

+
+ + ); +}; -export default Banner; \ No newline at end of file +export default Banner; diff --git a/packages/nextjs/app/transactions/_components/CreateTransaction.tsx b/packages/nextjs/app/transactions/_components/CreateTransaction.tsx index 0f3dd38..dbb5193 100644 --- a/packages/nextjs/app/transactions/_components/CreateTransaction.tsx +++ b/packages/nextjs/app/transactions/_components/CreateTransaction.tsx @@ -1,143 +1,144 @@ - -import type { NextPage } from "next"; import { useState } from "react"; +import type { NextPage } from "next"; +import { keccak256 } from "viem"; +import { useAccount, useWalletClient } from "wagmi"; import { AddressInput, InputBase, IntegerInput } from "~~/components/scaffold-eth"; import { useScaffoldContract, useScaffoldReadContract } from "~~/hooks/scaffold-eth"; import { useTransactionStore } from "~~/services/store/transactionStore"; -import { useAccount, useWalletClient } from 'wagmi'; import { Signature, TransactionType } from "~~/types/transaction"; -import { keccak256 } from 'viem'; export const CreateTransaction: NextPage = () => { - const METHODS = ["addSigner", "removeSigner", "transferFunds"]; - const transactionStore = useTransactionStore(); - - const { data: walletClient } = useWalletClient(); - - const { data: initialNonce } = useScaffoldReadContract({ - contractName: "MetaMultisigWallet", - functionName: "s_nonce" - }); - const { data: initialRequiredSigners } = useScaffoldReadContract({ - contractName: "MetaMultisigWallet", - functionName: "s_numRequiredSigners" + const METHODS = ["addSigner", "removeSigner", "transferFunds"]; + const transactionStore = useTransactionStore(); + + const { data: walletClient } = useWalletClient(); + + const { data: initialNonce } = useScaffoldReadContract({ + contractName: "MetaMultisigWallet", + functionName: "s_nonce", + }); + const { data: initialRequiredSigners } = useScaffoldReadContract({ + contractName: "MetaMultisigWallet", + functionName: "s_numRequiredSigners", + }); + + const [funcSelected, setFuncSelected] = useState("addSigner"); + const [ethValue, setEthValue] = useState(""); + const [newReqSigners, setNewReqSigners] = useState(0); + const [callData, setCallData] = useState(""); + const [signer, setSigner] = useState(""); + + const { data: multisigWalletContract } = useScaffoldContract({ + contractName: "MetaMultisigWallet", + }); + const { address: sender } = useAccount(); + if (sender == undefined) { + return; + } + + const handleCreate = async () => { + const newTx: TransactionType = { + id: 0, + function: funcSelected + "(address,uint256)", + to: signer as `0x${string}`, + amount: funcSelected == "addSigner" || funcSelected == "removeSigner" ? BigInt(0) : (ethValue as bigint), + requiredSigners: Number(initialRequiredSigners), + signatures: [], + executed: false, + }; + + const argument = funcSelected == "transferFunds" ? newTx.amount : BigInt(newTx.requiredSigners); + newTx.callData = (await multisigWalletContract?.read.getHash([newTx.function, newTx.to, argument])) as `0x{string}`; + setCallData(newTx.callData); + + const messageHash = keccak256(newTx.callData); + const sign: any = await walletClient?.signMessage({ + message: { raw: messageHash }, }); - - const [funcSelected, setFuncSelected] = useState("addSigner"); - const [ethValue, setEthValue] = useState(""); - const [newReqSigners, setNewReqSigners] = useState(0); - const [callData, setCallData] = useState(""); - const [signer, setSigner] = useState(""); - - const { data: multisigWalletContract } = useScaffoldContract({ - contractName: "MetaMultisigWallet" - }) - const { address: sender } = useAccount(); - if (sender == undefined) { - return; - } - - const handleCreate = async () => { - const newTx: TransactionType = { - id: 0, - function: funcSelected + "(address,uint256)", - to: signer as `0x${string}`, - amount: (funcSelected == "addSigner" || funcSelected == "removeSigner") ? BigInt(0) : ethValue as bigint, - requiredSigners: Number(initialRequiredSigners), - signatures: [], - executed: false - } - - const argument = (funcSelected == "transferFunds") ? newTx.amount : BigInt(newTx.requiredSigners); - newTx.callData = await multisigWalletContract?.read.getHash([newTx.function, newTx.to, argument]) as `0x{string}`; - setCallData(newTx.callData); - - const messageHash = keccak256(newTx.callData); - const sign: any = await walletClient?.signMessage({ - message: { raw: messageHash } - }); - const signatureObject: Signature = { - signature: sign, - address: sender - } - newTx.signatures.push(signatureObject); - - - transactionStore.addTransaction(newTx); - } - - return ( -
-
-
-
- - { - null; - }} - /> -
- -
-
- - -
- - setSigner(signer)} - /> - - {funcSelected === "transferFunds" && ( - { - setEthValue(val); - }} - /> - )} - - {funcSelected !== "transferFunds" && ( - { - setNewReqSigners(val) - }} - placeholder="Set new required signers" - /> - )} - - { - null; - }} - disabled - /> - - -
-
+ const signatureObject: Signature = { + signature: sign, + address: sender as `0x${string}`, + }; + newTx.signatures.push(signatureObject); + + transactionStore.addTransaction(newTx); + }; + + return ( +
+
+
+
+ + { + null; + }} + /> +
+ +
+
+ +
+ + setSigner(signer)} + /> + + {funcSelected === "transferFunds" && ( + { + setEthValue(val); + }} + /> + )} + + {funcSelected !== "transferFunds" && ( + { + setNewReqSigners(val); + }} + placeholder="Set new required signers" + /> + )} + + { + null; + }} + disabled + /> + + +
- ); -} +
+
+ ); +}; diff --git a/packages/nextjs/app/transactions/_components/TransactionRow.tsx b/packages/nextjs/app/transactions/_components/TransactionRow.tsx index 4dffc16..f23d82e 100644 --- a/packages/nextjs/app/transactions/_components/TransactionRow.tsx +++ b/packages/nextjs/app/transactions/_components/TransactionRow.tsx @@ -1,87 +1,95 @@ -import { Signature, TransactionType } from "~~/types/transaction"; +import { useAccount, useWalletClient } from "wagmi"; import { useScaffoldWriteContract } from "~~/hooks/scaffold-eth"; -import { useAccount, useWalletClient } from 'wagmi'; -import { useTransactionStore } from "~~/services/store/transactionStore"; import { useScaffoldReadContract } from "~~/hooks/scaffold-eth"; +import { useTransactionStore } from "~~/services/store/transactionStore"; +import { Signature, TransactionType } from "~~/types/transaction"; export const TransactionRow = ({ tx }: { tx: TransactionType }) => { - const { writeContractAsync: writeMetaMultisigAsync } = useScaffoldWriteContract("MetaMultisigWallet"); - const { data: walletClient } = useWalletClient(); - const { address: sender } = useAccount(); - if (sender == undefined) { - return; - } - - const { data: isOwner } = useScaffoldReadContract({ - contractName: "MetaMultisigWallet", - functionName: "isOwnerActive", - args: [sender], - }); - const updateTransaction = useTransactionStore(state => state.updateTransaction); - - const handleSign = async (tx: TransactionType) => { - const sign: any = await walletClient?.signMessage({ - message: { raw: tx.callData as `0x${string}` } - }); + const { writeContractAsync: writeMetaMultisigAsync } = useScaffoldWriteContract("MetaMultisigWallet"); + const { data: walletClient } = useWalletClient(); + let { address: sender } = useAccount(); + if (sender == undefined) { + sender = "0x0" as `0x${string}`; + } - const signatureObject: Signature = { - signature: sign, - address: sender - } + const { data: isOwner } = useScaffoldReadContract({ + contractName: "MetaMultisigWallet", + functionName: "isOwnerActive", + args: [sender], + }); + const updateTransaction = useTransactionStore(state => state.updateTransaction); - tx.signatures.push(signatureObject); - updateTransaction(tx.id, tx); + const handleSign = async (tx: TransactionType) => { + const sign: any = await walletClient?.signMessage({ + message: { raw: tx.callData as `0x${string}` }, + }); - } + const signatureObject: Signature = { + signature: sign, + address: sender as `0x${string}`, + }; - const handleExec = async (tx: TransactionType) => { - try { - await writeMetaMultisigAsync({ - functionName: "executeTransaction", - args: [tx.callData, tx.signatures.map(sig => sig.signature)], - }); - } catch (error) { - console.log(error) - } - } + tx.signatures.push(signatureObject); + updateTransaction(tx.id, tx); + }; - const hasAlreadySigned = (transaction: TransactionType, address: `0x${string}`): boolean => { - return transaction.signatures.some(signature => signature.address === address); + const handleExec = async (tx: TransactionType) => { + try { + await writeMetaMultisigAsync({ + functionName: "executeTransaction", + args: [tx.callData, tx.signatures.map(sig => sig.signature)], + }); + } catch (error) { + console.log(error); } - const amountToTransfer = (transaction: TransactionType) => { - if (transaction.function == "transferFunds(address,uint256)") { - - return Number(transaction.amount) / 1000000000000000000; - } + }; - return ""; + const hasAlreadySigned = (transaction: TransactionType, address: `0x${string}`): boolean => { + return transaction.signatures.some(signature => signature.address === address); + }; + const amountToTransfer = (transaction: TransactionType) => { + if (transaction.function == "transferFunds(address,uint256)") { + return Number(transaction.amount) / 1000000000000000000; } - return ( - - {tx.id} - {tx.function} {amountToTransfer(tx).toString()} ETH - {tx.signatures?.length || 0} / {tx.requiredSigners} - - {isOwner ? ( - <> - - - - ) : ( -

No rights 😶

- )} + return ""; + }; - - - ) -} + return ( + + {tx.id} + + {tx.function} {amountToTransfer(tx).toString()} ETH + + + {tx.signatures?.length || 0} / {tx.requiredSigners}{" "} + + + {isOwner ? ( + <> + + + + ) : ( +

No rights 😶

+ )} + + + ); +}; export default TransactionRow; diff --git a/packages/nextjs/app/transactions/_components/Transactions.tsx b/packages/nextjs/app/transactions/_components/Transactions.tsx index 9905aa3..17d704d 100644 --- a/packages/nextjs/app/transactions/_components/Transactions.tsx +++ b/packages/nextjs/app/transactions/_components/Transactions.tsx @@ -1,52 +1,50 @@ -import { type FC, useEffect, useState } from "react"; -import type { NextPage } from "next"; +import { useEffect } from "react"; import TransactionRow from "./TransactionRow"; +import type { NextPage } from "next"; import { useTransactionStore } from "~~/services/store/transactionStore"; export const TransactionsList: NextPage = () => { - const transactions = useTransactionStore((state) => state.transactions); - const fetchTransactions = useTransactionStore((state) => state.fetchTransactions); + const transactions = useTransactionStore(state => state.transactions); + const fetchTransactions = useTransactionStore(state => state.fetchTransactions); - useEffect(() => { - fetchTransactions(); - }, [fetchTransactions]); + useEffect(() => { + fetchTransactions(); + }, [fetchTransactions]); - return ( -
-
-
-
-
-
- {transactions?.length ? ( - - - - - - - - - - - - {transactions.map((tx) => ( - - ))} - -
- Current transactions -
ID.TYPESIGNERS
- ) : ( -
-

No transactions available

-
- )} -
-
-
-
+ return ( +
+
+
+
+
+
+ {transactions?.length ? ( + + + + + + + + + + + + {transactions.map(tx => ( + + ))} + +
Current transactions
ID.TYPESIGNERS
+ ) : ( +
+

No transactions available

+
+ )} +
+
- ) -} \ No newline at end of file +
+
+ ); +}; diff --git a/packages/nextjs/app/transactions/_components/index.tsx b/packages/nextjs/app/transactions/_components/index.tsx index 599d9ad..4d70332 100644 --- a/packages/nextjs/app/transactions/_components/index.tsx +++ b/packages/nextjs/app/transactions/_components/index.tsx @@ -1,3 +1,3 @@ export * from "./CreateTransaction"; export * from "./Transactions"; -export * from "./Banner"; \ No newline at end of file +export * from "./Banner"; diff --git a/packages/nextjs/app/transactions/page.tsx b/packages/nextjs/app/transactions/page.tsx index 1ec19f8..fb8f917 100644 --- a/packages/nextjs/app/transactions/page.tsx +++ b/packages/nextjs/app/transactions/page.tsx @@ -1,75 +1,69 @@ "use client"; -import { type FC, useEffect, useState } from "react"; +import { useEffect, useState } from "react"; +import { Banner, CreateTransaction, TransactionsList } from "./_components"; import type { NextPage } from "next"; -import { CreateTransaction, TransactionsList, Banner } from "./_components"; -import { AddressInput, EtherInput, InputBase } from "~~/components/scaffold-eth"; import { useScaffoldEventHistory } from "~~/hooks/scaffold-eth"; import { Signer } from "~~/types/transaction"; const Transactions: NextPage = () => { - const [signers, setSigners] = useState([]); - const { - data: events, - isLoading: isLoadingEvents, - error: errorReadingEvents, - } = useScaffoldEventHistory({ - contractName: "MetaMultisigWallet", - eventName: "SignerAdded", - fromBlock: 0n, - watch: true, - blockData: true, - }); + const [signers, setSigners] = useState([]); + const { data: events } = useScaffoldEventHistory({ + contractName: "MetaMultisigWallet", + eventName: "SignerAdded", + fromBlock: 0n, + watch: true, + blockData: true, + }); - useEffect(() => { - if (events) { - const newSigners: Signer[] = events.map(event => { - return { address: event.args.who } as Signer; - }); - setSigners(newSigners); - } - }, [events]); + useEffect(() => { + if (events) { + const newSigners: Signer[] = events.map(event => { + return { address: event.args.who } as Signer; + }); + setSigners(newSigners); + } + }, [events]); - - return ( - <> - -
-
-
-
-
-
-
- Owners: - {signers?.length ? ( -
    - {signers.map((signer, i) => ( -
  • {signer.address}
  • - ))} -
- ) : ( -
-

No signers available

-
- )} -
-
-
-
-
-
-
-
-
- -
-
- + return ( + <> + +
+
+
+
+
+
+
+ Owners: + {signers?.length ? ( +
    + {signers.map((signer, i) => ( +
  • {signer.address}
  • + ))} +
+ ) : ( +
+

No signers available

+
+ )} +
+
- - ); +
+
+
+
+
+ +
+
+ +
+
+ + ); }; export default Transactions; diff --git a/packages/nextjs/components/Footer.tsx b/packages/nextjs/components/Footer.tsx index a256e3f..0cf9ec3 100644 --- a/packages/nextjs/components/Footer.tsx +++ b/packages/nextjs/components/Footer.tsx @@ -4,7 +4,6 @@ import { hardhat } from "viem/chains"; import { CurrencyDollarIcon, MagnifyingGlassIcon } from "@heroicons/react/24/outline"; import { HeartIcon } from "@heroicons/react/24/outline"; import { SwitchTheme } from "~~/components/SwitchTheme"; -import { BuidlGuidlLogo } from "~~/components/assets/BuidlGuidlLogo"; import { Faucet } from "~~/components/scaffold-eth"; import { useTargetNetwork } from "~~/hooks/scaffold-eth/useTargetNetwork"; import { useGlobalState } from "~~/services/store/store"; @@ -47,7 +46,12 @@ export const Footer = () => {
    diff --git a/packages/nextjs/services/store/transactionStore.ts b/packages/nextjs/services/store/transactionStore.ts index 0f20501..dce43c8 100644 --- a/packages/nextjs/services/store/transactionStore.ts +++ b/packages/nextjs/services/store/transactionStore.ts @@ -1,65 +1,60 @@ -import { create } from 'zustand'; +import { create } from "zustand"; import { TransactionType } from "~~/types/transaction"; type TransactionState = { - nextId: number; - transactions: TransactionType[]; - fetchTransactions: () => Promise; - addTransaction: (transaction: TransactionType) => Promise; - updateTransaction: (id: number, updatedData: Partial) => Promise; + nextId: number; + transactions: TransactionType[]; + fetchTransactions: () => Promise; + addTransaction: (transaction: TransactionType) => Promise; + updateTransaction: (id: number, updatedData: Partial) => Promise; }; export const useTransactionStore = create((set, get) => ({ - transactions: [], - nextId: 1, + transactions: [], + nextId: 1, - fetchTransactions: async () => { - const response = await fetch('/api/transactions'); - const data: any[] = await response.json(); - const transactions = data.map((transaction) => ({ - ...transaction, - requiredSigners: transaction.requiredSigners, - })); - set({ transactions }); - }, + fetchTransactions: async () => { + const response = await fetch("/api/transactions"); + const data: any[] = await response.json(); + const transactions = data.map(transaction => ({ + ...transaction, + requiredSigners: transaction.requiredSigners, + })); + set({ transactions }); + }, - addTransaction: async (transaction: TransactionType) => { - const id = get().nextId; - const transactionWithId = { ...transaction, id }; - const response = await fetch('/api/transactions', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify( - transaction, - (key, value) => (typeof value === "bigint" ? value.toString() : value), - ), - }); - const newTransaction = await response.json(); - set((state) => ({ - transactions: [...state.transactions, newTransaction], - nextId: state.nextId + 1, - })); - }, + addTransaction: async (transaction: TransactionType) => { + const id = get().nextId; + const transactionWithId = { ...transaction, id }; + const response = await fetch("/api/transactions", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(transactionWithId, (key, value) => (typeof value === "bigint" ? value.toString() : value)), + }); + const newTransaction = await response.json(); + set(state => ({ + transactions: [...state.transactions, newTransaction], + nextId: state.nextId + 1, + })); + }, - updateTransaction: async (id: number, updatedData: Partial) => { - const response = await fetch(`/api/transactions`, { - method: 'PUT', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify( - updatedData, - // stringifying bigint - (key, value) => (typeof value === "bigint" ? value.toString() : value), - ), - }); - const updatedTransaction = await response.json(); - set((state) => ({ - transactions: state.transactions.map((transaction) => - transaction.id === id ? updatedTransaction : transaction - ), - })); - }, + updateTransaction: async (id: number, updatedData: Partial) => { + const response = await fetch(`/api/transactions`, { + method: "PUT", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify( + updatedData, + // stringifying bigint + (key, value) => (typeof value === "bigint" ? value.toString() : value), + ), + }); + const updatedTransaction = await response.json(); + set(state => ({ + transactions: state.transactions.map(transaction => (transaction.id === id ? updatedTransaction : transaction)), + })); + }, })); diff --git a/packages/nextjs/types/transaction.ts b/packages/nextjs/types/transaction.ts index 69f6fa2..75ba281 100644 --- a/packages/nextjs/types/transaction.ts +++ b/packages/nextjs/types/transaction.ts @@ -1,19 +1,19 @@ export type TransactionType = { - id: number, - function: string, - to: `0x${string}`, - amount: bigint, - callData?: `0x${string}`, - signatures: Signature[], - requiredSigners: number, - executed: boolean -} + id: number; + function: string; + to: `0x${string}`; + amount: bigint; + callData?: `0x${string}`; + signatures: Signature[]; + requiredSigners: number; + executed: boolean; +}; export type Signature = { - address: `0x${string}`, - signature: `0x${string}` -} + address?: `0x${string}`; + signature: `0x${string}`; +}; export type Signer = { - address: `0x${string}` -} + address: `0x${string}`; +};