1
+ // npx ts-node --files ./scripts/DeployTokenizedBallot.ts TOKEN_CONTRACT TARGET_BLOCK_NUMBER PROPOSAL_NAMES
2
+
3
+ import { createPublicClient , http , createWalletClient , formatEther , toHex } from "viem" ;
4
+
5
+ import { privateKeyToAccount } from "viem/accounts" ;
6
+ import { sepolia } from "viem/chains" ;
7
+ import { abi , bytecode } from "../artifacts/contracts/TokenizedBallot.sol/TokenizedBallot.json" ;
8
+ import * as dotenv from "dotenv" ;
9
+ dotenv . config ( ) ;
10
+
11
+ const providerApiKey = process . env . ALCHEMY_API_KEY || "" ;
12
+ const deployerPrivateKey = process . env . PRIVATE_KEY || "" ;
13
+
14
+ function validateParameters ( parameters : string [ ] ) {
15
+ if ( ! parameters || parameters . length < 3 )
16
+ throw new Error ( "Parameters not provided" ) ;
17
+
18
+ const tokenAddress = parameters [ 0 ] as `0x${string } `;
19
+ if ( ! tokenAddress ) throw new Error ( "Token address not provided" ) ;
20
+ if ( ! / ^ 0 x [ a - f A - F 0 - 9 ] { 40 } $ / . test ( tokenAddress ) )
21
+ throw new Error ( "Invalid token address" ) ;
22
+
23
+ const targetBlockNumber = parameters [ 1 ] ;
24
+ if ( isNaN ( Number ( targetBlockNumber ) ) ) throw new Error ( "Invalid target block number" ) ;
25
+
26
+ const proposals = parameters . slice ( 2 ) ;
27
+ if ( ! proposals || proposals . length < 1 )
28
+ throw new Error ( "Proposals not provided" ) ;
29
+
30
+ return { tokenAddress, targetBlockNumber, proposals }
31
+ }
32
+
33
+ async function main ( ) {
34
+ console . log ( "\n" ) ;
35
+ const { tokenAddress, targetBlockNumber, proposals } = validateParameters ( process . argv . slice ( 2 ) ) ;
36
+
37
+ console . log ( `Deploying ballot with proposals: ${ proposals } ` ) ;
38
+ console . log ( "Confirm? (Y/n)" ) ;
39
+
40
+ const stdin = process . stdin ;
41
+ stdin . on ( "data" , async function ( d ) {
42
+ if ( d . toString ( ) . trim ( ) == "Y" ) {
43
+ const publicClient = createPublicClient ( {
44
+ chain : sepolia ,
45
+ transport : http ( `https://eth-sepolia.g.alchemy.com/v2/${ providerApiKey } ` ) ,
46
+ } ) ;
47
+ const blockNumber = await publicClient . getBlockNumber ( ) ;
48
+ console . log ( "Last block number:" , blockNumber ) ;
49
+
50
+ const account = privateKeyToAccount ( `0x${ deployerPrivateKey } ` ) ;
51
+ const deployer = createWalletClient ( {
52
+ account,
53
+ chain : sepolia ,
54
+ transport : http ( `https://eth-sepolia.g.alchemy.com/v2/${ providerApiKey } ` ) ,
55
+ } ) ;
56
+ console . log ( "Deployer address:" , deployer . account . address ) ;
57
+ const balance = await publicClient . getBalance ( {
58
+ address : deployer . account . address ,
59
+ } ) ;
60
+ console . log (
61
+ "Deployer balance:" ,
62
+ formatEther ( balance ) ,
63
+ deployer . chain . nativeCurrency . symbol
64
+ ) ;
65
+
66
+ console . log ( "\nDeploying Ballot contract" ) ;
67
+ const hash = await deployer . deployContract ( {
68
+ abi,
69
+ bytecode : bytecode as `0x${string } `,
70
+ args : [
71
+ proposals . map ( ( prop ) => toHex ( prop , { size : 32 } ) ) ,
72
+ tokenAddress ,
73
+ targetBlockNumber
74
+ ]
75
+ } ) ;
76
+ console . log ( "Transaction hash:" , hash ) ;
77
+ console . log ( "Waiting for confirmations..." ) ;
78
+ const receipt = await publicClient . waitForTransactionReceipt ( { hash } ) ;
79
+ const contractAddress = receipt . contractAddress ;
80
+ console . log ( "Ballot contract deployed to:" , contractAddress ) ;
81
+ } else {
82
+ console . log ( "Operation cancelled" ) ;
83
+ }
84
+ process . exit ( ) ;
85
+ } ) ;
86
+ }
87
+
88
+ main ( ) . catch ( ( error ) => {
89
+ console . error ( error ) ;
90
+ process . exitCode = 1 ;
91
+ } ) ;
0 commit comments