Last active
November 8, 2022 01:52
-
-
Save srinjoychakravarty/4399157896dad5ea100d8a7acf17090a to your computer and use it in GitHub Desktop.
intro to localhost cows comms
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// pragma experimental ABIEncoderV2; | |
// SPDX-License-Identifier: UNLICENSED | |
pragma solidity ^0.8.16; | |
import {VerifySignatureUtil as SigUtil} from "./VerifySignatureUtil.sol"; | |
import {VerifyUtil} from "./VerifyUtil.sol"; | |
import {KeyManagement} from "./KeyManagement.sol"; | |
import {GlobalState} from "./GlobalState.sol"; | |
import {CustodyWallet} from "./CustodyWallet.sol"; | |
import "forge-std/console.sol"; | |
contract COWSManagement { | |
using SigUtil for SigUtil.VerifiedSignature; | |
//*******************// | |
//****** ENUMS ******// | |
//*******************// | |
enum ActionType { | |
TerminateCOWS, | |
PauseCOWS, | |
UnpauseCOWS | |
} | |
enum Status { | |
Processing, | |
Approved, | |
Completed, | |
ForceClosed | |
} | |
enum AccountType { | |
Empty, | |
Omnibus, | |
Airdrop, | |
CustomerInvestigation, | |
Garbage | |
} | |
//*********************// | |
//****** STRUCTS ******// | |
//*********************// | |
struct ContractInfo { | |
int32 contractId; | |
address contractAddr; | |
} | |
struct COWSInfo { | |
string chain; | |
AccountType accountType; | |
mapping(string => ContractInfo) contracts; | |
} | |
struct RecognizeRecord { | |
SigUtil.VerifiedSignature adminSignature; | |
} | |
struct RequestUnit { | |
ActionType action; | |
bytes32 cowId; | |
} | |
struct RequestData { | |
bytes32 requestId; | |
address requester; | |
RequestUnit[] units; | |
SigUtil.VerifiedSignature[] signatures; | |
SigUtil.VerifiedSignature callerSignature; | |
uint256 expireAtBlock; | |
bool isPassed; | |
bool isExecuted; | |
Status status; | |
} | |
struct InitUnit { | |
bytes32 cowId; | |
string chain; | |
AccountType accountType; | |
address[] castlKeys; | |
} | |
//***********************// | |
//****** VARIABLES ******// | |
//***********************// | |
mapping(bytes32 => COWSInfo) public COWS; | |
mapping(bytes32 => RequestData) public cowsChangeRequests; | |
mapping(bytes32 => RecognizeRecord) public recognizeRecords; | |
//********************// | |
//****** EVENTS ******// | |
//********************// | |
event DeployNewCOWS(string msg, bool isSuccess); | |
event Recognize(string msg, bool isSuccess); | |
event RequestChanges(string msg, bool isSuccess); | |
event ApproveChanges(string msg, bytes32 failedRequestId, bool isSuccess); | |
event ExecuteChanges(string msg, bytes32 failedCowId, bool isSuccess); | |
event ForceClose(string msg, bool isSuccess); | |
event SpillContractAddrs( | |
address globalStateContractLocation, | |
address keyManagementContractLocation, | |
address custodyWalletContractLocation | |
); | |
//******************// | |
//****** VIEW ******// | |
//******************// | |
function returnContractAddress(bytes32 cowId, string memory _contract) | |
public | |
view | |
returns (address) | |
{ | |
ContractInfo memory _info = COWS[cowId].contracts[_contract]; | |
return _info.contractAddr; | |
} | |
function getAccountType(bytes32 cowId) public view returns (AccountType accountType) { | |
return COWS[cowId].accountType; | |
} | |
function getRecognizeRecord(bytes32 cowId) public view returns (RecognizeRecord memory record) { | |
return recognizeRecords[cowId]; | |
} | |
//*****************************// | |
//****** DEPLOY NEW COWS ******// | |
//*****************************// | |
function deployNewCOWS(InitUnit[] calldata cowsUnits) public returns (bool) { | |
for (uint256 i; i < cowsUnits.length; ) { | |
bytes32 _cowId = cowsUnits[i].cowId; | |
// Check if number of castl_keys > 1; if not, emit event DeployNewCOWS("Need at least 1 CASTL key when add a new COWS!", false) | |
if (cowsUnits[i].castlKeys.length < 1) { | |
emit DeployNewCOWS("Need at least 1 CASTL key when add a new COWS!", false); | |
revert("Need 1+ CASTLkeys for new COWS!"); | |
} | |
/* Deploy contracts, set init global state as Deployed and update info & activeStatus as Preparing for each COWS */ | |
// Deploy GlobalState contract | |
address _globalStateAddress; | |
try new GlobalState(GlobalState.COWSState.Deployed, address(this)) returns ( | |
GlobalState _address | |
) { | |
_globalStateAddress = address(_address); | |
} catch Error(string memory reason) { | |
emit DeployNewCOWS("Failed to deploy COWS!", false); | |
revert(string(abi.encodePacked("GLOBALSTATE: ", reason))); | |
} | |
COWSInfo storage _cowInfo = COWS[_cowId]; | |
_cowInfo.chain = cowsUnits[i].chain; | |
_cowInfo.accountType = cowsUnits[i].accountType; | |
{ | |
string memory _globalState = string("GlobalState"); | |
ContractInfo storage _stateContractInfo = _cowInfo.contracts[_globalState]; | |
_stateContractInfo.contractId = 0; | |
_stateContractInfo.contractAddr = _globalStateAddress; // deployed contract address | |
} | |
// Deploy KeyManagement contract | |
address _keyManagementAddress; | |
try | |
new KeyManagement(cowsUnits[i].castlKeys, _cowId, address(this), _globalStateAddress) | |
returns (KeyManagement _address) { | |
_keyManagementAddress = address(_address); | |
} catch Error(string memory reason) { | |
emit DeployNewCOWS("Failed to deploy COWS!", false); | |
revert(string(abi.encodePacked("KEYMANAGEMENT: ", reason))); | |
} | |
{ | |
string memory _keyContract = string("KeyManagement"); | |
ContractInfo storage _keyContractInfo = _cowInfo.contracts[_keyContract]; | |
_keyContractInfo.contractId = 1; | |
_keyContractInfo.contractAddr = _keyManagementAddress; // deployed contract address | |
} | |
// Deploy CustodyWallet contract | |
address _custodyWalletAddress; | |
try new CustodyWallet(_cowId, address(this), _globalStateAddress) returns ( | |
CustodyWallet _address | |
) { | |
_custodyWalletAddress = address(_address); | |
} catch Error(string memory reason) { | |
emit DeployNewCOWS("Failed to deploy COWS!", false); | |
revert(string(abi.encodePacked("CUSTODYWALLET: ", reason))); | |
} | |
{ | |
string memory _custodyWallet = string("CustodyWallet"); | |
ContractInfo storage _custodyContractInfo = _cowInfo.contracts[_custodyWallet]; | |
_custodyContractInfo.contractId = 2; | |
_custodyContractInfo.contractAddr = _custodyWalletAddress; // deployed contract address | |
} | |
// TODO: deploy all other contracts when they're made | |
unchecked { | |
++i; | |
} | |
emit SpillContractAddrs(_globalStateAddress, _keyManagementAddress, _custodyWalletAddress); | |
} | |
emit DeployNewCOWS("All deployed, preparing!", true); | |
return true; | |
} | |
//***********************// | |
//****** RECOGNIZE ******// | |
//***********************// | |
// This function is for confirming CASTL keys already recognized the contract deployment and intend to init it | |
function recognize(SigUtil.BaseSignature calldata adminSignature) public { | |
// Extract params from message in adminSignature | |
bytes32 cowsId; | |
address signerAddr; | |
{ | |
string[] memory _extractedMessage = SigUtil.extractMessage(adminSignature.message); | |
SigUtil.ExtractedSigningMessage memory message = SigUtil.convertToStruct(_extractedMessage); | |
cowsId = message.cowId; | |
signerAddr = message.signerPublicAddress; | |
} | |
// Check if the cowId is already existed in recognizeRecords | |
if (recognizeRecords[cowsId].adminSignature.recoveredSigner != address(0)) { | |
emit Recognize("COW is already recognized!", false); | |
revert("cow id existed"); | |
} | |
KeyManagement keyManagement; | |
{ | |
address _keyAddr = returnContractAddress(cowsId, string("KeyManagement")); | |
keyManagement = KeyManagement(_keyAddr); | |
} | |
// Check if caller has valid CASTL key; | |
// if not, emit event Recognize("Invalid CASTL key from caller!", false) | |
KeyManagement.CASTLState castlState = keyManagement.castlKeys(signerAddr); | |
if (castlState != KeyManagement.CASTLState.Enabled) { | |
emit Recognize("Invalid CASTL key from caller!", false); | |
revert("castl key not enabled"); | |
} | |
// Call verifySignature() to check if the recovered signer of caller signature match; | |
// if not, emit event Recognize("Invalid CASTL signature from caller!", false) | |
(bool isVerified, ) = VerifyUtil.verifySingleSignature(signerAddr, adminSignature); | |
if (!isVerified) { | |
emit Recognize("Invalid CASTL signature from caller!", false); | |
revert("invalid castl signature"); | |
} | |
// Update adminSignature to recognizeRecords | |
RecognizeRecord storage _recognizeRecords = recognizeRecords[cowsId]; | |
_recognizeRecords.adminSignature = SigUtil.VerifiedSignature({ | |
signature: adminSignature, | |
recoveredSigner: signerAddr, | |
isVerified: true | |
}); | |
// Update global state to Recognized | |
{ | |
address _keyAddr = returnContractAddress(cowsId, string("GlobalState")); | |
GlobalState globalState = GlobalState(_keyAddr); | |
globalState.setGlobalState(GlobalState.COWSState.Recognized); | |
} | |
// Emit event Recognize("All passed!", true) | |
emit Recognize("All passed!", true); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import hre from "hardhat"; | |
import { ContractFactory, Contract } from "ethers"; | |
async function deployRegistry() { | |
const registryContract: ContractFactory = await hre.ethers.getContractFactory("Registry"); | |
const registryContractInstance: Contract = await registryContract.deploy(); | |
return registryContractInstance; | |
} | |
async function deployVerifySigUtilLib() { | |
const verifySigUtilLibrary: ContractFactory = await hre.ethers.getContractFactory( | |
"VerifySignatureUtil", | |
); | |
const verifySigUtilLibInstance: Contract = await verifySigUtilLibrary.deploy(); | |
return verifySigUtilLibInstance; | |
} | |
async function deployVerifyUtilLib(verifySigUtilLibAddr: string) { | |
const verifyUtilLibrary: ContractFactory = await hre.ethers.getContractFactory("VerifyUtil", { | |
libraries: { | |
VerifySignatureUtil: verifySigUtilLibAddr, | |
}, | |
}); | |
const verifyUtilLibInstance: Contract = await verifyUtilLibrary.deploy(); | |
return verifyUtilLibInstance; | |
} | |
async function deployCowsMgmt(verifySigUtilLibAddr: string, verifyUtilLibAddr: string) { | |
const cowsMgmtContract: ContractFactory = await hre.ethers.getContractFactory("COWSManagement", { | |
libraries: { | |
VerifySignatureUtil: verifySigUtilLibAddr, | |
VerifyUtil: verifyUtilLibAddr, | |
}, | |
}); | |
const cowsMgmtContractInstance: Contract = await cowsMgmtContract.deploy(); | |
return cowsMgmtContractInstance; | |
} | |
async function main() { | |
const verifySigUtilLibInstance: Contract = await deployVerifySigUtilLib(); | |
const verifySigUtilLibAddr: string = verifySigUtilLibInstance.address; | |
console.log(`VerifySignatureUtil library deployed at: ${verifySigUtilLibAddr}`); //VerifySignatureUtil library deployed at: 0x5FbDB2315678afecb367f032d93F642f64180aa3 | |
const verifyUtilLibInstance: Contract = await deployVerifyUtilLib(verifySigUtilLibAddr); | |
const verifyUtilLibAddr: string = verifyUtilLibInstance.address; | |
console.log(`VerifyUtil library deployed at: ${verifyUtilLibAddr}`); //VerifyUtil library deployed at: 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 | |
const cowsMgmtContractInstance: Contract = await deployCowsMgmt( | |
verifySigUtilLibAddr, | |
verifyUtilLibAddr, | |
); | |
const cowsMgmtContractAddr: string = cowsMgmtContractInstance.address; | |
const registryContractInstance: Contract = await deployRegistry(); | |
const registryContractAddr: string = registryContractInstance.address; | |
console.log(`Registry contract deployed at: ${registryContractAddr}`); //Registry contract deployed to: 0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512 / 0xE451980132E65465d0a498c53f0b5227326Dd73F | |
console.log(`COWSManagement contract deployed at: ${cowsMgmtContractAddr}`); //COWSManagement contract deployed at: 0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0 | |
const cowId1 = "CowsCluster1"; | |
const cowId1Proto = "Ethereum"; | |
let knownCastlAddrs: string[] = ["0xFfB92A0e14BC8966358aEbe4C41026b2b6bd9fE7"]; | |
enum AccountType { | |
Empty = 0, | |
Omnibus = 1, | |
Airdrop = 2, | |
CustomerInvestigation = 3, | |
Garbage = 4, | |
} | |
type InitUnit = { | |
cowId: string; | |
chain: string; | |
accountType: AccountType; | |
castlKeys: string[]; | |
}; | |
const initUnits: [InitUnit] = [ | |
{ | |
cowId: hre.ethers.utils.formatBytes32String(cowId1), | |
chain: cowId1Proto, | |
accountType: AccountType.Omnibus, | |
castlKeys: knownCastlAddrs, | |
}, | |
]; | |
const deployNewCowsTxn = await cowsMgmtContractInstance.deployNewCOWS(initUnits); | |
const deployNewCowsTxnReceipt = await deployNewCowsTxn.wait(); | |
console.log(deployNewCowsTxnReceipt); | |
const etherDecimals = 18; | |
const deployNewCowsTxnGasUsed = hre.ethers.utils.formatUnits( | |
deployNewCowsTxnReceipt.gasUsed, | |
etherDecimals, | |
); | |
console.log(`deployNewCOWS Gas Usage: ${deployNewCowsTxnGasUsed}`); | |
const spillAddrsEvent = deployNewCowsTxnReceipt.events.find( | |
(event: any) => event.event === "SpillContractAddrs", | |
); | |
const spillAddrsEventArgs = spillAddrsEvent.args; | |
const globalStateContractAddr = spillAddrsEventArgs.globalStateContractLocation; | |
console.log(`GlobalState contract deployed at: ${globalStateContractAddr}`); //GlobalState contract deployed at: 0x75537828f2ce51be7289709686A69CbFDbB714F1 | |
const keyMgmtContractAddr = spillAddrsEventArgs.keyManagementContractLocation; | |
console.log(`KeyManagement contract deployed at: ${keyMgmtContractAddr}`); //KeyManagement contract deployed at: 0xE451980132E65465d0a498c53f0b5227326Dd73F | |
const CustodyWalletContractAddr = spillAddrsEventArgs.custodyWalletContractLocation; //CustodyWallet contract deployed at: 0x5392A33F7F677f59e833FEBF4016cDDD88fF9E67 | |
console.log(`CustodyWallet contract deployed at: ${CustodyWalletContractAddr}`); | |
} | |
main() | |
.then(() => process.exit(0)) | |
.catch((error) => { | |
console.error(error); | |
process.exit(1); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { task } from "hardhat/config"; | |
import "@nomiclabs/hardhat-waffle"; | |
import "hardhat-preprocessor"; | |
import fs from "fs"; | |
import dotenv from "dotenv"; | |
dotenv.config({ path: __dirname + "/.env" }); | |
const { | |
INFURA_PROJECT_ID, | |
METAMASK_PRIVATE_KEY, | |
ETHERNAL_EMAIL, | |
ETHERNAL_PASSWORD, | |
ETHERNAL_WORKSPACE, | |
} = process.env; | |
task("accounts", "Prints the list of accounts", async (taskArgs, hre) => { | |
const accounts = await hre.ethers.getSigners(); | |
for (const account of accounts) { | |
console.log(account.address); | |
} | |
}); | |
function getRemappings() { | |
return fs | |
.readFileSync("remappings.txt", "utf8") | |
.split("\n") | |
.filter(Boolean) // remove empty lines | |
.map((line) => line.trim().split("=")); | |
} | |
export default { | |
ethernal: { | |
email: ETHERNAL_EMAIL, | |
password: ETHERNAL_PASSWORD, | |
workspace: ETHERNAL_WORKSPACE, | |
uploadAst: true, | |
resetOnStart: ETHERNAL_WORKSPACE, | |
serverSync: true, | |
}, | |
solidity: { | |
compilers: [ | |
{ | |
version: "0.8.16", | |
}, | |
], | |
}, | |
preprocess: { | |
eachLine: (hre: any) => ({ | |
transform: (line: any) => { | |
if (line.match(/^\s*import /i)) { | |
getRemappings().forEach(([find, replace]) => { | |
if (line.match(find)) { | |
line = line.replace(find, replace); | |
} | |
}); | |
} | |
return line; | |
}, | |
}), | |
}, | |
paths: { | |
sources: "./src", | |
tests: "./test_hardhat", | |
cache: "./cache_hardhat", | |
}, | |
networks: { | |
ethernal: { | |
url: "http://prometh-cows.click:8545", | |
accounts: [`0x${METAMASK_PRIVATE_KEY}`], | |
}, | |
hardhat: { | |
chainId: 1337, | |
mining: { | |
auto: false, | |
interval: 1000, // mines 1 block every 1 millisecond | |
}, | |
allowUnlimitedContractSize: true, | |
}, | |
ropsten: { | |
url: `https://ropsten.infura.io/v3/${INFURA_PROJECT_ID}`, | |
accounts: [`0x${METAMASK_PRIVATE_KEY}`], | |
}, | |
rinkeby: { | |
url: `https://rinkeby.infura.io/v3/${INFURA_PROJECT_ID}`, | |
accounts: [`0x${METAMASK_PRIVATE_KEY}`], | |
}, | |
kovan: { | |
url: `https://kovan.infura.io/v3/${INFURA_PROJECT_ID}`, | |
accounts: [`0x${METAMASK_PRIVATE_KEY}`], | |
}, | |
}, | |
mocha: { | |
timeout: 100000000, | |
}, | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment