-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
create scripts for interacting with Tokenized Ballots
- Loading branch information
Showing
10 changed files
with
775 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
// npx ts-node --files ./scripts/CastVote.ts CONTRACT_ADDRESS PROPOSAL_INDEX AMOUNT | ||
|
||
import { createPublicClient, http, createWalletClient, hexToString } from "viem"; | ||
|
||
import { privateKeyToAccount } from "viem/accounts"; | ||
import { sepolia } from "viem/chains"; | ||
import { abi } from "../artifacts/contracts/TokenizedBallot.sol/TokenizedBallot.json"; | ||
import * as dotenv from "dotenv"; | ||
dotenv.config(); | ||
|
||
const providerApiKey = process.env.ALCHEMY_API_KEY || ""; | ||
const voterPrivateKey = process.env.PRIVATE_KEY || ""; | ||
|
||
function validateParameters(parameters: string[]) { | ||
if (!parameters || parameters.length < 3) | ||
throw new Error("Parameters not provided"); | ||
|
||
const contractAddress = parameters[0] as `0x${string}`; | ||
if (!contractAddress) throw new Error("Contract address not provided"); | ||
if (!/^0x[a-fA-F0-9]{40}$/.test(contractAddress)) | ||
throw new Error("Invalid contract address"); | ||
|
||
const proposalIndex = parameters[1]; | ||
if (isNaN(Number(proposalIndex))) throw new Error("Invalid proposal index"); | ||
|
||
const amount = parameters[2]; | ||
if (isNaN(Number(amount))) throw new Error("Invalid amount"); | ||
|
||
return { contractAddress, proposalIndex, amount }; | ||
} | ||
|
||
async function main() { | ||
console.log("\n"); | ||
const { contractAddress, proposalIndex, amount } = validateParameters(process.argv.slice(2)); | ||
|
||
const publicClient = createPublicClient({ | ||
chain: sepolia, | ||
transport: http(`https://eth-sepolia.g.alchemy.com/v2/${providerApiKey}`), | ||
}); | ||
|
||
const proposal = (await publicClient.readContract({ | ||
address: contractAddress, | ||
abi, | ||
functionName: "proposals", | ||
args: [BigInt(proposalIndex)], | ||
})) as any[]; | ||
const proposalName = hexToString(proposal[0], { size: 32 }); | ||
|
||
const account = privateKeyToAccount(`0x${voterPrivateKey}`); | ||
const sender = createWalletClient({ | ||
account, | ||
chain: sepolia, | ||
transport: http(`https://eth-sepolia.g.alchemy.com/v2/${providerApiKey}`), | ||
}); | ||
|
||
console.log(`Voting for proposal '${proposalName}' with ${amount} votes`); | ||
console.log("Confirm? (Y/n)"); | ||
|
||
const stdin = process.stdin; | ||
stdin.on("data", async function (d) { | ||
if (d.toString().trim() == "Y") { | ||
const hash = await sender.writeContract({ | ||
address: contractAddress, | ||
abi, | ||
functionName: "vote", | ||
args: [proposalIndex, amount], | ||
}); | ||
console.log("Transaction hash:", hash); | ||
console.log("Waiting for confirmations..."); | ||
const publicClient = createPublicClient({ | ||
chain: sepolia, | ||
transport: http(`https://eth-sepolia.g.alchemy.com/v2/${providerApiKey}`), | ||
}); | ||
const receipt = await publicClient.waitForTransactionReceipt({ hash }); | ||
console.log(`Transaction confirmed: ${receipt.status}`); | ||
} else { | ||
console.log("Operation cancelled"); | ||
} | ||
process.exit(); | ||
}); | ||
} | ||
|
||
main().catch((error) => { | ||
console.error(error); | ||
process.exitCode = 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// npx ts-node --files ./scripts/DelegateVotes.ts CONTRACT_ADDRESS DELEGATE_ADDRESS | ||
|
||
import { createPublicClient, http, createWalletClient } from "viem"; | ||
|
||
import { privateKeyToAccount } from "viem/accounts"; | ||
import { sepolia } from "viem/chains"; | ||
import { abi } from "../artifacts/contracts/MyToken.sol/MyToken.json"; | ||
import * as dotenv from "dotenv"; | ||
dotenv.config(); | ||
|
||
const providerApiKey = process.env.ALCHEMY_API_KEY || ""; | ||
const delegatorPrivateKey = process.env.PRIVATE_KEY || ""; | ||
|
||
function validateParameters(parameters: string[]) { | ||
if (!parameters || parameters.length < 2) | ||
throw new Error("Parameters not provided"); | ||
|
||
const contractAddress = parameters[0] as `0x${string}`; | ||
if (!contractAddress) throw new Error("Contract address not provided"); | ||
if (!/^0x[a-fA-F0-9]{40}$/.test(contractAddress)) | ||
throw new Error("Invalid contract address"); | ||
|
||
const delegateAddress = parameters[1] as `0x${string}`; | ||
if (!delegateAddress) throw new Error("Delegate address not provided"); | ||
if (!/^0x[a-fA-F0-9]{40}$/.test(delegateAddress)) | ||
throw new Error("Invalid delegate address"); | ||
|
||
return { contractAddress, delegateAddress } | ||
} | ||
|
||
async function main() { | ||
console.log("\n"); | ||
const { contractAddress, delegateAddress } = validateParameters(process.argv.slice(2)); | ||
|
||
const account = privateKeyToAccount(`0x${delegatorPrivateKey}`); | ||
const sender = createWalletClient({ | ||
account, | ||
chain: sepolia, | ||
transport: http(`https://eth-sepolia.g.alchemy.com/v2/${providerApiKey}`), | ||
}); | ||
|
||
console.log(`Delegating from ${account.address} tokens to account: ${delegateAddress}`); | ||
console.log("Confirm? (Y/n)"); | ||
|
||
const stdin = process.stdin; | ||
stdin.on("data", async function (d) { | ||
if (d.toString().trim() == "Y") { | ||
const hash = await sender.writeContract({ | ||
address: contractAddress, | ||
abi, | ||
functionName: "delegate", | ||
args: [delegateAddress], | ||
}); | ||
console.log("Transaction hash:", hash); | ||
console.log("Waiting for confirmations..."); | ||
const publicClient = createPublicClient({ | ||
chain: sepolia, | ||
transport: http(`https://eth-sepolia.g.alchemy.com/v2/${providerApiKey}`), | ||
}); | ||
const receipt = await publicClient.waitForTransactionReceipt({ hash }); | ||
console.log(`Transaction confirmed: ${receipt.status}`); | ||
console.log(`Block: ${receipt.blockNumber}`) | ||
} else { | ||
console.log("Operation cancelled"); | ||
} | ||
process.exit(); | ||
}); | ||
} | ||
|
||
main().catch((error) => { | ||
console.error(error); | ||
process.exitCode = 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// npx ts-node --files ./scripts/DeployMyToken.ts | ||
|
||
import { createPublicClient, http, createWalletClient, formatEther } from "viem"; | ||
|
||
import { privateKeyToAccount } from "viem/accounts"; | ||
import { sepolia } from "viem/chains"; | ||
import { abi, bytecode } from "../artifacts/contracts/MyToken.sol/MyToken.json"; | ||
import * as dotenv from "dotenv"; | ||
dotenv.config(); | ||
|
||
const providerApiKey = process.env.ALCHEMY_API_KEY || ""; | ||
const deployerPrivateKey = process.env.PRIVATE_KEY || ""; | ||
|
||
async function main() { | ||
const publicClient = createPublicClient({ | ||
chain: sepolia, | ||
transport: http(`https://eth-sepolia.g.alchemy.com/v2/${providerApiKey}`), | ||
}); | ||
const blockNumber = await publicClient.getBlockNumber(); | ||
console.log("Last block number:", blockNumber); | ||
|
||
const account = privateKeyToAccount(`0x${deployerPrivateKey}`); | ||
const deployer = createWalletClient({ | ||
account, | ||
chain: sepolia, | ||
transport: http(`https://eth-sepolia.g.alchemy.com/v2/${providerApiKey}`), | ||
}); | ||
console.log("Deployer address:", deployer.account.address); | ||
const balance = await publicClient.getBalance({ | ||
address: deployer.account.address, | ||
}); | ||
console.log( | ||
"Deployer balance:", | ||
formatEther(balance), | ||
deployer.chain.nativeCurrency.symbol | ||
); | ||
|
||
console.log("\nDeploying Token contract"); | ||
const hash = await deployer.deployContract({ | ||
abi, | ||
bytecode: bytecode as `0x${string}`, | ||
}); | ||
console.log("Transaction hash:", hash); | ||
console.log("Waiting for confirmations..."); | ||
const receipt = await publicClient.waitForTransactionReceipt({ hash }); | ||
const contractAddress = receipt.contractAddress; | ||
console.log("Token contract deployed to:", contractAddress); | ||
} | ||
|
||
main().catch((error) => { | ||
console.error(error); | ||
process.exitCode = 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
// npx ts-node --files ./scripts/DeployTokenizedBallot.ts TOKEN_CONTRACT TARGET_BLOCK_NUMBER PROPOSAL_NAMES | ||
|
||
import { createPublicClient, http, createWalletClient, formatEther, toHex } from "viem"; | ||
|
||
import { privateKeyToAccount } from "viem/accounts"; | ||
import { sepolia } from "viem/chains"; | ||
import { abi, bytecode } from "../artifacts/contracts/TokenizedBallot.sol/TokenizedBallot.json"; | ||
import * as dotenv from "dotenv"; | ||
dotenv.config(); | ||
|
||
const providerApiKey = process.env.ALCHEMY_API_KEY || ""; | ||
const deployerPrivateKey = process.env.PRIVATE_KEY || ""; | ||
|
||
function validateParameters(parameters: string[]) { | ||
if (!parameters || parameters.length < 3) | ||
throw new Error("Parameters not provided"); | ||
|
||
const tokenAddress = parameters[0] as `0x${string}`; | ||
if (!tokenAddress) throw new Error("Token address not provided"); | ||
if (!/^0x[a-fA-F0-9]{40}$/.test(tokenAddress)) | ||
throw new Error("Invalid token address"); | ||
|
||
const targetBlockNumber = parameters[1]; | ||
if (isNaN(Number(targetBlockNumber))) throw new Error("Invalid target block number"); | ||
|
||
const proposals = parameters.slice(2); | ||
if (!proposals || proposals.length < 1) | ||
throw new Error("Proposals not provided"); | ||
|
||
return { tokenAddress, targetBlockNumber, proposals } | ||
} | ||
|
||
async function main() { | ||
console.log("\n"); | ||
const { tokenAddress, targetBlockNumber, proposals } = validateParameters(process.argv.slice(2)); | ||
|
||
console.log(`Deploying ballot with proposals: ${proposals}`); | ||
console.log("Confirm? (Y/n)"); | ||
|
||
const stdin = process.stdin; | ||
stdin.on("data", async function (d) { | ||
if (d.toString().trim() == "Y") { | ||
const publicClient = createPublicClient({ | ||
chain: sepolia, | ||
transport: http(`https://eth-sepolia.g.alchemy.com/v2/${providerApiKey}`), | ||
}); | ||
const blockNumber = await publicClient.getBlockNumber(); | ||
console.log("Last block number:", blockNumber); | ||
|
||
const account = privateKeyToAccount(`0x${deployerPrivateKey}`); | ||
const deployer = createWalletClient({ | ||
account, | ||
chain: sepolia, | ||
transport: http(`https://eth-sepolia.g.alchemy.com/v2/${providerApiKey}`), | ||
}); | ||
console.log("Deployer address:", deployer.account.address); | ||
const balance = await publicClient.getBalance({ | ||
address: deployer.account.address, | ||
}); | ||
console.log( | ||
"Deployer balance:", | ||
formatEther(balance), | ||
deployer.chain.nativeCurrency.symbol | ||
); | ||
|
||
console.log("\nDeploying Ballot contract"); | ||
const hash = await deployer.deployContract({ | ||
abi, | ||
bytecode: bytecode as `0x${string}`, | ||
args: [ | ||
proposals.map((prop) => toHex(prop, { size: 32 })), | ||
tokenAddress, | ||
targetBlockNumber | ||
] | ||
}); | ||
console.log("Transaction hash:", hash); | ||
console.log("Waiting for confirmations..."); | ||
const receipt = await publicClient.waitForTransactionReceipt({ hash }); | ||
const contractAddress = receipt.contractAddress; | ||
console.log("Ballot contract deployed to:", contractAddress); | ||
} else { | ||
console.log("Operation cancelled"); | ||
} | ||
process.exit(); | ||
}); | ||
} | ||
|
||
main().catch((error) => { | ||
console.error(error); | ||
process.exitCode = 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
// npx ts-node --files ./scripts/GrantMinterRole.ts TOKEN_ADDRESS MINTER_ADDRESS | ||
|
||
import { createPublicClient, http, createWalletClient, keccak256, toHex } from "viem"; | ||
|
||
import { privateKeyToAccount } from "viem/accounts"; | ||
import { sepolia } from "viem/chains"; | ||
import { abi } from "../artifacts/contracts/MyToken.sol/MyToken.json"; | ||
import * as dotenv from "dotenv"; | ||
dotenv.config(); | ||
|
||
const providerApiKey = process.env.ALCHEMY_API_KEY || ""; | ||
const delegatorPrivateKey = process.env.PRIVATE_KEY || ""; | ||
|
||
const MINTER_ROLE = keccak256(toHex("MINTER_ROLE"));; | ||
|
||
function validateParameters(parameters: string[]) { | ||
if (!parameters || parameters.length < 2) | ||
throw new Error("Parameters not provided"); | ||
|
||
const tokenAddress = parameters[0] as `0x${string}`; | ||
if (!tokenAddress) throw new Error("Token address not provided"); | ||
if (!/^0x[a-fA-F0-9]{40}$/.test(tokenAddress)) | ||
throw new Error("Invalid token address"); | ||
|
||
const minterAddress = parameters[1] as `0x${string}`; | ||
if (!minterAddress) throw new Error("Minter address not provided"); | ||
if (!/^0x[a-fA-F0-9]{40}$/.test(minterAddress)) | ||
throw new Error("Invalid minter address"); | ||
|
||
return { tokenAddress, minterAddress } | ||
} | ||
|
||
async function main() { | ||
console.log("\n"); | ||
const { tokenAddress, minterAddress } = validateParameters(process.argv.slice(2)); | ||
|
||
const account = privateKeyToAccount(`0x${delegatorPrivateKey}`); | ||
const sender = createWalletClient({ | ||
account, | ||
chain: sepolia, | ||
transport: http(`https://eth-sepolia.g.alchemy.com/v2/${providerApiKey}`), | ||
}); | ||
|
||
console.log(`Granting minter role to ${minterAddress}`); | ||
console.log("Confirm? (Y/n)"); | ||
|
||
const stdin = process.stdin; | ||
stdin.on("data", async function (d) { | ||
if (d.toString().trim() == "Y") { | ||
const hash = await sender.writeContract({ | ||
address: tokenAddress, | ||
abi, | ||
functionName: "grantRole", | ||
args: [MINTER_ROLE, minterAddress], | ||
}); | ||
console.log("Transaction hash:", hash); | ||
console.log("Waiting for confirmations..."); | ||
const publicClient = createPublicClient({ | ||
chain: sepolia, | ||
transport: http(`https://eth-sepolia.g.alchemy.com/v2/${providerApiKey}`), | ||
}); | ||
const receipt = await publicClient.waitForTransactionReceipt({ hash }); | ||
console.log(`Transaction confirmed: ${receipt.status}`); | ||
console.log(`Block: ${receipt.blockNumber}`) | ||
} else { | ||
console.log("Operation cancelled"); | ||
} | ||
process.exit(); | ||
}); | ||
} | ||
|
||
main().catch((error) => { | ||
console.error(error); | ||
process.exitCode = 1; | ||
}); |
Oops, something went wrong.