@@ -32,6 +32,11 @@ class SpotTradeCircuit : public BaseTransactionCircuit
3232 DynamicBalanceGadget balanceA_O;
3333 DynamicBalanceGadget balanceB_O;
3434
35+ DynamicBalanceGadget vbalanceS_A;
36+ DynamicBalanceGadget vbalanceB_A;
37+ DynamicBalanceGadget vbalanceS_B;
38+ DynamicBalanceGadget vbalanceB_B;
39+
3540 // Order fills
3641 FloatGadget fillS_A;
3742 FloatGadget fillS_B;
@@ -59,6 +64,16 @@ class SpotTradeCircuit : public BaseTransactionCircuit
5964 TransferGadget protocolFeeA_from_balanceAO_to_balanceAP;
6065 TransferGadget protocolFeeB_from_balanceBO_to_balanceBP;
6166
67+ /* Virtual Token Transfers */
68+ TernaryGadget vfills_S_A;
69+ TernaryGadget vfills_B_A;
70+ TernaryGadget vfills_S_B;
71+ TernaryGadget vfills_B_B;
72+ SubGadget update_vbalanceS_A;
73+ AddGadget update_vbalanceB_A;
74+ SubGadget update_vbalanceS_B;
75+ AddGadget update_vbalanceB_B;
76+
6277 // AMM validation
6378 ValidateAMMGadget validateAMM;
6479
@@ -82,6 +97,12 @@ class SpotTradeCircuit : public BaseTransactionCircuit
8297 balanceA_O(pb, state.oper.balanceA, FMT(prefix, " .balanceA_O" )),
8398 balanceB_O(pb, state.oper.balanceB, FMT(prefix, " .balanceB_O" )),
8499
100+ // Virtual balances
101+ vbalanceS_A(pb, state.accountA.balanceS.weightAMM, FMT(prefix, " .vbalanceS_A" )),
102+ vbalanceB_A(pb, state.accountA.balanceB.weightAMM, FMT(prefix, " .vbalanceB_A" )),
103+ vbalanceS_B(pb, state.accountB.balanceS.weightAMM, FMT(prefix, " .vbalanceS_B" )),
104+ vbalanceB_B(pb, state.accountB.balanceB.weightAMM, FMT(prefix, " .vbalanceB_B" )),
105+
85106 // Order fills
86107 fillS_A(pb, state.constants, Float24Encoding, FMT(prefix, " .fillS_A" )),
87108 fillS_B(pb, state.constants, Float24Encoding, FMT(prefix, " .fillS_B" )),
@@ -175,28 +196,55 @@ class SpotTradeCircuit : public BaseTransactionCircuit
175196 feeCalculatorB.getProtocolFee(),
176197 FMT(prefix, " .protocolFeeB_from_balanceBO_to_balanceBP" )),
177198
199+ /* Virtual balance updates (for AMMs only) */
200+ vfills_S_A(pb, orderA.amm.packed, fillS_A.value(), state.constants._0, FMT(prefix, " .vfills_S_A" )),
201+ vfills_B_A(pb, orderA.amm.packed, fillS_B.value(), state.constants._0, FMT(prefix, " .vfills_B_A" )),
202+ vfills_S_B(pb, orderB.amm.packed, fillS_B.value(), state.constants._0, FMT(prefix, " .vfills_S_B" )),
203+ vfills_B_B(pb, orderB.amm.packed, fillS_A.value(), state.constants._0, FMT(prefix, " .vfills_B_B" )),
204+ update_vbalanceS_A(
205+ pb,
206+ state.accountA.balanceS.weightAMM,
207+ vfills_S_A.result(),
208+ NUM_BITS_AMOUNT,
209+ FMT(prefix, " .update_vbalanceS_A" )),
210+ update_vbalanceB_A(
211+ pb,
212+ state.accountA.balanceB.weightAMM,
213+ vfills_B_A.result(),
214+ NUM_BITS_AMOUNT,
215+ FMT(prefix, " .update_vbalanceB_A" )),
216+ update_vbalanceS_B(
217+ pb,
218+ state.accountB.balanceS.weightAMM,
219+ vfills_S_B.result(),
220+ NUM_BITS_AMOUNT,
221+ FMT(prefix, " .update_vbalanceS_B" )),
222+ update_vbalanceB_B(
223+ pb,
224+ state.accountB.balanceB.weightAMM,
225+ vfills_B_B.result(),
226+ NUM_BITS_AMOUNT,
227+ FMT(prefix, " .update_vbalanceB_B" )),
228+
178229 validateAMM(
179230 pb,
180231 state.constants,
232+ isSpotTradeTx.result(),
181233 {orderA.amm .packed ,
182234 orderA.feeBips .packed ,
183235 fillS_A.value (),
184- state.accountA .balanceS .balance ,
185- state.accountA .balanceB .balance ,
186- balanceS_A.balance (),
187- balanceB_A.balance (),
188236 state.accountA .balanceS .weightAMM ,
189237 state.accountA .balanceB .weightAMM ,
238+ update_vbalanceS_A.result (),
239+ update_vbalanceB_A.result (),
190240 state.accountA .account .feeBipsAMM },
191241 {orderB.amm .packed ,
192242 orderB.feeBips .packed ,
193243 fillS_B.value (),
194- state.accountB .balanceS .balance ,
195- state.accountB .balanceB .balance ,
196- balanceS_B.balance (),
197- balanceB_B.balance (),
198244 state.accountB .balanceS .weightAMM ,
199245 state.accountB .balanceB .weightAMM ,
246+ update_vbalanceS_B.result (),
247+ update_vbalanceB_B.result (),
200248 state.accountB .account .feeBipsAMM },
201249 FMT (prefix, " .validateAMM" ))
202250 {
@@ -210,6 +258,8 @@ class SpotTradeCircuit : public BaseTransactionCircuit
210258 setOutput (TXV_STORAGE_A_STORAGEID, orderA.storageID .packed );
211259 setOutput (TXV_BALANCE_A_S_BALANCE, balanceS_A.balance ());
212260 setOutput (TXV_BALANCE_A_B_BALANCE, balanceB_A.balance ());
261+ setOutput (TXV_BALANCE_A_S_WEIGHTAMM, update_vbalanceS_A.result ());
262+ setOutput (TXV_BALANCE_A_B_WEIGHTAMM, update_vbalanceB_A.result ());
213263 setArrayOutput (TXV_ACCOUNT_A_ADDRESS, orderA.accountID .bits );
214264
215265 // Update account B
@@ -218,6 +268,8 @@ class SpotTradeCircuit : public BaseTransactionCircuit
218268 setOutput (TXV_STORAGE_B_STORAGEID, orderB.storageID .packed );
219269 setOutput (TXV_BALANCE_B_S_BALANCE, balanceS_B.balance ());
220270 setOutput (TXV_BALANCE_B_B_BALANCE, balanceB_B.balance ());
271+ setOutput (TXV_BALANCE_B_S_WEIGHTAMM, update_vbalanceS_B.result ());
272+ setOutput (TXV_BALANCE_B_B_WEIGHTAMM, update_vbalanceB_B.result ());
221273 setArrayOutput (TXV_ACCOUNT_B_ADDRESS, orderB.accountID .bits );
222274
223275 // Update balances of the protocol fee pool
@@ -252,6 +304,12 @@ class SpotTradeCircuit : public BaseTransactionCircuit
252304 balanceA_O.generate_r1cs_witness ();
253305 balanceB_O.generate_r1cs_witness ();
254306
307+ // Virtual balances
308+ vbalanceS_A.generate_r1cs_witness ();
309+ vbalanceB_A.generate_r1cs_witness ();
310+ vbalanceS_B.generate_r1cs_witness ();
311+ vbalanceB_B.generate_r1cs_witness ();
312+
255313 // Order fills
256314 fillS_A.generate_r1cs_witness (spotTrade.fillS_A );
257315 fillS_B.generate_r1cs_witness (spotTrade.fillS_B );
@@ -279,6 +337,16 @@ class SpotTradeCircuit : public BaseTransactionCircuit
279337 protocolFeeA_from_balanceAO_to_balanceAP.generate_r1cs_witness ();
280338 protocolFeeB_from_balanceBO_to_balanceBP.generate_r1cs_witness ();
281339
340+ /* Virtual Token Transfers */
341+ vfills_S_A.generate_r1cs_witness ();
342+ vfills_B_A.generate_r1cs_witness ();
343+ vfills_S_B.generate_r1cs_witness ();
344+ vfills_B_B.generate_r1cs_witness ();
345+ update_vbalanceS_A.generate_r1cs_witness ();
346+ update_vbalanceB_A.generate_r1cs_witness ();
347+ update_vbalanceS_B.generate_r1cs_witness ();
348+ update_vbalanceB_B.generate_r1cs_witness ();
349+
282350 // AMM validation
283351 validateAMM.generate_r1cs_witness ();
284352 }
@@ -299,6 +367,12 @@ class SpotTradeCircuit : public BaseTransactionCircuit
299367 balanceA_O.generate_r1cs_constraints ();
300368 balanceB_O.generate_r1cs_constraints ();
301369
370+ // Virtual balances
371+ vbalanceS_A.generate_r1cs_constraints ();
372+ vbalanceB_A.generate_r1cs_constraints ();
373+ vbalanceS_B.generate_r1cs_constraints ();
374+ vbalanceB_B.generate_r1cs_constraints ();
375+
302376 // Order fills
303377 fillS_A.generate_r1cs_constraints ();
304378 fillS_B.generate_r1cs_constraints ();
@@ -326,6 +400,16 @@ class SpotTradeCircuit : public BaseTransactionCircuit
326400 protocolFeeA_from_balanceAO_to_balanceAP.generate_r1cs_constraints ();
327401 protocolFeeB_from_balanceBO_to_balanceBP.generate_r1cs_constraints ();
328402
403+ /* Virtual Token Transfers */
404+ vfills_S_A.generate_r1cs_constraints ();
405+ vfills_B_A.generate_r1cs_constraints ();
406+ vfills_S_B.generate_r1cs_constraints ();
407+ vfills_B_B.generate_r1cs_constraints ();
408+ update_vbalanceS_A.generate_r1cs_constraints ();
409+ update_vbalanceB_A.generate_r1cs_constraints ();
410+ update_vbalanceS_B.generate_r1cs_constraints ();
411+ update_vbalanceB_B.generate_r1cs_constraints ();
412+
329413 // AMM validation
330414 validateAMM.generate_r1cs_constraints ();
331415 }
0 commit comments