1+ import { EasyPrivateVotingContractArtifact , EasyPrivateVotingContract } from "../artifacts/EasyPrivateVoting.js"
2+ import { AccountManager , AccountWallet , CompleteAddress , ContractDeployer , createLogger , Fr , PXE , waitForPXE , TxStatus , createPXEClient , getContractInstanceFromDeployParams , Logger } from "@aztec/aztec.js" ;
3+ import { getInitialTestAccountsWallets , generateSchnorrAccounts } from "@aztec/accounts/testing"
4+ import { getSchnorrAccount } from '@aztec/accounts/schnorr' ;
5+ import { spawn } from 'child_process' ;
6+ import { SponsoredFeePaymentMethod } from '../utils/sponsored_fee_payment_method.js' ;
7+ import { getFeeJuiceBalance , type L2AmountClaim , L1FeeJuicePortalManager , FeeJuicePaymentMethodWithClaim , AztecAddress } from "@aztec/aztec.js" ;
8+ import { createEthereumChain , createL1Clients } from '@aztec/ethereum' ;
9+
10+ const setupSandbox = async ( ) => {
11+ const { PXE_URL = 'http://localhost:8080' } = process . env ;
12+ const pxe = createPXEClient ( PXE_URL ) ;
13+ await waitForPXE ( pxe ) ;
14+ return pxe ;
15+ } ;
16+ const sleep = ( ms : number ) => new Promise ( resolve => setTimeout ( resolve , ms ) ) ;
17+
18+ describe ( "Accounts" , ( ) => {
19+ let pxe : PXE ;
20+ let wallets : AccountWallet [ ] = [ ] ;
21+ let accounts : CompleteAddress [ ] = [ ] ;
22+ let logger : Logger ;
23+ let sandboxInstance ;
24+ let sponsoredPaymentMethod : SponsoredFeePaymentMethod ;
25+
26+ let randomAccountManagers : AccountManager [ ] = [ ] ;
27+ let randomWallets : AccountWallet [ ] = [ ] ;
28+ let randomAddresses : AztecAddress [ ] = [ ] ;
29+
30+ let l1PortalManager : L1FeeJuicePortalManager ;
31+ let feeJuiceAddress : AztecAddress ;
32+ let skipSandbox : boolean ;
33+
34+ beforeAll ( async ( ) => {
35+ skipSandbox = process . env . SKIP_SANDBOX === 'true' ;
36+ if ( ! skipSandbox ) {
37+ sandboxInstance = spawn ( "aztec" , [ "start" , "--sandbox" ] , {
38+ detached : true ,
39+ stdio : 'ignore'
40+ } )
41+ await sleep ( 15000 ) ;
42+ }
43+
44+ logger = createLogger ( 'aztec:aztec-starter:accounts' ) ;
45+ logger . info ( "Aztec-Starter tests running." )
46+
47+ pxe = await setupSandbox ( ) ;
48+
49+ wallets = await getInitialTestAccountsWallets ( pxe ) ;
50+ accounts = wallets . map ( w => w . getCompleteAddress ( ) ) ;
51+ sponsoredPaymentMethod = await SponsoredFeePaymentMethod . new ( pxe ) ;
52+
53+ // generate random accounts
54+ randomAccountManagers = await Promise . all (
55+ ( await generateSchnorrAccounts ( 5 ) ) . map (
56+ a => getSchnorrAccount ( pxe , a . secret , a . signingKey , a . salt )
57+ )
58+ ) ;
59+ // get corresponding wallets
60+ randomWallets = await Promise . all ( randomAccountManagers . map ( am => am . getWallet ( ) ) ) ;
61+ // get corresponding addresses
62+ randomAddresses = await Promise . all ( randomWallets . map ( async w => ( await w . getCompleteAddress ( ) ) . address ) ) ;
63+
64+ // create default ethereum clients
65+ const nodeInfo = await pxe . getNodeInfo ( ) ;
66+ const chain = createEthereumChain ( [ 'http://localhost:8545' ] , nodeInfo . l1ChainId ) ;
67+ const DefaultMnemonic = 'test test test test test test test test test test test junk' ;
68+ const { publicClient, walletClient } = createL1Clients ( chain . rpcUrls , DefaultMnemonic , chain . chainInfo ) ;
69+
70+ feeJuiceAddress = nodeInfo . protocolContractAddresses . feeJuice ;
71+
72+ // create portal manager
73+ l1PortalManager = await L1FeeJuicePortalManager . new (
74+ pxe ,
75+ publicClient ,
76+ walletClient ,
77+ logger
78+ ) ;
79+
80+ } )
81+
82+ afterAll ( async ( ) => {
83+ if ( ! skipSandbox ) {
84+ sandboxInstance ! . kill ( 'SIGINT' ) ;
85+ }
86+ } )
87+
88+ it ( "Creates accounts with fee juice" , async ( ) => {
89+ // balance of each random account is 0 before bridge
90+ let balances = await Promise . all ( randomAddresses . map ( async a => getFeeJuiceBalance ( a , pxe ) ) ) ;
91+ balances . forEach ( b => expect ( b ) . toBe ( 0n ) ) ;
92+
93+
94+ // bridge funds to unfunded random addresses
95+ const claimAmount = 10n ** 22n ;
96+ const approxMaxDeployCost = 10n ** 10n ; // Need to manually update this if fees increase significantly
97+ let claims : L2AmountClaim [ ] = [ ] ;
98+ // bridge sequentially to avoid l1 txs (nonces) being processed out of order
99+ for ( let i = 0 ; i < randomAddresses . length ; i ++ ) {
100+ claims . push ( await l1PortalManager . bridgeTokensPublic ( randomAddresses [ i ] , claimAmount , true ) ) ;
101+ }
102+
103+ // arbitrary transactions to progress 2 blocks, and have fee juice on Aztec ready to claim
104+ await EasyPrivateVotingContract . deploy ( wallets [ 0 ] , accounts [ 0 ] ) . send ( ) . deployed ( ) ; // deploy contract with first funded wallet
105+ await EasyPrivateVotingContract . deploy ( wallets [ 0 ] , accounts [ 0 ] ) . send ( ) . deployed ( ) ; // deploy contract with first funded wallet
106+
107+ // claim and pay to deploy random accounts
108+ let sentTxs = [ ] ;
109+ for ( let i = 0 ; i < randomWallets . length ; i ++ ) {
110+ const paymentMethod = new FeeJuicePaymentMethodWithClaim ( randomWallets [ i ] , claims [ i ] ) ;
111+ sentTxs . push ( randomAccountManagers [ i ] . deploy ( { fee : { paymentMethod } } ) ) ;
112+ }
113+ await Promise . all ( sentTxs . map ( stx => stx . wait ( ) ) ) ;
114+
115+ // balance after deploy with claimed fee juice
116+ balances = await Promise . all ( randomAddresses . map ( async a => getFeeJuiceBalance ( a , pxe ) ) ) ;
117+ const amountAfterDeploy = claimAmount - approxMaxDeployCost ;
118+ balances . forEach ( b => expect ( b ) . toBeGreaterThanOrEqual ( amountAfterDeploy ) ) ;
119+
120+ } ) ;
121+
122+ it ( "Deploys first unfunded account from first funded account" , async ( ) => {
123+ const tx_acc = await randomAccountManagers [ 0 ] . deploy ( { deployWallet : wallets [ 0 ] } ) ;
124+ } ) ;
125+
126+ it ( "Sponsored contract deployment" , async ( ) => {
127+ const salt = Fr . random ( ) ;
128+ const VotingContractArtifact = EasyPrivateVotingContractArtifact
129+ // const [deployerWallet, adminWallet] = wallets; // using first account as deployer and second as contract admin
130+ const accounts = await Promise . all (
131+ ( await generateSchnorrAccounts ( 2 ) ) . map (
132+ async a => await getSchnorrAccount ( pxe , a . secret , a . signingKey , a . salt )
133+ )
134+ ) ;
135+ await Promise . all ( accounts . map ( a => a . deploy ( { fee : { paymentMethod : sponsoredPaymentMethod } } ) ) ) ;
136+ const daWallets = await Promise . all ( accounts . map ( a => a . getWallet ( ) ) ) ;
137+ const [ deployerWallet , adminWallet ] = daWallets ;
138+ const [ deployerAddress , adminAddress ] = daWallets . map ( w => w . getAddress ( ) ) ;
139+ // const adminAddress = adminWallet.getCompleteAddress().address;
140+
141+ const deploymentData = await getContractInstanceFromDeployParams ( VotingContractArtifact ,
142+ {
143+ constructorArgs : [ adminAddress ] ,
144+ salt,
145+ deployer : deployerWallet . getAddress ( )
146+ } ) ;
147+ const deployer = new ContractDeployer ( VotingContractArtifact , deployerWallet ) ;
148+ const tx = deployer . deploy ( adminAddress ) . send ( {
149+ contractAddressSalt : salt ,
150+ fee : { paymentMethod : sponsoredPaymentMethod } // without the sponsoredFPC the deployment fails, thus confirming it works
151+ } )
152+ const receipt = await tx . getReceipt ( ) ;
153+
154+ expect ( receipt ) . toEqual (
155+ expect . objectContaining ( {
156+ status : TxStatus . PENDING ,
157+ error : ''
158+ } ) ,
159+ ) ;
160+
161+ const receiptAfterMined = await tx . wait ( { wallet : deployerWallet } ) ;
162+ expect ( await pxe . getContractMetadata ( deploymentData . address ) ) . toBeDefined ( ) ;
163+ expect ( ( await pxe . getContractMetadata ( deploymentData . address ) ) . contractInstance ) . toBeTruthy ( ) ;
164+ expect ( receiptAfterMined ) . toEqual (
165+ expect . objectContaining ( {
166+ status : TxStatus . SUCCESS ,
167+ } ) ,
168+ ) ;
169+
170+ expect ( receiptAfterMined . contract . instance . address ) . toEqual ( deploymentData . address )
171+ } )
172+
173+ } ) ;
0 commit comments