@@ -8,17 +8,27 @@ import fs from 'fs';
88import path from 'path' ;
99import { SubscriptionFPC } from '@gregojuice/contracts/subscription-fpc' ;
1010import { FunctionSelector } from '@aztec/stdlib/abi' ;
11+ import { L1FeeJuicePortalManager } from '@aztec/aztec.js/ethereum' ;
12+ import { waitForL1ToL2MessageReady } from '@aztec/aztec.js/messaging' ;
13+ import { createExtendedL1Client } from '@aztec/ethereum/client' ;
14+ import { createLogger } from '@aztec/foundation/log' ;
15+ import { foundry } from 'viem/chains' ;
16+ import { Fr } from '@aztec/foundation/curves/bn254' ;
1117import { ProofOfPasswordContractArtifact } from '../contracts/target/ProofOfPassword.ts' ;
1218import { AMMContractArtifact } from '../contracts/target/AMM.ts' ;
19+ import { TokenContractArtifact } from '../contracts/target/Token.ts' ;
1320import { setupWallet , getOrCreateDeployer } from './utils.ts' ;
1421
22+ // Well-known Anvil account #0 — used to sign the L1 bridge transaction on local sandbox
23+ const ANVIL_KEY_0 = '0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80' ;
24+
1525async function main ( ) {
16- const { wallet, paymentMethod } = await setupWallet ( 'http://localhost:8080' , 'local' ) ;
26+ const { wallet, node , paymentMethod } = await setupWallet ( 'http://localhost:8080' , 'local' ) ;
1727 const deployer = await getOrCreateDeployer ( wallet , paymentMethod ) ;
1828
1929 console . log ( 'Deploying SubscriptionFPC...' ) ;
2030 const { deployment, secretKey } = await SubscriptionFPC . deployWithKeys ( wallet , deployer ) ;
21- const receipt = await deployment . send ( { fee : { paymentMethod } } ) ;
31+ const receipt = await deployment . send ( { from : deployer , fee : { paymentMethod } } ) ;
2232 const fpcAddress = receipt . contract . address . toString ( ) ;
2333 console . log ( 'SubscriptionFPC deployed at:' , fpcAddress ) ;
2434 console . log ( 'Secret key:' , secretKey . toString ( ) ) ;
@@ -30,6 +40,12 @@ async function main() {
3040 const ammFn = AMMContractArtifact . functions . find ( f => f . name === 'swap_tokens_for_exact_tokens_from' ) ;
3141 const ammSelector = await FunctionSelector . fromNameAndParameters ( ammFn ! . name , ammFn ! . parameters ) ;
3242
43+ const transferOffchainFn = TokenContractArtifact . functions . find ( f => f . name === 'transfer_offchain_from' ) ;
44+ const transferOffchainSelector = await FunctionSelector . fromNameAndParameters (
45+ transferOffchainFn ! . name ,
46+ transferOffchainFn ! . parameters ,
47+ ) ;
48+
3349 // Update local.json
3450 const configPath = path . join ( import . meta. dirname , '../src/config/networks/local.json' ) ;
3551 const config = JSON . parse ( fs . readFileSync ( configPath , 'utf-8' ) ) ;
@@ -44,11 +60,81 @@ async function main() {
4460 [ config . contracts . amm ] : {
4561 [ ammSelector . toString ( ) ] : 0 ,
4662 } ,
63+ [ config . contracts . gregoCoin ] : {
64+ [ transferOffchainSelector . toString ( ) ] : 0 ,
65+ } ,
66+ [ config . contracts . gregoCoinPremium ] : {
67+ [ transferOffchainSelector . toString ( ) ] : 0 ,
68+ } ,
4769 } ,
4870 } ;
4971
5072 fs . writeFileSync ( configPath , JSON . stringify ( config , null , 2 ) ) ;
5173 console . log ( `\nUpdated ${ configPath } with subscriptionFPC config.` ) ;
74+
75+ // Re-register the FPC contract with its secret key so PXE can compute tagging secrets
76+ const { SubscriptionFPCContractArtifact : fpcArtifact } = await import ( '@gregojuice/contracts/artifacts/SubscriptionFPC' ) ;
77+ const fpcInstance = await node . getContract ( receipt . contract . address ) ;
78+ if ( ! fpcInstance ) throw new Error ( 'FPC contract not found on-chain after deploy' ) ;
79+ await wallet . registerContract ( fpcInstance , fpcArtifact , secretKey ) ;
80+
81+ // Start the L1 bridge early so the message can propagate while we do sign_up on L2.
82+ // On local sandbox, the fee asset handler mints a fixed amount per call (1000 FJ).
83+ // When mint=true, bridgeTokensPublic must match this exact amount.
84+ const bridgeAmount : bigint = BigInt ( '1000000000000000000000' ) ; // 1000 FJ
85+
86+ console . log ( `\nBridging ${ bridgeAmount } wei of fee juice to FPC...` ) ;
87+ const l1Client = createExtendedL1Client ( [ 'http://localhost:8545' ] , ANVIL_KEY_0 , foundry ) ;
88+ const portalManager = await L1FeeJuicePortalManager . new ( node , l1Client , createLogger ( 'bridge' ) ) ;
89+ const claim = await portalManager . bridgeTokensPublic ( receipt . contract . address , bridgeAmount , true ) ;
90+ console . log ( 'L1 bridge tx mined.' ) ;
91+
92+ // Sign up functions so users can subscribe. These L2 txs also advance the L2 chain,
93+ // which helps the sequencer include the pending L1->L2 bridge message.
94+ const { SubscriptionFPCContract } = await import ( '@gregojuice/contracts/artifacts/SubscriptionFPC' ) ;
95+ const fpc = SubscriptionFPCContract . at ( receipt . contract . address , wallet ) ;
96+
97+ const maxUses = 100 ;
98+ const maxFee = BigInt ( '1000000000000000000000' ) ; // 1000 FJ
99+ const maxUsers = 100 ;
100+
101+ const popAddress = config . contracts . pop ;
102+ console . log ( `\nSigning up PoP selector ${ popSelector } at index 0...` ) ;
103+ await fpc . methods
104+ . sign_up ( popAddress , popSelector , 0 , maxUses , maxFee , maxUsers )
105+ . send ( { from : deployer , fee : { paymentMethod } } ) ;
106+ console . log ( 'PoP sign_up done!' ) ;
107+
108+ const ammAddress = config . contracts . amm ;
109+ console . log ( `Signing up AMM selector ${ ammSelector } at index 0...` ) ;
110+ await fpc . methods
111+ . sign_up ( ammAddress , ammSelector , 0 , maxUses , maxFee , maxUsers )
112+ . send ( { from : deployer , fee : { paymentMethod } } ) ;
113+ console . log ( 'AMM sign_up done!' ) ;
114+
115+ // Sign up transfer_offchain_from on both token contracts
116+ for ( const tokenKey of [ 'gregoCoin' , 'gregoCoinPremium' ] as const ) {
117+ const tokenAddress = config . contracts [ tokenKey ] ;
118+ console . log ( `Signing up ${ tokenKey } .transfer_offchain_from at index 0...` ) ;
119+ await fpc . methods
120+ . sign_up ( tokenAddress , transferOffchainSelector , 0 , maxUses , maxFee , maxUsers )
121+ . send ( { from : deployer , fee : { paymentMethod } } ) ;
122+ console . log ( `${ tokenKey } sign_up done!` ) ;
123+ }
124+
125+ // Wait for the L1->L2 bridge message and claim the FJ to credit the FPC's balance.
126+ console . log ( '\nWaiting for L1->L2 message sync...' ) ;
127+ const messageHash = Fr . fromHexString ( claim . messageHash ) ;
128+ await waitForL1ToL2MessageReady ( node , messageHash , { timeoutSeconds : 120 } ) ;
129+ console . log ( 'Message ready' ) ;
130+
131+ const { FeeJuiceContract } = await import ( '@aztec/aztec.js/protocol' ) ;
132+ const feeJuice = FeeJuiceContract . at ( wallet ) ;
133+ console . log ( 'Claiming fee juice on L2 for FPC...' ) ;
134+ await feeJuice . methods
135+ . claim ( receipt . contract . address , claim . claimAmount , claim . claimSecret , claim . messageLeafIndex )
136+ . send ( { from : deployer , fee : { paymentMethod } } ) ;
137+ console . log ( 'FPC funded!' ) ;
52138}
53139
54140main ( ) . catch ( err => {
0 commit comments