19
19
* - the _coreDisputeID: just use 0 for now.
20
20
**/
21
21
22
- import { createPublicClient , createWalletClient , http , Hex , decodeEventLog , Log , getContract } from "viem" ;
22
+ import { createPublicClient , createWalletClient , http , Hex , decodeEventLog , getContract } from "viem" ;
23
23
import { privateKeyToAccount } from "viem/accounts" ;
24
24
import { hardhat } from "viem/chains" ;
25
25
import { encrypt , decrypt , DECRYPTION_DELAY } from "./shutter" ;
26
- import dotenv from "dotenv" ;
27
26
import { abi as DisputeKitShutterPoCAbi } from "../deployments/localhost/DisputeKitShutterPoC.json" ;
28
-
29
- // Load environment variables
30
- dotenv . config ( ) ;
27
+ import crypto from "crypto" ;
31
28
32
29
// Constants
33
30
const SEPARATOR = "␟" ; // U+241F
34
31
35
- // Validate environment variables
36
- if ( ! process . env . PRIVATE_KEY ) throw new Error ( "PRIVATE_KEY environment variable is required" ) ;
37
-
38
- /**
39
- * Split a hex string into bytes32 chunks
40
- */
41
- function splitToBytes32 ( hex : string ) : Hex [ ] {
42
- // Remove 0x prefix if present
43
- const cleanHex = hex . startsWith ( "0x" ) ? hex . slice ( 2 ) : hex ;
44
-
45
- // Split into chunks of 64 characters (32 bytes)
46
- const chunks : Hex [ ] = [ ] ;
47
- for ( let i = 0 ; i < cleanHex . length ; i += 64 ) {
48
- const chunk = `0x${ cleanHex . slice ( i , i + 64 ) } ` as Hex ;
49
- chunks . push ( chunk ) ;
50
- }
51
-
52
- return chunks ;
53
- }
54
-
55
32
// Store encrypted votes for later decryption
56
33
interface EncryptedVote {
57
34
encryptedCommitment : string ;
58
35
identity : Hex ;
59
36
timestamp : number ;
60
37
voteId : bigint ;
38
+ salt : Hex ;
61
39
}
62
40
63
41
const encryptedVotes : EncryptedVote [ ] = [ ] ;
64
42
65
- // Initialize Viem clients
43
+ const PRIVATE_KEY = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" as const ;
44
+
45
+ const CONTRACT_ADDRESS = "0x5FbDB2315678afecb367f032d93F642f64180aa3" as const ;
46
+
47
+ const transport = http ( ) ;
66
48
const publicClient = createPublicClient ( {
67
49
chain : hardhat ,
68
- transport : http ( ) ,
50
+ transport,
69
51
} ) ;
70
52
71
- const PRIVATE_KEY = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" as Hex ;
72
- const CONTRACT_ADDRESS = "0x5FbDB2315678afecb367f032d93F642f64180aa3" as const ;
73
-
74
53
const account = privateKeyToAccount ( PRIVATE_KEY ) ;
75
54
const walletClient = createWalletClient ( {
76
55
account,
77
56
chain : hardhat ,
78
- transport : http ( ) ,
57
+ transport,
79
58
} ) ;
80
59
81
60
const disputeKit = getContract ( {
@@ -85,46 +64,57 @@ const disputeKit = getContract({
85
64
} ) ;
86
65
87
66
/**
88
- * Cast an encrypted commit for a vote
67
+ * Generate a random salt
89
68
*/
90
- export async function castCommit ( {
91
- disputeId,
92
- voteId,
69
+ function generateSalt ( ) : Hex {
70
+ return ( "0x" + crypto . randomBytes ( 32 ) . toString ( "hex" ) ) as Hex ;
71
+ }
72
+
73
+ /**
74
+ * Cast a commit on-chain
75
+ */
76
+ async function castCommit ( {
77
+ coreDisputeID,
78
+ voteIDs,
93
79
choice,
94
80
justification,
95
81
} : {
96
- disputeId : bigint ;
97
- voteId : bigint ;
82
+ coreDisputeID : bigint ;
83
+ voteIDs : bigint [ ] ;
98
84
choice : bigint ;
99
85
justification : string ;
100
86
} ) {
101
87
try {
102
88
// Create message with U+241F separator
103
- const message = `${ disputeId } ${ SEPARATOR } ${ voteId } ${ SEPARATOR } ${ choice } ${ SEPARATOR } ${ justification } ` ;
89
+ const message = `${ coreDisputeID } ${ SEPARATOR } ${ voteIDs [ 0 ] } ${ SEPARATOR } ${ choice } ${ SEPARATOR } ${ justification } ` ;
104
90
105
- // Encrypt the message
91
+ // Encrypt the message using shutter.ts
106
92
const { encryptedCommitment, identity } = await encrypt ( message ) ;
107
93
108
- // Split encrypted commitment into bytes32 chunks
109
- const commitmentChunks = splitToBytes32 ( encryptedCommitment ) ;
110
- console . log ( "Commitment chunks:" , commitmentChunks ) ;
94
+ // Generate salt and compute hash
95
+ const salt = generateSalt ( ) ;
96
+ const commitHash = await disputeKit . read . hashVote ( [ coreDisputeID , voteIDs [ 0 ] , choice , justification , salt ] ) ;
111
97
112
98
// Cast the commit on-chain
113
- const hash = await disputeKit . write . castCommit ( [ disputeId , [ voteId ] , encryptedCommitment as Hex , identity as Hex ] ) ;
99
+ const txHash = await disputeKit . write . castCommit ( [ coreDisputeID , voteIDs , commitHash , identity as Hex ] ) ;
100
+
101
+ // Wait for transaction to be mined
102
+ await publicClient . waitForTransactionReceipt ( { hash : txHash } ) ;
103
+
104
+ // Watch for CommitCast event
105
+ const events = await disputeKit . getEvents . CommitCast ( ) ;
106
+ console . log ( "CommitCast event:" , ( events [ 0 ] as any ) . args ) ;
114
107
115
108
// Store encrypted vote for later decryption
116
109
encryptedVotes . push ( {
117
110
encryptedCommitment,
118
111
identity : identity as Hex ,
119
112
timestamp : Math . floor ( Date . now ( ) / 1000 ) ,
120
- voteId,
113
+ voteId : voteIDs [ 0 ] ,
114
+ salt,
121
115
} ) ;
122
116
123
- // Watch for CommitCast event
124
- const events = await disputeKit . getEvents . CommitCast ( ) ;
125
- console . log ( "CommitCast event:" , ( events [ 0 ] as any ) . args ) ;
126
-
127
- return { encryptedCommitment, identity } ;
117
+ return { commitHash, identity, salt } ;
128
118
} catch ( error ) {
129
119
console . error ( "Error in castCommit:" , error ) ;
130
120
throw error ;
@@ -140,29 +130,28 @@ export async function autoVote() {
140
130
const currentTime = Math . floor ( Date . now ( ) / 1000 ) ;
141
131
142
132
// Find votes ready for decryption
143
- const readyVotes = encryptedVotes . filter ( ( vote ) => currentTime - vote . timestamp >= DECRYPTION_DELAY ) ;
144
- console . log ( "Ready votes:" , readyVotes ) ;
133
+ const readyVotes = encryptedVotes . filter ( ( vote ) => currentTime - vote . timestamp >= DECRYPTION_DELAY + 10 ) ;
145
134
146
135
for ( const vote of readyVotes ) {
147
136
try {
148
- console . log ( "Decrypting vote:" , vote ) ;
149
-
150
137
// Attempt to decrypt the vote
151
138
const decryptedMessage = await decrypt ( vote . encryptedCommitment , vote . identity ) ;
152
- console . log ( "Decrypted message:" , decryptedMessage ) ;
153
139
154
140
// Parse the decrypted message
155
- const [ , , choice , justification ] = decryptedMessage . split ( SEPARATOR ) ;
141
+ const [ coreDisputeID , , choice , justification ] = decryptedMessage . split ( SEPARATOR ) ;
156
142
157
143
// Cast the vote on-chain
158
- const hash = await disputeKit . write . castVote ( [
159
- BigInt ( 0 ) ,
144
+ const txHash = await disputeKit . write . castVote ( [
145
+ BigInt ( coreDisputeID ) ,
160
146
[ vote . voteId ] ,
161
147
BigInt ( choice ) ,
162
148
justification ,
163
- vote . identity ,
149
+ vote . salt ,
164
150
] ) ;
165
151
152
+ // Wait for transaction to be mined
153
+ await publicClient . waitForTransactionReceipt ( { hash : txHash } ) ;
154
+
166
155
// Watch for VoteCast event
167
156
const events = await disputeKit . getEvents . VoteCast ( ) ;
168
157
console . log ( "VoteCast event:" , ( events [ 0 ] as any ) . args ) ;
@@ -190,8 +179,8 @@ async function main() {
190
179
try {
191
180
// Cast an encrypted commit
192
181
await castCommit ( {
193
- disputeId : BigInt ( 0 ) ,
194
- voteId : BigInt ( 0 ) ,
182
+ coreDisputeID : BigInt ( 0 ) ,
183
+ voteIDs : [ BigInt ( 0 ) ] ,
195
184
choice : BigInt ( 2 ) ,
196
185
justification : "This is my vote justification" ,
197
186
} ) ;
0 commit comments