diff --git a/packages/foundry/broadcast/Deploy.s.sol/84532/run-1733586991.json b/packages/foundry/broadcast/Deploy.s.sol/84532/run-1733586991.json new file mode 100644 index 0000000..f7d849e --- /dev/null +++ b/packages/foundry/broadcast/Deploy.s.sol/84532/run-1733586991.json @@ -0,0 +1,53 @@ +{ + "transactions": [ + { + "hash": "0xe8291b013f1757fe85b50f0f74722021e896d96538ac7611c47f9258644e4d0e", + "transactionType": "CREATE2", + "contractName": null, + "contractAddress": "0x9695d17226aa0e8c68103f77a7e8c9bf0e6852e3", + "function": null, + "arguments": null, + "transaction": { + "from": "0xdef013e1c10cc2b4baa652f60b7c7c9f833075d0", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "gas": "0x363f7", + "value": "0x0", + "input": "0x66cfa0570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000123400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000001ab5610160604052346101265760405161001860408261012b565b600681526020810190651692d4985a5b60d21b82526040519161003c60408461012b565b600183526020830191603160f81b835261005581610164565b6101205261006284610326565b61014052519020918260e05251902080610100524660a0526040519060208201927f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8452604083015260608201524660808201523060a082015260a081526100cb60c08261012b565b5190206080523060c0526040516115f090816104c58239608051816111fa015260a051816112b7015260c051816111c4015260e051816112490152610100518161126f01526101205181610bb201526101405181610bdb0152f35b600080fd5b601f909101601f19168101906001600160401b0382119082101761014e57604052565b634e487b7160e01b600052604160045260246000fd5b908151602081106000146101fc575090601f8151116101a0576020815191015160208210610190571790565b6000198260200360031b1b161790565b6040519063305a27a960e01b8252602060048301528181519182602483015260005b8381106101e45750508160006044809484010152601f80199101168101030190fd5b602082820181015160448784010152859350016101c2565b6001600160401b03811161014e57600054600181811c9116801561031c575b602082101461030657601f81116102d1575b50602092601f821160011461026d5792819293600092610262575b50508160011b916000199060031b1c19161760005560ff90565b015190503880610248565b601f1982169360008052806000209160005b8681106102b957508360019596106102a0575b505050811b0160005560ff90565b015160001960f88460031b161c19169055388080610292565b9192602060018192868501518155019401920161027f565b60008052601f6020600020910160051c810190601f830160051c015b8181106102fa575061022d565b600081556001016102ed565b634e487b7160e01b600052602260045260246000fd5b90607f169061021b565b908151602081106000146103ae575090601f815111610352576020815191015160208210610190571790565b6040519063305a27a960e01b8252602060048301528181519182602483015260005b8381106103965750508160006044809484010152601f80199101168101030190fd5b60208282018101516044878401015285935001610374565b6001600160401b03811161014e57600154600181811c911680156104ba575b602082101461030657601f8111610484575b50602092601f821160011461041f5792819293600092610414575b50508160011b916000199060031b1c19161760015560ff90565b0151905038806103fa565b601f198216936001600052806000209160005b86811061046c5750836001959610610453575b505050811b0160015560ff90565b015160001960f88460031b161c19169055388080610445565b91926020600181928685015181550194019201610432565b6001600052601f6020600020910160051c810190601f830160051c015b8181106104ae57506103df565b600081556001016104a1565b90607f16906103cd56fe6080604052600436101561001257600080fd5b60003560e01c80630254f39214610dec5780632a7559ad14610cdd5780633644e51514610cc25780635afb31c814610c9657806384b0196e14610b995780638ed0e37d14610b5e578063987757dd14610aa2578063b4257b9a146108df578063d8da5b2b146108b9578063d8ef508d146107545763f8af14d11461009557600080fd5b3461074f57604036600319011261074f5760043567ffffffffffffffff811161074f57610120600319823603011261074f5760243567ffffffffffffffff811161074f576100e7903690600401610e5e565b91906001600160a01b036100fe61010484016110ab565b16330361071d578160040135600052600460205260406000205461070c5761025d9261024e61025492604261014361013c60248801886004016110bf565b36916112dd565b6020815191012061015d61013c60448901896004016110bf565b60208151910120610170608489016110ab565b61017c60c48a016110ab565b6101896101048b016110ab565b916040519360208501957f93ff08ae199cf6417984a0da02ae95c00ebb8ec23824cf2ed480560e3c5f051387528c6004013560408701526060860152608085015260648b013560a085015260018060a01b031660c084015260a48a013560e084015260018060a01b031661010083015260e489013561012083015260018060a01b0316610140820152610140815261022361016082610fb2565b51902061022e6111c1565b906040519161190160f01b835260028301526022820152209236916112dd565b9061146d565b909391936114a9565b6001600160a01b038216156106fb576004810135600090815260056020526040902080546001600160a01b0319166001600160a01b0384161790556102c66102a860a4830135611091565b6001600160a01b036102bc608485016110ab565b1630903390611324565b6102ea60e482013530846001600160a01b036102e460c487016110ab565b16611324565b806004013560005260026020526040600020816004013581556001810161031760248401846004016110bf565b9067ffffffffffffffff82116106215781906103338454610fd4565b601f81116106a8575b50600090601f831160011461064257600092610637575b50508160011b916000199060031b1c19161790555b61037860448301836004016110bf565b9067ffffffffffffffff82116106215781906103976002850154610fd4565b601f81116105ce575b50600090601f831160011461056257600092610557575b50508160011b916000199060031b1c19161760028201555b606482013560038201556103e5608483016110ab565b6004820180546001600160a01b0319166001600160a01b0390921691909117905560a4820135600582015561041c60c483016110ab565b6006820180546001600160a01b0319166001600160a01b0390921691909117905560e48201356007820155600861045661010484016110ab565b91019060018060a01b03166bffffffffffffffffffffffff60a01b825416179055806004013560005260046020524260406000205561050f7f982c454c7eadeac52cca70807d29ec7fa0ab50878c2f4515a9084676975ca7d16104bf60248401846004016110bf565b906104d060448601866004016110bf565b94906104de608488016110ab565b956105016104ee60c48a016110ab565b946040519660e0885260e08801916110f2565b9185830360208701526110f2565b606486013560408401526001600160a01b03948516606084015260a4860135608084015290841660a083015260e485013560c0830152339590931693600401359281900390a4005b0135905038806103b7565b60028501825260208220919350835b601f19841685106105b6576001945083601f1981161061059c575b505050811b0160028201556103cf565b0135600019600384901b60f8161c1916905538808061058c565b81810135835560209485019460019093019201610571565b909150600284016000526020600020601f840160051c81016020851061061a575b90849392915b601f830160051c8201811061060b5750506103a0565b600081558594506001016105f5565b50806105ef565b634e487b7160e01b600052604160045260246000fd5b013590503880610353565b84825260208220925090601f198416815b8181106106905750908460019594939210610676575b505050811b019055610368565b0135600019600384901b60f8161c19169055388080610669565b91936020600181928787013581550195019201610653565b909150836000526020600020601f840160051c810191602085106106f1575b90601f859493920160051c01905b8181106106e2575061033c565b600081558493506001016106d5565b90915081906106c7565b638baa579f60e01b60005260046000fd5b6317fd8aab60e31b60005260046000fd5b61072a61010483016110ab565b63536dd9ef60e01b6000908152336004526001600160a01b0391909116602452604490fd5b600080fd5b3461074f57604036600319011261074f5760043560243567ffffffffffffffff811161074f57610788903690600401610e5e565b505061079381611113565b6001600160a01b0381169190338390036108a05781600052600460205260406000205461012c810180821161088a5780421061087257506202a300810180911161088a57804210156108725750610832908260005260026020526040600020906108186108036005840154611091565b600484015483906001600160a01b031661117f565b6006820154600790920154916001600160a01b031661117f565b8060005260036020526040600020600160ff198254161790557f40fa46a0f0868890a59cbb2de69a0fbe24e336329925b215cac7fe18e84767c2600080a3005b63293d061b60e11b6000524260045260245260446000fd5b634e487b7160e01b600052601160045260246000fd5b8263536dd9ef60e01b6000523360045260245260446000fd5b3461074f57602036600319011261074f5760206108d7600435611091565b604051908152f35b3461074f57602036600319011261074f576080600435600061010060405161090681610f95565b828152606060208201526060604082015282606082015282858201528260a08201528260c08201528260e08201520152806000526002602052604060002081600052600360205260ff604060002054169160005260046020526040600020546040519261097284610f95565b82548452604051936109928561098b816001880161100e565b0386610fb2565b60208101948552604051936109ae8561098b816002850161100e565b604082019485526003810154946060830195865260018060a01b0360048301541688840190815260058301549060a08501918252610a5760018060a01b036006860154169360c08701948552610a4460078701549660e08901978852600860018060a01b03910154169761010081019889526101206040519e8f9e8f9360608552516060850152519201526101808d0190610e1d565b90518b8203605f190160a08d0152610e1d565b975160c08a0152516001600160a01b0390811660e08a015290516101008901529051811661012088015290516101408701529051166101608501521515602084015260408301520390f35b3461074f57602036600319011261074f57600435610abf81611113565b600082815260026020526040902060088101546001600160a01b031691338390036108a057600582015460328102908082046032149015171561088a576004830154610b1c946108189260649004916001600160a01b031661117f565b8060005260036020526040600020600160ff1982541617905533907f16a82196722dee8c3133e9a254d354ecd82df1ae49081db3270b4a8bb4382604600080a3005b3461074f57600036600319011261074f5760206040517f93ff08ae199cf6417984a0da02ae95c00ebb8ec23824cf2ed480560e3c5f05138152f35b3461074f57600036600319011261074f57610c38610bd67f00000000000000000000000000000000000000000000000000000000000000006113cf565b610bff7f0000000000000000000000000000000000000000000000000000000000000000611436565b6020610c4660405192610c128385610fb2565b600084526000368137604051958695600f60f81b875260e08588015260e0870190610e1d565b908582036040870152610e1d565b466060850152306080850152600060a085015283810360c085015281808451928381520193019160005b828110610c7f57505050500390f35b835185528695509381019392810192600101610c70565b3461074f57602036600319011261074f576040610cb4600435610f15565b825191151582526020820152f35b3461074f57600036600319011261074f5760206108d76111c1565b3461074f57602036600319011261074f57600435610cfa81611113565b5060008181526002602052604090206008810180546001600160a01b0316929133849003610dd3578260005260046020526040600020546202a300810180911161088a578042106108725750610d71610d919394610d5b6005840154611091565b60048401549091906001600160a01b031661117f565b60068101549154600790910154916001600160a01b03918216911661117f565b8060005260036020526040600020600160ff1982541617905533907fb0da478e7a30218f2beadf504e14493c318640d667e4e2871e9d201227153ac5600080a3005b8363536dd9ef60e01b6000523360045260245260446000fd5b3461074f57602036600319011261074f57604060ff610e0c600435610e8c565b835191151582529091166020820152f35b919082519283825260005b848110610e49575050826000602080949584010152601f8019910116010190565b80602080928401015182828601015201610e28565b9181601f8401121561074f5782359167ffffffffffffffff831161074f576020838186019501011161074f57565b80600052600460205260406000205415610f0c5780600052600360205260ff60406000205416610f0357600052600460205260406000205461012c810180821161088a574210610efa576202a300810180911161088a57421015610ef257600190600090565b600090600490565b50600090600390565b50600090600290565b50600090600190565b806000526004602052604060002054158015610f7d575b610f74576000526004602052604060002054906202a30082019182811161088a5782421015610f6a574290036202a3000191821161088a5760009190565b5060019150600090565b50600090600090565b5080600052600360205260ff60406000205416610f2c565b610120810190811067ffffffffffffffff82111761062157604052565b90601f8019910116810190811067ffffffffffffffff82111761062157604052565b90600182811c92168015611004575b6020831014610fee57565b634e487b7160e01b600052602260045260246000fd5b91607f1691610fe3565b6000929181549161101e83610fd4565b8083529260018116908115611074575060011461103a57505050565b60009081526020812093945091925b83831061105a575060209250010190565b600181602092949394548385870101520191019190611049565b915050602093945060ff929192191683830152151560051b010190565b60968102908082046096149015171561088a576064900490565b356001600160a01b038116810361074f5790565b903590601e198136030182121561074f570180359067ffffffffffffffff821161074f5760200191813603831361074f57565b908060209392818452848401376000828201840152601f01601f1916010190565b8060005260046020526040600020541561115e5780600052600360205260ff6040600020541661116f576000908152600560205260409020546001600160a01b031690811561115e57565b6361ae648360e01b60005260046000fd5b62560ff960e81b60005260046000fd5b60405163a9059cbb60e01b60208201526001600160a01b0390921660248301526044808301939093529181526111bf916111ba606483610fb2565b611368565b565b307f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614806112b4575b1561121c577f000000000000000000000000000000000000000000000000000000000000000090565b60405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f000000000000000000000000000000000000000000000000000000000000000060408201527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260a081526112ae60c082610fb2565b51902090565b507f000000000000000000000000000000000000000000000000000000000000000046146111f3565b92919267ffffffffffffffff82116106215760405191611307601f8201601f191660200184610fb2565b82948184528183011161074f578281602093846000960137010152565b6040516323b872dd60e01b60208201526001600160a01b0392831660248201529290911660448301526064808301939093529181526111bf916111ba608483610fb2565b906000602091828151910182855af1156113c3576000513d6113ba57506001600160a01b0381163b155b6113995750565b635274afe760e01b60009081526001600160a01b0391909116600452602490fd5b60011415611392565b6040513d6000823e3d90fd5b60ff81146114195760ff811690601f82116114085760408051926113f38285610fb2565b6020808552840191601f190136833783525290565b632cd44ac360e21b60005260046000fd5b506040516114338161142c81600061100e565b0382610fb2565b90565b60ff811461145a5760ff811690601f82116114085760408051926113f38285610fb2565b506040516114338161142c81600161100e565b815191906041830361149e5761149792506020820151906060604084015193015160001a90611531565b9192909190565b505060009160029190565b919091600481101561151b57806114bf57509050565b6000600182036114da5763f645eedf60e01b60005260046000fd5b50600281036114f8578263fce698f760e01b60005260045260246000fd5b9091600360009214611508575050565b6335e2f38360e21b825260045260249150fd5b634e487b7160e01b600052602160045260246000fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084116115ae579160209360809260ff60009560405194855216868401526040830152606082015282805260015afa156113c3576000516001600160a01b038116156115a25790600090600090565b50600090600190600090565b5050506000916003919056fea2646970667358221220a9c2b771049e5b062cbb3b8064691ae0bdd922a1d4e94bc22ca174f840a68ed864736f6c634300081a00330000000000000000000000", + "nonce": "0x7", + "chainId": "0x14a34" + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "status": "0x1", + "cumulativeGasUsed": "0x1c842c", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xe8291b013f1757fe85b50f0f74722021e896d96538ac7611c47f9258644e4d0e", + "transactionIndex": "0x9", + "blockHash": "0xcf7d31b3fc7abe28fa8fc8b02f2e1a424de8a9c521c2da491bcfe10cbdf125ee", + "blockNumber": "0x12088a7", + "gasUsed": "0x27619", + "effectiveGasPrice": "0xc584", + "from": "0xdef013e1c10cc2b4baa652f60b7c7c9f833075d0", + "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", + "contractAddress": "0x9695d17226aa0e8c68103f77a7e8c9bf0e6852e3", + "l1BaseFeeScalar": "0x44d", + "l1BlobBaseFee": "0x1", + "l1BlobBaseFeeScalar": "0xa118b", + "l1Fee": "0x7dddb50a2", + "l1GasPrice": "0x1cc6e66e", + "l1GasUsed": "0xf849" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1733586991, + "chain": 84532, + "commit": "e8e32f9" +} \ No newline at end of file diff --git a/packages/foundry/broadcast/Deploy.s.sol/84532/run-1733587211.json b/packages/foundry/broadcast/Deploy.s.sol/84532/run-1733587211.json new file mode 100644 index 0000000..fd50101 --- /dev/null +++ b/packages/foundry/broadcast/Deploy.s.sol/84532/run-1733587211.json @@ -0,0 +1,52 @@ +{ + "transactions": [ + { + "hash": "0xbe6442be7b6b4fcc28eb72b2e7a3362f8093187c8e7e1f9c5f266e11267be411", + "transactionType": "CREATE", + "contractName": "ZKRailUPI", + "contractAddress": "0x926b9bd1905cfec995b0955de7392bedece2fdc9", + "function": null, + "arguments": null, + "transaction": { + "from": "0xdef013e1c10cc2b4baa652f60b7c7c9f833075d0", + "gas": "0x197359", + "value": "0x0", + "input": "0x610160604052346101265760405161001860408261012b565b600681526020810190651692d4985a5b60d21b82526040519161003c60408461012b565b600183526020830191603160f81b835261005581610164565b6101205261006284610326565b61014052519020918260e05251902080610100524660a0526040519060208201927f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8452604083015260608201524660808201523060a082015260a081526100cb60c08261012b565b5190206080523060c0526040516115f090816104c58239608051816111fa015260a051816112b7015260c051816111c4015260e051816112490152610100518161126f01526101205181610bb201526101405181610bdb0152f35b600080fd5b601f909101601f19168101906001600160401b0382119082101761014e57604052565b634e487b7160e01b600052604160045260246000fd5b908151602081106000146101fc575090601f8151116101a0576020815191015160208210610190571790565b6000198260200360031b1b161790565b6040519063305a27a960e01b8252602060048301528181519182602483015260005b8381106101e45750508160006044809484010152601f80199101168101030190fd5b602082820181015160448784010152859350016101c2565b6001600160401b03811161014e57600054600181811c9116801561031c575b602082101461030657601f81116102d1575b50602092601f821160011461026d5792819293600092610262575b50508160011b916000199060031b1c19161760005560ff90565b015190503880610248565b601f1982169360008052806000209160005b8681106102b957508360019596106102a0575b505050811b0160005560ff90565b015160001960f88460031b161c19169055388080610292565b9192602060018192868501518155019401920161027f565b60008052601f6020600020910160051c810190601f830160051c015b8181106102fa575061022d565b600081556001016102ed565b634e487b7160e01b600052602260045260246000fd5b90607f169061021b565b908151602081106000146103ae575090601f815111610352576020815191015160208210610190571790565b6040519063305a27a960e01b8252602060048301528181519182602483015260005b8381106103965750508160006044809484010152601f80199101168101030190fd5b60208282018101516044878401015285935001610374565b6001600160401b03811161014e57600154600181811c911680156104ba575b602082101461030657601f8111610484575b50602092601f821160011461041f5792819293600092610414575b50508160011b916000199060031b1c19161760015560ff90565b0151905038806103fa565b601f198216936001600052806000209160005b86811061046c5750836001959610610453575b505050811b0160015560ff90565b015160001960f88460031b161c19169055388080610445565b91926020600181928685015181550194019201610432565b6001600052601f6020600020910160051c810190601f830160051c015b8181106104ae57506103df565b600081556001016104a1565b90607f16906103cd56fe6080604052600436101561001257600080fd5b60003560e01c80630254f39214610dec5780632a7559ad14610cdd5780633644e51514610cc25780635afb31c814610c9657806384b0196e14610b995780638ed0e37d14610b5e578063987757dd14610aa2578063b4257b9a146108df578063d8da5b2b146108b9578063d8ef508d146107545763f8af14d11461009557600080fd5b3461074f57604036600319011261074f5760043567ffffffffffffffff811161074f57610120600319823603011261074f5760243567ffffffffffffffff811161074f576100e7903690600401610e5e565b91906001600160a01b036100fe61010484016110ab565b16330361071d578160040135600052600460205260406000205461070c5761025d9261024e61025492604261014361013c60248801886004016110bf565b36916112dd565b6020815191012061015d61013c60448901896004016110bf565b60208151910120610170608489016110ab565b61017c60c48a016110ab565b6101896101048b016110ab565b916040519360208501957f93ff08ae199cf6417984a0da02ae95c00ebb8ec23824cf2ed480560e3c5f051387528c6004013560408701526060860152608085015260648b013560a085015260018060a01b031660c084015260a48a013560e084015260018060a01b031661010083015260e489013561012083015260018060a01b0316610140820152610140815261022361016082610fb2565b51902061022e6111c1565b906040519161190160f01b835260028301526022820152209236916112dd565b9061146d565b909391936114a9565b6001600160a01b038216156106fb576004810135600090815260056020526040902080546001600160a01b0319166001600160a01b0384161790556102c66102a860a4830135611091565b6001600160a01b036102bc608485016110ab565b1630903390611324565b6102ea60e482013530846001600160a01b036102e460c487016110ab565b16611324565b806004013560005260026020526040600020816004013581556001810161031760248401846004016110bf565b9067ffffffffffffffff82116106215781906103338454610fd4565b601f81116106a8575b50600090601f831160011461064257600092610637575b50508160011b916000199060031b1c19161790555b61037860448301836004016110bf565b9067ffffffffffffffff82116106215781906103976002850154610fd4565b601f81116105ce575b50600090601f831160011461056257600092610557575b50508160011b916000199060031b1c19161760028201555b606482013560038201556103e5608483016110ab565b6004820180546001600160a01b0319166001600160a01b0390921691909117905560a4820135600582015561041c60c483016110ab565b6006820180546001600160a01b0319166001600160a01b0390921691909117905560e48201356007820155600861045661010484016110ab565b91019060018060a01b03166bffffffffffffffffffffffff60a01b825416179055806004013560005260046020524260406000205561050f7f982c454c7eadeac52cca70807d29ec7fa0ab50878c2f4515a9084676975ca7d16104bf60248401846004016110bf565b906104d060448601866004016110bf565b94906104de608488016110ab565b956105016104ee60c48a016110ab565b946040519660e0885260e08801916110f2565b9185830360208701526110f2565b606486013560408401526001600160a01b03948516606084015260a4860135608084015290841660a083015260e485013560c0830152339590931693600401359281900390a4005b0135905038806103b7565b60028501825260208220919350835b601f19841685106105b6576001945083601f1981161061059c575b505050811b0160028201556103cf565b0135600019600384901b60f8161c1916905538808061058c565b81810135835560209485019460019093019201610571565b909150600284016000526020600020601f840160051c81016020851061061a575b90849392915b601f830160051c8201811061060b5750506103a0565b600081558594506001016105f5565b50806105ef565b634e487b7160e01b600052604160045260246000fd5b013590503880610353565b84825260208220925090601f198416815b8181106106905750908460019594939210610676575b505050811b019055610368565b0135600019600384901b60f8161c19169055388080610669565b91936020600181928787013581550195019201610653565b909150836000526020600020601f840160051c810191602085106106f1575b90601f859493920160051c01905b8181106106e2575061033c565b600081558493506001016106d5565b90915081906106c7565b638baa579f60e01b60005260046000fd5b6317fd8aab60e31b60005260046000fd5b61072a61010483016110ab565b63536dd9ef60e01b6000908152336004526001600160a01b0391909116602452604490fd5b600080fd5b3461074f57604036600319011261074f5760043560243567ffffffffffffffff811161074f57610788903690600401610e5e565b505061079381611113565b6001600160a01b0381169190338390036108a05781600052600460205260406000205461012c810180821161088a5780421061087257506202a300810180911161088a57804210156108725750610832908260005260026020526040600020906108186108036005840154611091565b600484015483906001600160a01b031661117f565b6006820154600790920154916001600160a01b031661117f565b8060005260036020526040600020600160ff198254161790557f40fa46a0f0868890a59cbb2de69a0fbe24e336329925b215cac7fe18e84767c2600080a3005b63293d061b60e11b6000524260045260245260446000fd5b634e487b7160e01b600052601160045260246000fd5b8263536dd9ef60e01b6000523360045260245260446000fd5b3461074f57602036600319011261074f5760206108d7600435611091565b604051908152f35b3461074f57602036600319011261074f576080600435600061010060405161090681610f95565b828152606060208201526060604082015282606082015282858201528260a08201528260c08201528260e08201520152806000526002602052604060002081600052600360205260ff604060002054169160005260046020526040600020546040519261097284610f95565b82548452604051936109928561098b816001880161100e565b0386610fb2565b60208101948552604051936109ae8561098b816002850161100e565b604082019485526003810154946060830195865260018060a01b0360048301541688840190815260058301549060a08501918252610a5760018060a01b036006860154169360c08701948552610a4460078701549660e08901978852600860018060a01b03910154169761010081019889526101206040519e8f9e8f9360608552516060850152519201526101808d0190610e1d565b90518b8203605f190160a08d0152610e1d565b975160c08a0152516001600160a01b0390811660e08a015290516101008901529051811661012088015290516101408701529051166101608501521515602084015260408301520390f35b3461074f57602036600319011261074f57600435610abf81611113565b600082815260026020526040902060088101546001600160a01b031691338390036108a057600582015460328102908082046032149015171561088a576004830154610b1c946108189260649004916001600160a01b031661117f565b8060005260036020526040600020600160ff1982541617905533907f16a82196722dee8c3133e9a254d354ecd82df1ae49081db3270b4a8bb4382604600080a3005b3461074f57600036600319011261074f5760206040517f93ff08ae199cf6417984a0da02ae95c00ebb8ec23824cf2ed480560e3c5f05138152f35b3461074f57600036600319011261074f57610c38610bd67f00000000000000000000000000000000000000000000000000000000000000006113cf565b610bff7f0000000000000000000000000000000000000000000000000000000000000000611436565b6020610c4660405192610c128385610fb2565b600084526000368137604051958695600f60f81b875260e08588015260e0870190610e1d565b908582036040870152610e1d565b466060850152306080850152600060a085015283810360c085015281808451928381520193019160005b828110610c7f57505050500390f35b835185528695509381019392810192600101610c70565b3461074f57602036600319011261074f576040610cb4600435610f15565b825191151582526020820152f35b3461074f57600036600319011261074f5760206108d76111c1565b3461074f57602036600319011261074f57600435610cfa81611113565b5060008181526002602052604090206008810180546001600160a01b0316929133849003610dd3578260005260046020526040600020546202a300810180911161088a578042106108725750610d71610d919394610d5b6005840154611091565b60048401549091906001600160a01b031661117f565b60068101549154600790910154916001600160a01b03918216911661117f565b8060005260036020526040600020600160ff1982541617905533907fb0da478e7a30218f2beadf504e14493c318640d667e4e2871e9d201227153ac5600080a3005b8363536dd9ef60e01b6000523360045260245260446000fd5b3461074f57602036600319011261074f57604060ff610e0c600435610e8c565b835191151582529091166020820152f35b919082519283825260005b848110610e49575050826000602080949584010152601f8019910116010190565b80602080928401015182828601015201610e28565b9181601f8401121561074f5782359167ffffffffffffffff831161074f576020838186019501011161074f57565b80600052600460205260406000205415610f0c5780600052600360205260ff60406000205416610f0357600052600460205260406000205461012c810180821161088a574210610efa576202a300810180911161088a57421015610ef257600190600090565b600090600490565b50600090600390565b50600090600290565b50600090600190565b806000526004602052604060002054158015610f7d575b610f74576000526004602052604060002054906202a30082019182811161088a5782421015610f6a574290036202a3000191821161088a5760009190565b5060019150600090565b50600090600090565b5080600052600360205260ff60406000205416610f2c565b610120810190811067ffffffffffffffff82111761062157604052565b90601f8019910116810190811067ffffffffffffffff82111761062157604052565b90600182811c92168015611004575b6020831014610fee57565b634e487b7160e01b600052602260045260246000fd5b91607f1691610fe3565b6000929181549161101e83610fd4565b8083529260018116908115611074575060011461103a57505050565b60009081526020812093945091925b83831061105a575060209250010190565b600181602092949394548385870101520191019190611049565b915050602093945060ff929192191683830152151560051b010190565b60968102908082046096149015171561088a576064900490565b356001600160a01b038116810361074f5790565b903590601e198136030182121561074f570180359067ffffffffffffffff821161074f5760200191813603831361074f57565b908060209392818452848401376000828201840152601f01601f1916010190565b8060005260046020526040600020541561115e5780600052600360205260ff6040600020541661116f576000908152600560205260409020546001600160a01b031690811561115e57565b6361ae648360e01b60005260046000fd5b62560ff960e81b60005260046000fd5b60405163a9059cbb60e01b60208201526001600160a01b0390921660248301526044808301939093529181526111bf916111ba606483610fb2565b611368565b565b307f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614806112b4575b1561121c577f000000000000000000000000000000000000000000000000000000000000000090565b60405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f000000000000000000000000000000000000000000000000000000000000000060408201527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260a081526112ae60c082610fb2565b51902090565b507f000000000000000000000000000000000000000000000000000000000000000046146111f3565b92919267ffffffffffffffff82116106215760405191611307601f8201601f191660200184610fb2565b82948184528183011161074f578281602093846000960137010152565b6040516323b872dd60e01b60208201526001600160a01b0392831660248201529290911660448301526064808301939093529181526111bf916111ba608483610fb2565b906000602091828151910182855af1156113c3576000513d6113ba57506001600160a01b0381163b155b6113995750565b635274afe760e01b60009081526001600160a01b0391909116600452602490fd5b60011415611392565b6040513d6000823e3d90fd5b60ff81146114195760ff811690601f82116114085760408051926113f38285610fb2565b6020808552840191601f190136833783525290565b632cd44ac360e21b60005260046000fd5b506040516114338161142c81600061100e565b0382610fb2565b90565b60ff811461145a5760ff811690601f82116114085760408051926113f38285610fb2565b506040516114338161142c81600161100e565b815191906041830361149e5761149792506020820151906060604084015193015160001a90611531565b9192909190565b505060009160029190565b919091600481101561151b57806114bf57509050565b6000600182036114da5763f645eedf60e01b60005260046000fd5b50600281036114f8578263fce698f760e01b60005260045260246000fd5b9091600360009214611508575050565b6335e2f38360e21b825260045260249150fd5b634e487b7160e01b600052602160045260246000fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084116115ae579160209360809260ff60009560405194855216868401526040830152606082015282805260015afa156113c3576000516001600160a01b038116156115a25790600090600090565b50600090600190600090565b5050506000916003919056fea2646970667358221220a9c2b771049e5b062cbb3b8064691ae0bdd922a1d4e94bc22ca174f840a68ed864736f6c634300081a0033", + "nonce": "0x8", + "chainId": "0x14a34" + }, + "additionalContracts": [], + "isFixedGasLimit": false + } + ], + "receipts": [ + { + "status": "0x1", + "cumulativeGasUsed": "0x1e35db", + "logs": [], + "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "type": "0x2", + "transactionHash": "0xbe6442be7b6b4fcc28eb72b2e7a3362f8093187c8e7e1f9c5f266e11267be411", + "transactionIndex": "0xb", + "blockHash": "0x50d37daeb24f9290eeea673803d1dce2f9c29045683269f115bdc07da79a7c33", + "blockNumber": "0x120890c", + "gasUsed": "0x13957b", + "effectiveGasPrice": "0x3ee", + "from": "0xdef013e1c10cc2b4baa652f60b7c7c9f833075d0", + "to": null, + "contractAddress": "0x926b9bd1905cfec995b0955de7392bedece2fdc9", + "l1BaseFeeScalar": "0x44d", + "l1BlobBaseFee": "0x1", + "l1BlobBaseFeeScalar": "0xa118b", + "l1Fee": "0x6dc5c77f3", + "l1GasPrice": "0x1957cbac", + "l1GasUsed": "0xf5e2" + } + ], + "libraries": [], + "pending": [], + "returns": {}, + "timestamp": 1733587211, + "chain": 84532, + "commit": "e8e32f9" +} \ No newline at end of file diff --git a/packages/foundry/broadcast/Deploy.s.sol/84532/run-latest.json b/packages/foundry/broadcast/Deploy.s.sol/84532/run-latest.json index d142fb5..fd50101 100644 --- a/packages/foundry/broadcast/Deploy.s.sol/84532/run-latest.json +++ b/packages/foundry/broadcast/Deploy.s.sol/84532/run-latest.json @@ -1,19 +1,18 @@ { "transactions": [ { - "hash": "0x84282298d95a3c7ffca16e764265bda57eb1b20c7de23817da6d30c57aa4a32e", - "transactionType": "CREATE2", + "hash": "0xbe6442be7b6b4fcc28eb72b2e7a3362f8093187c8e7e1f9c5f266e11267be411", + "transactionType": "CREATE", "contractName": "ZKRailUPI", - "contractAddress": "0x887a72abf9395b0a45dca391901ccd71243cd1b3", + "contractAddress": "0x926b9bd1905cfec995b0955de7392bedece2fdc9", "function": null, "arguments": null, "transaction": { "from": "0xdef013e1c10cc2b4baa652f60b7c7c9f833075d0", - "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", - "gas": "0x21ac24", + "gas": "0x197359", "value": "0x0", - "input": "0x0000000000000000000000000000000000000000000000000000000000001234610160604052346101265760405161001860408261012b565b600681526020810190651692d4985a5b60d21b82526040519161003c60408461012b565b600183526020830191603160f81b835261005581610164565b6101205261006284610326565b61014052519020918260e05251902080610100524660a0526040519060208201927f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8452604083015260608201524660808201523060a082015260a081526100cb60c08261012b565b5190206080523060c052604051611b9090816104c582396080518161192a015260a051816119e7015260c051816118f4015260e051816119790152610100518161199f01526101205181610e3f01526101405181610e680152f35b600080fd5b601f909101601f19168101906001600160401b0382119082101761014e57604052565b634e487b7160e01b600052604160045260246000fd5b908151602081106000146101fc575090601f8151116101a0576020815191015160208210610190571790565b6000198260200360031b1b161790565b6040519063305a27a960e01b8252602060048301528181519182602483015260005b8381106101e45750508160006044809484010152601f80199101168101030190fd5b602082820181015160448784010152859350016101c2565b6001600160401b03811161014e57600054600181811c9116801561031c575b602082101461030657601f81116102d1575b50602092601f821160011461026d5792819293600092610262575b50508160011b916000199060031b1c19161760005560ff90565b015190503880610248565b601f1982169360008052806000209160005b8681106102b957508360019596106102a0575b505050811b0160005560ff90565b015160001960f88460031b161c19169055388080610292565b9192602060018192868501518155019401920161027f565b60008052601f6020600020910160051c810190601f830160051c015b8181106102fa575061022d565b600081556001016102ed565b634e487b7160e01b600052602260045260246000fd5b90607f169061021b565b908151602081106000146103ae575090601f815111610352576020815191015160208210610190571790565b6040519063305a27a960e01b8252602060048301528181519182602483015260005b8381106103965750508160006044809484010152601f80199101168101030190fd5b60208282018101516044878401015285935001610374565b6001600160401b03811161014e57600154600181811c911680156104ba575b602082101461030657601f8111610484575b50602092601f821160011461041f5792819293600092610414575b50508160011b916000199060031b1c19161760015560ff90565b0151905038806103fa565b601f198216936001600052806000209160005b86811061046c5750836001959610610453575b505050811b0160015560ff90565b015160001960f88460031b161c19169055388080610445565b91926020600181928685015181550194019201610432565b6001600052601f6020600020910160051c810190601f830160051c015b8181106104ae57506103df565b600081556001016104a1565b90607f16906103cd56fe6080604052600436101561001257600080fd5b60003560e01c80630254f3921461119f5780632a7559ad14611021578063540ef46114610fed5780635afb31c814610fc157806375c7050914610f2357806384b0196e14610e265780638ed0e37d14610deb5780638ffafd0c1461067f578063924c9e7214610653578063987757dd1461050b578063b082a274146104d0578063b4257b9a14610357578063bd07f3c914610326578063d8da5b2b146103005763d8ef508d146100c157600080fd5b346102fb5760403660031901126102fb5760043560243567ffffffffffffffff81116102fb576100f59036906004016113b4565b505080600052600260205260406000209080600052600460205261011f60406000205415156115a6565b80600052600360205261013a60ff604060002054161561146b565b80600052600460205260406000205461012c81018082116102aa5742106102c0576202a30081018091116102aa5742101561026e576000818152600560205260409020546001600160a01b0316916101938315156115a6565b82330361021f57806101c36101ae60056101df9401546115e9565b600483015486906001600160a01b0316611603565b60068101546007909101549084906001600160a01b0316611603565b8060005260036020526040600020600160ff198254161790557f40fa46a0f0868890a59cbb2de69a0fbe24e336329925b215cac7fe18e84767c2600080a3005b60405162461bcd60e51b815260206004820152602160248201527f4f6e6c79206d616b65722063616e207265736f6c766520776974682070726f6f6044820152603360f91b6064820152608490fd5b60405162461bcd60e51b8152602060048201526014602482015273141c9bdbd9881dda5b991bddc8195e1c1a5c995960621b6044820152606490fd5b634e487b7160e01b600052601160045260246000fd5b60405162461bcd60e51b81526020600482015260136024820152722a37b79032b0b9363c903337b910383937b7b360691b6044820152606490fd5b600080fd5b346102fb5760203660031901126102fb57602061031e6004356115e9565b604051908152f35b346102fb5760203660031901126102fb576004356000526003602052602060ff604060002054166040519015158152f35b346102fb5760203660031901126102fb57600435600060c060405161037b8161120a565b82815260405161038a81611226565b606081526060602082015283604082015260208201528260408201528260608201528260808201528260a08201520152806000526002602052604060002081600052600360205260ff6040600020541691600052600460205260406000205490604051916103f78361120a565b8154835261040760018301611308565b936020840194855260018060a01b0360048401541692604085019384526005810154906060860191825260018060a01b036006820154166080870190815260078201549160a08801928352600860018060a01b03910154169260c0880193845261048d604051998a9960608b525160608b01525160e060808b01526101408a019061137f565b96516001600160a01b0390811660a08a0152905160c08901529051811660e088015290516101008701529051166101208501521515602084015260408301520390f35b346102fb5760003660031901126102fb5760206040517f1468475ec693620e078de60b230b69f8316434c04e2277c318a725830318d72b8152f35b346102fb5760203660031901126102fb57600435600081815260026020526040902060088101546001600160a01b031690338290036106165782600052600360205261055f60ff604060002054161561146b565b6000838152600560205260409020546001600160a01b03166105828115156115a6565b60058201546032810290808204603214901517156102aa5760048301546105d4946105ba9260649004916001600160a01b0316611603565b6006820154600790920154916001600160a01b0316611603565b8060005260036020526040600020600160ff1982541617905533907f16a82196722dee8c3133e9a254d354ecd82df1ae49081db3270b4a8bb4382604600080a3005b60405162461bcd60e51b81526020600482015260156024820152744f6e6c792074616b65722063616e20736574746c6560581b6044820152606490fd5b346102fb5760203660031901126102fb5760043560005260046020526020604060002054604051908152f35b346102fb5760403660031901126102fb5760043567ffffffffffffffff81116102fb57806004019060e060031982360301126102fb5760243567ffffffffffffffff81116102fb576106d59036906004016113b4565b9260c48301926001600160a01b036106ec85611529565b163303610da657813592836000526004602052604060002054610d615761089194602483019161071c838661153d565b6107306107298280611552565b3691611643565b6020815191012090604061074a6107296020840184611552565b602081519101209181519260208401947f1468475ec693620e078de60b230b69f8316434c04e2277c318a725830318d72b8652838501526060840152013560808201526080815261079c60a082611242565b5190209161088860448601996108826107b48c611529565b9460428b60648b01359860848c019860a46107ce8b611529565b9d01359c6107db8a611529565b916040519360208501957f7ced3993fcde6944cc4de21b2b9367f2ce6ea9972cbef31bbb1671cb9d29c0e387526040860152606085015260018060a01b031660808401528b60a084015260018060a01b031660c08301528c60e083015260018060a01b0316610100820152610100815261085761012082611242565b5190206108626118f1565b906040519161190160f01b83526002830152602282015220923691611643565b90611a0d565b90999199611a49565b6001600160a01b038816978815610d28578561090c9189600052600560205260406000208b6bffffffffffffffffffffffff60a01b8254161790556108f36108d8876115e9565b6001600160a01b036108e98f611529565b163090339061168a565b30906001600160a01b0361090687611529565b1661168a565b8660005260026020526040600020908782556001820161092c868961153d565b906109378280611552565b9067ffffffffffffffff8211610c4e57819061095384546111d0565b601f8111610cd5575b50600090601f8311600114610c6f57600092610c64575b50508160011b916000199060031b1c19161790555b600283016109996020830183611552565b9067ffffffffffffffff8211610c4e576109b383546111d0565b601f8111610c06575b50600090601f8311600114610b705793610a8b93837f982c454c7eadeac52cca70807d29ec7fa0ab50878c2f4515a9084676975ca7d19d9c9b9a99989794604094600898600092610b65575b50508160011b916000199060031b1c19161790555b01356003850155610a2d8d611529565b6004850180546001600160a01b0319166001600160a01b0390921691909117905560058401869055610a5e85611529565b6006850180546001600160a01b0319166001600160a01b0390921691909117905560078401889055611529565b91019060018060a01b03166bffffffffffffffffffffffff60a01b82541617905586600052600460205242604060002055610b31610ad2610acc858861153d565b80611552565b969094610b23610b10610b0a6040610b02610afa610af0878961153d565b6020810190611552565b96909761153d565b01359e611529565b95611529565b966040519960e08b5260e08b0191611585565b9188830360208a0152611585565b60408601999099526001600160a01b03908116606086015260808501919091521660a083015260c0820152339481900390a4005b013590503880610a08565b8382526020822091601f198416815b818110610bee5750846040947f982c454c7eadeac52cca70807d29ec7fa0ab50878c2f4515a9084676975ca7d19f9e9d9c9b9a999694610a8b989460089a9660019510610bd4575b505050811b019055610a1d565b0135600019600384901b60f8161c19169055388080610bc7565b91936020600181928787013581550195019201610b7f565b836000526020600020601f840160051c81019160208510610c44575b601f0160051c01905b818110610c3857506109bc565b60008155600101610c2b565b9091508190610c22565b634e487b7160e01b600052604160045260246000fd5b013590508e80610973565b84825260208220925090601f198416815b818110610cbd5750908460019594939210610ca3575b505050811b019055610988565b0135600019600384901b60f8161c191690558e8080610c96565b91936020600181928787013581550195019201610c80565b909150836000526020600020601f840160051c81019160208510610d1e575b90601f859493920160051c01905b818110610d0f575061095c565b60008155849350600101610d02565b9091508190610cf4565b60405162461bcd60e51b8152602060048201526011602482015270496e76616c6964207369676e617475726560781b6044820152606490fd5b60405162461bcd60e51b815260206004820152601860248201527f496e74656e7420616c726561647920636f6d6d697474656400000000000000006044820152606490fd5b60405162461bcd60e51b815260206004820152601e60248201527f4f6e6c7920696e74656e742063726561746f722063616e20636f6d6d697400006044820152606490fd5b346102fb5760003660031901126102fb5760206040517f7ced3993fcde6944cc4de21b2b9367f2ce6ea9972cbef31bbb1671cb9d29c0e38152f35b346102fb5760003660031901126102fb57610ec5610e637f0000000000000000000000000000000000000000000000000000000000000000611735565b610e8c7f0000000000000000000000000000000000000000000000000000000000000000611837565b6020610ed360405192610e9f8385611242565b600084526000368137604051958695600f60f81b875260e08588015260e087019061133e565b90858203604087015261133e565b466060850152306080850152600060a085015283810360c085015281808451928381520193019160005b828110610f0c57505050500390f35b835185528695509381019392810192600101610efd565b346102fb5760203660031901126102fb57600435600052600260205260406000208054610f5260018301611308565b600483015460058401546006850154600786015460089096015460405195865260e060208701819052959687966001600160a01b0395861696928616959194939091169291610fa39188019061137f565b9460408701526060860152608085015260a084015260c08301520390f35b346102fb5760203660031901126102fb576040610fdf6004356114a9565b825191151582526020820152f35b346102fb5760203660031901126102fb576004356000526005602052602060018060a01b0360406000205416604051908152f35b346102fb5760203660031901126102fb5760043560008181526002602052604090206008810180546001600160a01b031691338390036111615783600052600360205261107660ff604060002054161561146b565b8360005260046020526040600020546202a30081018091116102aa574210611124576110c26110e2936110ac60058401546115e9565b60048401549091906001600160a01b0316611603565b60068101549154600790910154916001600160a01b039182169116611603565b8060005260036020526040600020600160ff1982541617905533907fb0da478e7a30218f2beadf504e14493c318640d667e4e2871e9d201227153ac5600080a3005b60405162461bcd60e51b8152602060048201526015602482015274151bdbc819585c9b1e48199bdc881d1a5b595bdd5d605a1b6044820152606490fd5b60405162461bcd60e51b815260206004820152601660248201527513db9b1e481d185ad95c8818d85b881d1a5b595bdd5d60521b6044820152606490fd5b346102fb5760203660031901126102fb57604060ff6111bf6004356113e2565b835191151582529091166020820152f35b90600182811c92168015611200575b60208310146111ea57565b634e487b7160e01b600052602260045260246000fd5b91607f16916111df565b60e0810190811067ffffffffffffffff821117610c4e57604052565b6060810190811067ffffffffffffffff821117610c4e57604052565b90601f8019910116810190811067ffffffffffffffff821117610c4e57604052565b9060405191826000825492611278846111d0565b80845293600181169081156112e6575060011461129f575b5061129d92500383611242565b565b90506000929192526020600020906000915b8183106112ca57505090602061129d9282010138611290565b60209193508060019154838589010152019101909184926112b1565b90506020925061129d94915060ff191682840152151560051b82010138611290565b9060405161131581611226565b60406002829461132481611264565b845261133260018201611264565b60208501520154910152565b919082519283825260005b84811061136a575050826000602080949584010152601f8019910116010190565b80602080928401015182828601015201611349565b906040806113ab611399855160608652606086019061133e565b6020860151858203602087015261133e565b93015191015290565b9181601f840112156102fb5782359167ffffffffffffffff83116102fb57602083818601950101116102fb57565b806000526004602052604060002054156114625780600052600360205260ff6040600020541661145957600052600460205260406000205461012c81018082116102aa574210611450576202a30081018091116102aa5742101561144857600190600090565b600090600490565b50600090600390565b50600090600290565b50600090600190565b1561147257565b60405162461bcd60e51b815260206004820152600f60248201526e105b1c9958591e481cd95d1d1b1959608a1b6044820152606490fd5b806000526004602052604060002054158015611511575b611508576000526004602052604060002054906202a3008201918281116102aa57824210156114fe574290036202a300019182116102aa5760009190565b5060019150600090565b50600090600090565b5080600052600360205260ff604060002054166114c0565b356001600160a01b03811681036102fb5790565b903590605e19813603018212156102fb570190565b903590601e19813603018212156102fb570180359067ffffffffffffffff82116102fb576020019181360383136102fb57565b908060209392818452848401376000828201840152601f01601f1916010190565b156115ad57565b60405162461bcd60e51b8152602060048201526014602482015273125b9d195b9d081b9bdd0818dbdb5b5a5d1d195960621b6044820152606490fd5b6096810290808204609614901517156102aa576064900490565b60405163a9059cbb60e01b60208201526001600160a01b03909216602483015260448083019390935291815261129d9161163e606483611242565b6116ce565b92919267ffffffffffffffff8211610c4e576040519161166d601f8201601f191660200184611242565b8294818452818301116102fb578281602093846000960137010152565b6040516323b872dd60e01b60208201526001600160a01b03928316602482015292909116604483015260648083019390935291815261129d9161163e608483611242565b906000602091828151910182855af115611729576000513d61172057506001600160a01b0381163b155b6116ff5750565b635274afe760e01b60009081526001600160a01b0391909116600452602490fd5b600114156116f8565b6040513d6000823e3d90fd5b60ff811461177f5760ff811690601f821161176e5760408051926117598285611242565b6020808552840191601f190136833783525290565b632cd44ac360e21b60005260046000fd5b5060405160008160005491611793836111d0565b808352926001811690811561181857506001146117ba575b6117b792500382611242565b90565b50600080805290917f290decd9548b62a8d60345a988386fc84ba6bc95484008f6362f93160ef3e5635b8183106117fc5750509060206117b7928201016117ab565b60209193508060019154838588010152019101909183926117e4565b602092506117b794915060ff191682840152151560051b8201016117ab565b60ff811461185b5760ff811690601f821161176e5760408051926117598285611242565b5060405160015481600061186e836111d0565b80835292600181169081156118185750600114611891576117b792500382611242565b506001600090815290917fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf65b8183106118d55750509060206117b7928201016117ab565b60209193508060019154838588010152019101909183926118bd565b307f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614806119e4575b1561194c577f000000000000000000000000000000000000000000000000000000000000000090565b60405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f000000000000000000000000000000000000000000000000000000000000000060408201527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260a081526119de60c082611242565b51902090565b507f00000000000000000000000000000000000000000000000000000000000000004614611923565b8151919060418303611a3e57611a3792506020820151906060604084015193015160001a90611ad1565b9192909190565b505060009160029190565b9190916004811015611abb5780611a5f57509050565b600060018203611a7a5763f645eedf60e01b60005260046000fd5b5060028103611a98578263fce698f760e01b60005260045260246000fd5b9091600360009214611aa8575050565b6335e2f38360e21b825260045260249150fd5b634e487b7160e01b600052602160045260246000fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08411611b4e579160209360809260ff60009560405194855216868401526040830152606082015282805260015afa15611729576000516001600160a01b03811615611b425790600090600090565b50600090600190600090565b5050506000916003919056fea2646970667358221220f620445ddc00495eafae500fd583f395a003d5ac422759a822cffb68bdb574e364736f6c634300081a0033", - "nonce": "0x4", + "input": "0x610160604052346101265760405161001860408261012b565b600681526020810190651692d4985a5b60d21b82526040519161003c60408461012b565b600183526020830191603160f81b835261005581610164565b6101205261006284610326565b61014052519020918260e05251902080610100524660a0526040519060208201927f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f8452604083015260608201524660808201523060a082015260a081526100cb60c08261012b565b5190206080523060c0526040516115f090816104c58239608051816111fa015260a051816112b7015260c051816111c4015260e051816112490152610100518161126f01526101205181610bb201526101405181610bdb0152f35b600080fd5b601f909101601f19168101906001600160401b0382119082101761014e57604052565b634e487b7160e01b600052604160045260246000fd5b908151602081106000146101fc575090601f8151116101a0576020815191015160208210610190571790565b6000198260200360031b1b161790565b6040519063305a27a960e01b8252602060048301528181519182602483015260005b8381106101e45750508160006044809484010152601f80199101168101030190fd5b602082820181015160448784010152859350016101c2565b6001600160401b03811161014e57600054600181811c9116801561031c575b602082101461030657601f81116102d1575b50602092601f821160011461026d5792819293600092610262575b50508160011b916000199060031b1c19161760005560ff90565b015190503880610248565b601f1982169360008052806000209160005b8681106102b957508360019596106102a0575b505050811b0160005560ff90565b015160001960f88460031b161c19169055388080610292565b9192602060018192868501518155019401920161027f565b60008052601f6020600020910160051c810190601f830160051c015b8181106102fa575061022d565b600081556001016102ed565b634e487b7160e01b600052602260045260246000fd5b90607f169061021b565b908151602081106000146103ae575090601f815111610352576020815191015160208210610190571790565b6040519063305a27a960e01b8252602060048301528181519182602483015260005b8381106103965750508160006044809484010152601f80199101168101030190fd5b60208282018101516044878401015285935001610374565b6001600160401b03811161014e57600154600181811c911680156104ba575b602082101461030657601f8111610484575b50602092601f821160011461041f5792819293600092610414575b50508160011b916000199060031b1c19161760015560ff90565b0151905038806103fa565b601f198216936001600052806000209160005b86811061046c5750836001959610610453575b505050811b0160015560ff90565b015160001960f88460031b161c19169055388080610445565b91926020600181928685015181550194019201610432565b6001600052601f6020600020910160051c810190601f830160051c015b8181106104ae57506103df565b600081556001016104a1565b90607f16906103cd56fe6080604052600436101561001257600080fd5b60003560e01c80630254f39214610dec5780632a7559ad14610cdd5780633644e51514610cc25780635afb31c814610c9657806384b0196e14610b995780638ed0e37d14610b5e578063987757dd14610aa2578063b4257b9a146108df578063d8da5b2b146108b9578063d8ef508d146107545763f8af14d11461009557600080fd5b3461074f57604036600319011261074f5760043567ffffffffffffffff811161074f57610120600319823603011261074f5760243567ffffffffffffffff811161074f576100e7903690600401610e5e565b91906001600160a01b036100fe61010484016110ab565b16330361071d578160040135600052600460205260406000205461070c5761025d9261024e61025492604261014361013c60248801886004016110bf565b36916112dd565b6020815191012061015d61013c60448901896004016110bf565b60208151910120610170608489016110ab565b61017c60c48a016110ab565b6101896101048b016110ab565b916040519360208501957f93ff08ae199cf6417984a0da02ae95c00ebb8ec23824cf2ed480560e3c5f051387528c6004013560408701526060860152608085015260648b013560a085015260018060a01b031660c084015260a48a013560e084015260018060a01b031661010083015260e489013561012083015260018060a01b0316610140820152610140815261022361016082610fb2565b51902061022e6111c1565b906040519161190160f01b835260028301526022820152209236916112dd565b9061146d565b909391936114a9565b6001600160a01b038216156106fb576004810135600090815260056020526040902080546001600160a01b0319166001600160a01b0384161790556102c66102a860a4830135611091565b6001600160a01b036102bc608485016110ab565b1630903390611324565b6102ea60e482013530846001600160a01b036102e460c487016110ab565b16611324565b806004013560005260026020526040600020816004013581556001810161031760248401846004016110bf565b9067ffffffffffffffff82116106215781906103338454610fd4565b601f81116106a8575b50600090601f831160011461064257600092610637575b50508160011b916000199060031b1c19161790555b61037860448301836004016110bf565b9067ffffffffffffffff82116106215781906103976002850154610fd4565b601f81116105ce575b50600090601f831160011461056257600092610557575b50508160011b916000199060031b1c19161760028201555b606482013560038201556103e5608483016110ab565b6004820180546001600160a01b0319166001600160a01b0390921691909117905560a4820135600582015561041c60c483016110ab565b6006820180546001600160a01b0319166001600160a01b0390921691909117905560e48201356007820155600861045661010484016110ab565b91019060018060a01b03166bffffffffffffffffffffffff60a01b825416179055806004013560005260046020524260406000205561050f7f982c454c7eadeac52cca70807d29ec7fa0ab50878c2f4515a9084676975ca7d16104bf60248401846004016110bf565b906104d060448601866004016110bf565b94906104de608488016110ab565b956105016104ee60c48a016110ab565b946040519660e0885260e08801916110f2565b9185830360208701526110f2565b606486013560408401526001600160a01b03948516606084015260a4860135608084015290841660a083015260e485013560c0830152339590931693600401359281900390a4005b0135905038806103b7565b60028501825260208220919350835b601f19841685106105b6576001945083601f1981161061059c575b505050811b0160028201556103cf565b0135600019600384901b60f8161c1916905538808061058c565b81810135835560209485019460019093019201610571565b909150600284016000526020600020601f840160051c81016020851061061a575b90849392915b601f830160051c8201811061060b5750506103a0565b600081558594506001016105f5565b50806105ef565b634e487b7160e01b600052604160045260246000fd5b013590503880610353565b84825260208220925090601f198416815b8181106106905750908460019594939210610676575b505050811b019055610368565b0135600019600384901b60f8161c19169055388080610669565b91936020600181928787013581550195019201610653565b909150836000526020600020601f840160051c810191602085106106f1575b90601f859493920160051c01905b8181106106e2575061033c565b600081558493506001016106d5565b90915081906106c7565b638baa579f60e01b60005260046000fd5b6317fd8aab60e31b60005260046000fd5b61072a61010483016110ab565b63536dd9ef60e01b6000908152336004526001600160a01b0391909116602452604490fd5b600080fd5b3461074f57604036600319011261074f5760043560243567ffffffffffffffff811161074f57610788903690600401610e5e565b505061079381611113565b6001600160a01b0381169190338390036108a05781600052600460205260406000205461012c810180821161088a5780421061087257506202a300810180911161088a57804210156108725750610832908260005260026020526040600020906108186108036005840154611091565b600484015483906001600160a01b031661117f565b6006820154600790920154916001600160a01b031661117f565b8060005260036020526040600020600160ff198254161790557f40fa46a0f0868890a59cbb2de69a0fbe24e336329925b215cac7fe18e84767c2600080a3005b63293d061b60e11b6000524260045260245260446000fd5b634e487b7160e01b600052601160045260246000fd5b8263536dd9ef60e01b6000523360045260245260446000fd5b3461074f57602036600319011261074f5760206108d7600435611091565b604051908152f35b3461074f57602036600319011261074f576080600435600061010060405161090681610f95565b828152606060208201526060604082015282606082015282858201528260a08201528260c08201528260e08201520152806000526002602052604060002081600052600360205260ff604060002054169160005260046020526040600020546040519261097284610f95565b82548452604051936109928561098b816001880161100e565b0386610fb2565b60208101948552604051936109ae8561098b816002850161100e565b604082019485526003810154946060830195865260018060a01b0360048301541688840190815260058301549060a08501918252610a5760018060a01b036006860154169360c08701948552610a4460078701549660e08901978852600860018060a01b03910154169761010081019889526101206040519e8f9e8f9360608552516060850152519201526101808d0190610e1d565b90518b8203605f190160a08d0152610e1d565b975160c08a0152516001600160a01b0390811660e08a015290516101008901529051811661012088015290516101408701529051166101608501521515602084015260408301520390f35b3461074f57602036600319011261074f57600435610abf81611113565b600082815260026020526040902060088101546001600160a01b031691338390036108a057600582015460328102908082046032149015171561088a576004830154610b1c946108189260649004916001600160a01b031661117f565b8060005260036020526040600020600160ff1982541617905533907f16a82196722dee8c3133e9a254d354ecd82df1ae49081db3270b4a8bb4382604600080a3005b3461074f57600036600319011261074f5760206040517f93ff08ae199cf6417984a0da02ae95c00ebb8ec23824cf2ed480560e3c5f05138152f35b3461074f57600036600319011261074f57610c38610bd67f00000000000000000000000000000000000000000000000000000000000000006113cf565b610bff7f0000000000000000000000000000000000000000000000000000000000000000611436565b6020610c4660405192610c128385610fb2565b600084526000368137604051958695600f60f81b875260e08588015260e0870190610e1d565b908582036040870152610e1d565b466060850152306080850152600060a085015283810360c085015281808451928381520193019160005b828110610c7f57505050500390f35b835185528695509381019392810192600101610c70565b3461074f57602036600319011261074f576040610cb4600435610f15565b825191151582526020820152f35b3461074f57600036600319011261074f5760206108d76111c1565b3461074f57602036600319011261074f57600435610cfa81611113565b5060008181526002602052604090206008810180546001600160a01b0316929133849003610dd3578260005260046020526040600020546202a300810180911161088a578042106108725750610d71610d919394610d5b6005840154611091565b60048401549091906001600160a01b031661117f565b60068101549154600790910154916001600160a01b03918216911661117f565b8060005260036020526040600020600160ff1982541617905533907fb0da478e7a30218f2beadf504e14493c318640d667e4e2871e9d201227153ac5600080a3005b8363536dd9ef60e01b6000523360045260245260446000fd5b3461074f57602036600319011261074f57604060ff610e0c600435610e8c565b835191151582529091166020820152f35b919082519283825260005b848110610e49575050826000602080949584010152601f8019910116010190565b80602080928401015182828601015201610e28565b9181601f8401121561074f5782359167ffffffffffffffff831161074f576020838186019501011161074f57565b80600052600460205260406000205415610f0c5780600052600360205260ff60406000205416610f0357600052600460205260406000205461012c810180821161088a574210610efa576202a300810180911161088a57421015610ef257600190600090565b600090600490565b50600090600390565b50600090600290565b50600090600190565b806000526004602052604060002054158015610f7d575b610f74576000526004602052604060002054906202a30082019182811161088a5782421015610f6a574290036202a3000191821161088a5760009190565b5060019150600090565b50600090600090565b5080600052600360205260ff60406000205416610f2c565b610120810190811067ffffffffffffffff82111761062157604052565b90601f8019910116810190811067ffffffffffffffff82111761062157604052565b90600182811c92168015611004575b6020831014610fee57565b634e487b7160e01b600052602260045260246000fd5b91607f1691610fe3565b6000929181549161101e83610fd4565b8083529260018116908115611074575060011461103a57505050565b60009081526020812093945091925b83831061105a575060209250010190565b600181602092949394548385870101520191019190611049565b915050602093945060ff929192191683830152151560051b010190565b60968102908082046096149015171561088a576064900490565b356001600160a01b038116810361074f5790565b903590601e198136030182121561074f570180359067ffffffffffffffff821161074f5760200191813603831361074f57565b908060209392818452848401376000828201840152601f01601f1916010190565b8060005260046020526040600020541561115e5780600052600360205260ff6040600020541661116f576000908152600560205260409020546001600160a01b031690811561115e57565b6361ae648360e01b60005260046000fd5b62560ff960e81b60005260046000fd5b60405163a9059cbb60e01b60208201526001600160a01b0390921660248301526044808301939093529181526111bf916111ba606483610fb2565b611368565b565b307f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614806112b4575b1561121c577f000000000000000000000000000000000000000000000000000000000000000090565b60405160208101907f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f82527f000000000000000000000000000000000000000000000000000000000000000060408201527f000000000000000000000000000000000000000000000000000000000000000060608201524660808201523060a082015260a081526112ae60c082610fb2565b51902090565b507f000000000000000000000000000000000000000000000000000000000000000046146111f3565b92919267ffffffffffffffff82116106215760405191611307601f8201601f191660200184610fb2565b82948184528183011161074f578281602093846000960137010152565b6040516323b872dd60e01b60208201526001600160a01b0392831660248201529290911660448301526064808301939093529181526111bf916111ba608483610fb2565b906000602091828151910182855af1156113c3576000513d6113ba57506001600160a01b0381163b155b6113995750565b635274afe760e01b60009081526001600160a01b0391909116600452602490fd5b60011415611392565b6040513d6000823e3d90fd5b60ff81146114195760ff811690601f82116114085760408051926113f38285610fb2565b6020808552840191601f190136833783525290565b632cd44ac360e21b60005260046000fd5b506040516114338161142c81600061100e565b0382610fb2565b90565b60ff811461145a5760ff811690601f82116114085760408051926113f38285610fb2565b506040516114338161142c81600161100e565b815191906041830361149e5761149792506020820151906060604084015193015160001a90611531565b9192909190565b505060009160029190565b919091600481101561151b57806114bf57509050565b6000600182036114da5763f645eedf60e01b60005260046000fd5b50600281036114f8578263fce698f760e01b60005260045260246000fd5b9091600360009214611508575050565b6335e2f38360e21b825260045260249150fd5b634e487b7160e01b600052602160045260246000fd5b91907f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a084116115ae579160209360809260ff60009560405194855216868401526040830152606082015282805260015afa156113c3576000516001600160a01b038116156115a25790600090600090565b50600090600190600090565b5050506000916003919056fea2646970667358221220a9c2b771049e5b062cbb3b8064691ae0bdd922a1d4e94bc22ca174f840a68ed864736f6c634300081a0033", + "nonce": "0x8", "chainId": "0x14a34" }, "additionalContracts": [], @@ -23,31 +22,31 @@ "receipts": [ { "status": "0x1", - "cumulativeGasUsed": "0x5a2317", + "cumulativeGasUsed": "0x1e35db", "logs": [], "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", "type": "0x2", - "transactionHash": "0x84282298d95a3c7ffca16e764265bda57eb1b20c7de23817da6d30c57aa4a32e", - "transactionIndex": "0x7", - "blockHash": "0x43bab0e99a8ab8493ad4bb8b3feadb25583166f801c46a10c76658bc3994f9e1", - "blockNumber": "0x120525d", - "gasUsed": "0x1862da", - "effectiveGasPrice": "0xd6bd", + "transactionHash": "0xbe6442be7b6b4fcc28eb72b2e7a3362f8093187c8e7e1f9c5f266e11267be411", + "transactionIndex": "0xb", + "blockHash": "0x50d37daeb24f9290eeea673803d1dce2f9c29045683269f115bdc07da79a7c33", + "blockNumber": "0x120890c", + "gasUsed": "0x13957b", + "effectiveGasPrice": "0x3ee", "from": "0xdef013e1c10cc2b4baa652f60b7c7c9f833075d0", - "to": "0x4e59b44847b379578588920ca78fbf26c0b4956c", - "contractAddress": "0x887a72abf9395b0a45dca391901ccd71243cd1b3", + "to": null, + "contractAddress": "0x926b9bd1905cfec995b0955de7392bedece2fdc9", "l1BaseFeeScalar": "0x44d", "l1BlobBaseFee": "0x1", "l1BlobBaseFeeScalar": "0xa118b", - "l1Fee": "0x1e5bd4d01a", - "l1GasPrice": "0x5eafbb3e", - "l1GasUsed": "0x12336" + "l1Fee": "0x6dc5c77f3", + "l1GasPrice": "0x1957cbac", + "l1GasUsed": "0xf5e2" } ], "libraries": [], "pending": [], "returns": {}, - "timestamp": 1733559212, + "timestamp": 1733587211, "chain": 84532, - "commit": "5c7a5d1" + "commit": "e8e32f9" } \ No newline at end of file diff --git a/packages/foundry/contracts/ZKRailBase.sol b/packages/foundry/contracts/ZKRailBase.sol index d31bd7e..2d2b250 100644 --- a/packages/foundry/contracts/ZKRailBase.sol +++ b/packages/foundry/contracts/ZKRailBase.sol @@ -15,60 +15,40 @@ import {IZKRail} from "./interfaces/IZKRail.sol"; abstract contract ZKRailBase is IZKRail, EIP712 { using SafeERC20 for ERC20; - // EIP-712 type hashes - bytes32 public constant INTENT_TYPEHASH = - keccak256( - "Intent(string railType,string recipientAddress,uint256 railAmount)" - ); - + // Single typehash for flattened structure bytes32 public constant INTENT_SOLUTION_TYPEHASH = keccak256( - "IntentSolution(bytes32 intentId,Intent intent,address paymentToken,uint256 paymentAmount,address bondToken,uint256 bondAmount,address intentCreator)Intent(string railType,string recipientAddress,uint256 railAmount)" + "IntentSolution(bytes32 intentId,string railType,string recipientAddress,uint256 railAmount,address paymentToken,uint256 paymentAmount,address bondToken,uint256 bondAmount,address intentCreator)" ); - // Storage - mapping(bytes32 => IntentSolution) public solutions; - mapping(bytes32 => bool) public isSettled; - mapping(bytes32 => uint256) public commitTimes; - mapping(bytes32 => address) public intentMakers; - - constructor() EIP712("ZKRail", "1") {} + // Storage slots + mapping(bytes32 => IntentSolution) internal _solutions; + mapping(bytes32 => bool) internal _isSettled; + mapping(bytes32 => uint256) internal _commitTimes; + mapping(bytes32 => address) internal _intentMakers; /** - * @notice Hash an intent for EIP-712 signing - * @param intent The intent to hash - * @return The EIP-712 compatible hash of the intent + * @notice Initialize the base contract + * @dev Sets up EIP712 domain separator */ - function _hashIntent( - Intent calldata intent - ) internal pure returns (bytes32) { - return - keccak256( - abi.encode( - INTENT_TYPEHASH, - keccak256(bytes(intent.railType)), - keccak256(bytes(intent.recipientAddress)), - intent.railAmount - ) - ); - } + constructor() EIP712("ZKRail", "1") {} /** - * @notice Hash a complete solution for EIP-712 signing + * @notice Hash an intent solution for EIP-712 signing * @param solution The solution to hash * @return The EIP-712 compatible hash of the solution */ function _hashIntentSolution( IntentSolution calldata solution ) internal pure returns (bytes32) { - bytes32 intentHash = _hashIntent(solution.intent); - return keccak256( abi.encode( INTENT_SOLUTION_TYPEHASH, solution.intentId, - intentHash, + keccak256(bytes(solution.railType)), + keccak256(bytes(solution.recipientAddress)), + solution.railAmount, solution.paymentToken, solution.paymentAmount, solution.bondToken, @@ -82,68 +62,63 @@ abstract contract ZKRailBase is IZKRail, EIP712 { * @notice Verify an EIP-712 signature for a solution * @param solution The solution being verified * @param signature The signature to verify - * @return The recovered signer address + * @return signer The recovered signer address */ function _verifySolutionSignature( IntentSolution calldata solution, bytes calldata signature - ) internal view returns (address) { + ) internal view returns (address signer) { bytes32 digest = _hashTypedDataV4(_hashIntentSolution(solution)); - return ECDSA.recover(digest, signature); + signer = ECDSA.recover(digest, signature); + if (signer == address(0)) { + revert InvalidSignature(); + } } /** - * @notice Core implementation of solution commitment - * @param solution The solution being committed to - * @param signature The maker's signature + * @inheritdoc IZKRail */ function commitToSolution( IntentSolution calldata solution, bytes calldata signature ) external virtual { - // Verify caller is intent creator - require( - msg.sender == solution.intentCreator, - "Only intent creator can commit" - ); - require( - commitTimes[solution.intentId] == 0, - "Intent already committed" - ); - - // Verify signature and get maker address + // Validate caller and state + if (msg.sender != solution.intentCreator) { + revert UnauthorizedCaller(msg.sender, solution.intentCreator); + } + if (_commitTimes[solution.intentId] != 0) { + revert AlreadyCommitted(); + } + + // Verify signature and get maker address maker = _verifySolutionSignature(solution, signature); - require(maker != address(0), "Invalid signature"); - - // Store maker along with other intent data - intentMakers[solution.intentId] = maker; + _intentMakers[solution.intentId] = maker; - // Calculate and transfer total amount from taker + // Transfer from taker to contract (needs approval) uint256 totalTakerAmount = calculateTotalAmount(solution.paymentAmount); ERC20(solution.paymentToken).safeTransferFrom( msg.sender, address(this), totalTakerAmount ); - - // Transfer bond from maker ERC20(solution.bondToken).safeTransferFrom( maker, address(this), solution.bondAmount ); - // Store solution details - solutions[solution.intentId] = solution; - commitTimes[solution.intentId] = block.timestamp; + // Update state + _solutions[solution.intentId] = solution; + _commitTimes[solution.intentId] = block.timestamp; + // Emit event emit IntentSolutionCommitted( solution.intentId, maker, msg.sender, - solution.intent.railType, - solution.intent.recipientAddress, - solution.intent.railAmount, + solution.railType, + solution.recipientAddress, + solution.railAmount, solution.paymentToken, solution.paymentAmount, solution.bondToken, @@ -152,19 +127,16 @@ abstract contract ZKRailBase is IZKRail, EIP712 { } /** - * @notice Calculate total amount including collateral - * @param paymentAmount Base payment amount - * @return Total amount including collateral + * @inheritdoc IZKRail */ function calculateTotalAmount( uint256 paymentAmount - ) public view returns (uint256) { + ) public view virtual returns (uint256) { return (paymentAmount * _getCollateralPercentage()) / 100; } /** - * @notice Get full intent state - * @param intentId The intent to query + * @inheritdoc IZKRail */ function getIntentState( bytes32 intentId @@ -173,17 +145,51 @@ abstract contract ZKRailBase is IZKRail, EIP712 { view returns ( IntentSolution memory solution, - bool _isSettled, + bool isSettled, uint256 commitTime ) { return ( - solutions[intentId], - isSettled[intentId], - commitTimes[intentId] + _solutions[intentId], + _isSettled[intentId], + _commitTimes[intentId] ); } + /** + * @notice Check basic intent validity + * @param intentId The intent to validate + * @return maker The maker address if valid + */ + function _validateIntent( + bytes32 intentId + ) internal view returns (address maker) { + if (_commitTimes[intentId] == 0) { + revert IntentNotFound(); + } + if (_isSettled[intentId]) { + revert AlreadySettled(); + } + maker = _intentMakers[intentId]; + if (maker == address(0)) { + revert IntentNotFound(); + } + } + + /** + * @notice Check if current time is within valid window + * @param commitTime Time intent was committed + * @param window Time window to check + */ + function _validateTimeWindow( + uint256 commitTime, + uint256 window + ) internal view { + if (block.timestamp < commitTime + window) { + revert InvalidTimeWindow(block.timestamp, commitTime + window); + } + } + // Abstract functions to be implemented by specific rails function _getCollateralPercentage() internal pure virtual returns (uint256); @@ -196,7 +202,7 @@ abstract contract ZKRailBase is IZKRail, EIP712 { bytes calldata proof ) internal virtual returns (bool); - function DOMAIN_SEPARATOR() public view returns (bytes32) { + function DOMAIN_SEPARATOR() external view returns (bytes32) { return _domainSeparatorV4(); } } diff --git a/packages/foundry/contracts/interfaces/IZKRail.sol b/packages/foundry/contracts/interfaces/IZKRail.sol index a1696cd..03562c1 100644 --- a/packages/foundry/contracts/interfaces/IZKRail.sol +++ b/packages/foundry/contracts/interfaces/IZKRail.sol @@ -2,27 +2,17 @@ pragma solidity ^0.8.19; /** - * @title IZKRail Interface + * @title IZKRail * @notice Interface for ZKRail contracts that enable cross-rail token swaps with payment proofs * @dev Each rail (UPI, Bitcoin, etc.) implements this interface with its specific proof verification */ interface IZKRail { /** - * @notice Rail-specific payment details + * @notice Solution details for an intent including both rail and token details + * @param intentId Unique identifier for the intent * @param railType Type of payment rail (e.g., "UPI", "BITCOIN") * @param recipientAddress Recipient's address on the rail (e.g., UPI ID, BTC address) * @param railAmount Amount in rail's smallest unit (e.g., paise for INR, sats for BTC) - */ - struct Intent { - string railType; - string recipientAddress; - uint256 railAmount; - } - - /** - * @notice Complete solution including intent and token details - * @param intentId Unique identifier for the intent (generated off-chain) - * @param intent Rail-specific payment details * @param paymentToken Token that maker will receive * @param paymentAmount Amount of tokens maker will receive * @param bondToken Token used for maker's bond @@ -31,7 +21,9 @@ interface IZKRail { */ struct IntentSolution { bytes32 intentId; - Intent intent; + string railType; + string recipientAddress; + uint256 railAmount; address paymentToken; uint256 paymentAmount; address bondToken; @@ -40,17 +32,7 @@ interface IZKRail { } /** - * @notice Emitted when a solution is committed to an intent - * @param intentId Unique identifier for the intent - * @param maker Address that signed the solution - * @param taker Address that committed to the solution - * @param railType Type of payment rail - * @param recipientAddress Recipient's address on the rail - * @param railAmount Amount in rail's smallest unit - * @param paymentToken Token maker will receive - * @param paymentAmount Amount maker will receive - * @param bondToken Token used for maker's bond - * @param bondAmount Amount of maker's bond + * @notice Emitted when a solution is committed to with locked tokens */ event IntentSolutionCommitted( bytes32 indexed intentId, @@ -66,7 +48,7 @@ interface IZKRail { ); /** - * @notice Emitted when a payment proof is submitted + * @notice Emitted when a valid payment proof is submitted */ event PaymentProofSubmitted( bytes32 indexed intentId, @@ -74,7 +56,7 @@ interface IZKRail { ); /** - * @notice Emitted when a solution is settled normally + * @notice Emitted when a solution is settled normally by the taker */ event SolutionSettled(bytes32 indexed intentId, address indexed taker); @@ -86,11 +68,49 @@ interface IZKRail { address indexed triggeredBy ); + /** + * @notice Error thrown when operations are attempted on a non-existent intent + */ + error IntentNotFound(); + + /** + * @notice Error thrown when operations are attempted on an already settled intent + */ + error AlreadySettled(); + + /** + * @notice Error thrown when an intent has already been committed to + */ + error AlreadyCommitted(); + + /** + * @notice Error thrown when the caller is not authorized for an operation + * @param caller Address that attempted the operation + * @param required Address that is authorized + */ + error UnauthorizedCaller(address caller, address required); + + /** + * @notice Error thrown when attempting operations outside their time window + * @param currentTime Current block timestamp + * @param requiredTime Required timestamp + */ + error InvalidTimeWindow(uint256 currentTime, uint256 requiredTime); + + /** + * @notice Error thrown when a provided signature is invalid + */ + error InvalidSignature(); + + /** + * @notice Error thrown when a provided payment proof is invalid + */ + error InvalidProof(); + /** * @notice Commit to a solution by locking tokens - * @param solution The complete solution being committed to + * @param solution Complete solution details * @param signature EIP-712 signature from the maker - * @dev Requires appropriate token approvals for both payment and bond */ function commitToSolution( IntentSolution calldata solution, @@ -100,7 +120,6 @@ interface IZKRail { /** * @notice Settle a solution after successful off-chain payment * @param intentId The intent being settled - * @dev Only callable by the taker (intent creator) */ function settle(bytes32 intentId) external; @@ -108,21 +127,19 @@ interface IZKRail { * @notice Resolve a solution with a proof of payment * @param intentId The intent being resolved * @param proof Rail-specific proof of payment - * @dev Only callable by the maker after proof window and before timeout */ function resolveWithProof(bytes32 intentId, bytes calldata proof) external; /** * @notice Resolve by timeout if no settlement or proof was submitted * @param intentId The intent being resolved - * @dev Only callable by the taker after timeout window */ function resolveByTimeout(bytes32 intentId) external; /** * @notice Calculate total amount including collateral * @param paymentAmount Base payment amount - * @return Total amount taker needs to approve (payment + collateral) + * @return Total amount including collateral */ function calculateTotalAmount( uint256 paymentAmount @@ -131,7 +148,7 @@ interface IZKRail { /** * @notice Get the current state of an intent * @param intentId The intent to query - * @return solution The solution data + * @return solution The complete solution data * @return isSettled Whether the intent is settled * @return commitTime When the solution was committed */ @@ -145,4 +162,24 @@ interface IZKRail { bool isSettled, uint256 commitTime ); + + /** + * @notice Check if proof submission is currently possible + * @param intentId The intent to check + * @return canProve Whether proof can be submitted + * @return reasonCode Code indicating why proof cannot be submitted (0 if it can) + */ + function canSubmitProof( + bytes32 intentId + ) external view returns (bool canProve, uint8 reasonCode); + + /** + * @notice Check if timeout resolution is currently possible + * @param intentId The intent to check + * @return canTimeout Whether timeout can be triggered + * @return remainingTime Time until timeout is possible (0 if ready) + */ + function canTimeout( + bytes32 intentId + ) external view returns (bool canTimeout, uint256 remainingTime); } diff --git a/packages/foundry/contracts/rails/ZKRailUPI.sol b/packages/foundry/contracts/rails/ZKRailUPI.sol index c23f155..096bfbd 100644 --- a/packages/foundry/contracts/rails/ZKRailUPI.sol +++ b/packages/foundry/contracts/rails/ZKRailUPI.sol @@ -1,9 +1,10 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.19; -import {ZKRailBase} from "../ZKRailBase.sol"; -import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; +import {ERC20} from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {ZKRailBase} from "../ZKRailBase.sol"; +import {IZKRail} from "../interfaces/IZKRail.sol"; /** * @title ZKRailUPI @@ -19,8 +20,15 @@ contract ZKRailUPI is ZKRailBase { uint256 private constant TIMEOUT_WINDOW = 48 hours; /** - * @dev Amount of collateral required as percentage - * @return Collateral percentage (e.g., 150 for 150%) + * @notice Reason codes for why proof submission might fail + */ + uint8 private constant REASON_NOT_COMMITTED = 1; + uint8 private constant REASON_ALREADY_SETTLED = 2; + uint8 private constant REASON_TOO_EARLY = 3; + uint8 private constant REASON_TOO_LATE = 4; + + /** + * @inheritdoc ZKRailBase */ function _getCollateralPercentage() internal @@ -32,16 +40,14 @@ contract ZKRailUPI is ZKRailBase { } /** - * @dev Time window after which maker can submit proof - * @return Duration in seconds + * @inheritdoc ZKRailBase */ function _getProofWindow() internal pure override returns (uint256) { return PROOF_WINDOW; } /** - * @dev Time window after which taker can claim timeout - * @return Duration in seconds + * @inheritdoc ZKRailBase */ function _getTimeoutWindow() internal pure override returns (uint256) { return TIMEOUT_WINDOW; @@ -51,104 +57,98 @@ contract ZKRailUPI is ZKRailBase { * @notice Verify UPI payment proof using ZKFetch * @param intentId The intent being verified * @param proof ZKFetch bank statement proof - * @dev Verifies that the bank statement shows correct payment to recipient - * @return Whether the proof is valid + * @return verified Whether the proof is valid */ function _verifyPaymentProof( bytes32 intentId, bytes calldata proof - ) internal override returns (bool) { + ) internal override returns (bool verified) { // TODO: Implement integration with ZKFetch verifier // 1. Extract bank statement details from proof // 2. Verify proof against ZKFetch verifier contract // 3. Verify payment details match intent (amount, recipient UPI) // 4. Verify timestamp is within valid window - return true; + return true; // Temporary for testing } /** - * @notice Resolve intent with bank statement proof - * @param intentId The intent to resolve - * @param proof ZKFetch bank statement proof - * @dev Can only be called by maker after proof window and before timeout + * @inheritdoc IZKRail */ function resolveWithProof( bytes32 intentId, bytes calldata proof ) external override { - IntentSolution storage solution = solutions[intentId]; - require(commitTimes[intentId] != 0, "Intent not committed"); - require(!isSettled[intentId], "Already settled"); + // Validate basic state + address maker = _validateIntent(intentId); + if (msg.sender != maker) { + revert UnauthorizedCaller(msg.sender, maker); + } // Validate time windows - uint256 commitTime = commitTimes[intentId]; - require( - block.timestamp >= commitTime + PROOF_WINDOW, - "Too early for proof" - ); - require( - block.timestamp < commitTime + TIMEOUT_WINDOW, - "Proof window expired" - ); - - // Check caller is the original maker - address maker = intentMakers[intentId]; - require(maker != address(0), "Intent not committed"); - require(msg.sender == maker, "Only maker can resolve with proof"); - - require(_verifyPaymentProof(intentId, proof), "Invalid proof"); - + uint256 commitTime = _commitTimes[intentId]; + _validateTimeWindow(commitTime, PROOF_WINDOW); + if (block.timestamp >= commitTime + TIMEOUT_WINDOW) { + revert InvalidTimeWindow( + block.timestamp, + commitTime + TIMEOUT_WINDOW + ); + } + + // Verify the proof + if (!_verifyPaymentProof(intentId, proof)) { + revert InvalidProof(); + } + + IntentSolution storage solution = _solutions[intentId]; // Transfer all assets to maker uint256 totalAmount = calculateTotalAmount(solution.paymentAmount); ERC20(solution.paymentToken).safeTransfer(maker, totalAmount); ERC20(solution.bondToken).safeTransfer(maker, solution.bondAmount); - // Update state and emit event - isSettled[intentId] = true; + _isSettled[intentId] = true; emit PaymentProofSubmitted(intentId, maker); } /** - * @notice Settle intent normally - * @param intentId The intent to settle - * @dev Called by taker to settle after receiving UPI payment + * @inheritdoc IZKRail */ function settle(bytes32 intentId) external override { - IntentSolution storage solution = solutions[intentId]; - require(msg.sender == solution.intentCreator, "Only taker can settle"); - require(!isSettled[intentId], "Already settled"); + // Validate basic state + address maker = _validateIntent(intentId); + IntentSolution storage solution = _solutions[intentId]; - address maker = intentMakers[intentId]; // Get stored maker address - require(maker != address(0), "Intent not committed"); + if (msg.sender != solution.intentCreator) { + revert UnauthorizedCaller(msg.sender, solution.intentCreator); + } - // Return collateral to taker (50% of payment amount) + // Calculate amounts and transfer uint256 collateralAmount = (solution.paymentAmount * 50) / 100; + // Use transfer instead of safeTransferFrom since we're sending from contract + // Direct transfer from contract ERC20(solution.paymentToken).safeTransfer( solution.intentCreator, collateralAmount ); - - // Return bond to maker ERC20(solution.bondToken).safeTransfer(maker, solution.bondAmount); - // Update state and emit event - isSettled[intentId] = true; + _isSettled[intentId] = true; emit SolutionSettled(intentId, msg.sender); } /** - * @notice Emergency resolution after timeout - * @param intentId The intent to resolve - * @dev Can be called by taker after timeout window to claim all assets + * @inheritdoc IZKRail */ function resolveByTimeout(bytes32 intentId) external override { - IntentSolution storage solution = solutions[intentId]; - require(msg.sender == solution.intentCreator, "Only taker can timeout"); - require(!isSettled[intentId], "Already settled"); - require( - block.timestamp >= commitTimes[intentId] + TIMEOUT_WINDOW, - "Too early for timeout" - ); + // Validate basic state + _validateIntent(intentId); + IntentSolution storage solution = _solutions[intentId]; + + if (msg.sender != solution.intentCreator) { + revert UnauthorizedCaller(msg.sender, solution.intentCreator); + } + + // Validate timeout window + _validateTimeWindow(_commitTimes[intentId], TIMEOUT_WINDOW); // Transfer all assets to taker uint256 totalAmount = calculateTotalAmount(solution.paymentAmount); @@ -161,44 +161,42 @@ contract ZKRailUPI is ZKRailBase { solution.bondAmount ); - // Update state and emit event - isSettled[intentId] = true; + _isSettled[intentId] = true; emit EmergencyTimeoutTriggered(intentId, msg.sender); } /** - * @notice Check if a solution can be proven - * @param intentId The intent to check - * @return canProve Whether proof can be submitted now - * @return reason Reason code if cannot prove (0 if can prove) + * @inheritdoc IZKRail */ function canSubmitProof( bytes32 intentId - ) external view returns (bool canProve, uint8 reason) { - if (commitTimes[intentId] == 0) return (false, 1); // Not committed - if (isSettled[intentId]) return (false, 2); // Already settled + ) external view returns (bool canProve, uint8 reasonCode) { + if (_commitTimes[intentId] == 0) return (false, REASON_NOT_COMMITTED); + if (_isSettled[intentId]) return (false, REASON_ALREADY_SETTLED); - uint256 commitTime = commitTimes[intentId]; - if (block.timestamp < commitTime + PROOF_WINDOW) return (false, 3); // Too early - if (block.timestamp >= commitTime + TIMEOUT_WINDOW) return (false, 4); // Too late + uint256 commitTime = _commitTimes[intentId]; + if (block.timestamp < commitTime + PROOF_WINDOW) + return (false, REASON_TOO_EARLY); + if (block.timestamp >= commitTime + TIMEOUT_WINDOW) + return (false, REASON_TOO_LATE); return (true, 0); } /** - * @notice Check if a timeout can be triggered - * @param intentId The intent to check - * @return canTimeout Whether timeout can be triggered - * @return remainingTime Time until timeout can be triggered (0 if ready) + * @inheritdoc IZKRail */ function canTimeout( bytes32 intentId ) external view returns (bool canTimeout, uint256 remainingTime) { - if (commitTimes[intentId] == 0 || isSettled[intentId]) + if (_commitTimes[intentId] == 0 || _isSettled[intentId]) { return (false, 0); + } - uint256 timeoutTime = commitTimes[intentId] + TIMEOUT_WINDOW; - if (block.timestamp >= timeoutTime) return (true, 0); + uint256 timeoutTime = _commitTimes[intentId] + TIMEOUT_WINDOW; + if (block.timestamp >= timeoutTime) { + return (true, 0); + } return (false, timeoutTime - block.timestamp); } diff --git a/packages/foundry/contracts/test/ZKRailUPI.t.sol b/packages/foundry/contracts/test/ZKRailUPI.t.sol new file mode 100644 index 0000000..a01c846 --- /dev/null +++ b/packages/foundry/contracts/test/ZKRailUPI.t.sol @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; + +import "forge-std/Test.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import "../contracts/rails/ZKRailUPI.sol"; + +contract MockToken is ERC20 { + constructor(string memory name, string memory symbol) ERC20(name, symbol) {} + + function mint(address to, uint256 amount) external { + _mint(to, amount); + } +} + +contract ZKRailUPITest is Test { + ZKRailUPI public zkRail; + MockToken public paymentToken; + MockToken public bondToken; + + address public constant MAKER = 0x476C88ED464EFD251a8b18Eb84785F7C46807873; + address public taker = address(0x2); + uint256 public makerKey = 0x123; // Private key for maker + + bytes32 public constant INTENT_ID = keccak256("test-intent-1"); + + function setUp() public { + // Deploy contracts + zkRail = new ZKRailUPI(); + paymentToken = new MockToken("Payment Token", "PAY"); + bondToken = new MockToken("Bond Token", "BOND"); + + // Setup test accounts + vm.deal(MAKER, 100 ether); + vm.deal(taker, 100 ether); + + // Mint tokens + paymentToken.mint(taker, 1000 ether); + bondToken.mint(MAKER, 1000 ether); + + // Approve tokens + vm.startPrank(taker); + paymentToken.approve(address(zkRail), type(uint256).max); + vm.stopPrank(); + + vm.startPrank(MAKER); + bondToken.approve(address(zkRail), type(uint256).max); + vm.stopPrank(); + + // Log addresses for debugging + console.log("Payment Token address:", address(paymentToken)); + console.log("Bond Token address:", address(bondToken)); + console.log("ZKRail address:", address(zkRail)); + } + + function testHappyPath() public { + // Create solution + IZKRail.IntentSolution memory solution = IZKRail.IntentSolution({ + intentId: INTENT_ID, + railType: "UPI", + recipientAddress: "maker@upi", + railAmount: 1000, + paymentToken: address(paymentToken), + paymentAmount: 100 ether, + bondToken: address(bondToken), + bondAmount: 10 ether, + intentCreator: taker + }); + + // Sign solution as maker + bytes32 domainSeparator = zkRail.DOMAIN_SEPARATOR(); + bytes32 typeHash = zkRail.INTENT_SOLUTION_TYPEHASH(); + + bytes32 structHash = keccak256( + abi.encode( + typeHash, + solution.intentId, + keccak256(bytes(solution.railType)), + keccak256(bytes(solution.recipientAddress)), + solution.railAmount, + solution.paymentToken, + solution.paymentAmount, + solution.bondToken, + solution.bondAmount, + solution.intentCreator + ) + ); + + bytes32 digest = keccak256( + abi.encodePacked("\x19\x01", domainSeparator, structHash) + ); + + (uint8 v, bytes32 r, bytes32 s) = vm.sign(makerKey, digest); + bytes memory signature = abi.encodePacked(r, s, v); + + // Record initial balances + uint256 takerPaymentInitial = paymentToken.balanceOf(taker); + uint256 makerBondInitial = bondToken.balanceOf(MAKER); + + // Step 1: Commit to solution + vm.prank(taker); + zkRail.commitToSolution(solution, signature); + + // Verify tokens locked + uint256 totalPayment = zkRail.calculateTotalAmount( + solution.paymentAmount + ); + assertEq( + paymentToken.balanceOf(taker), + takerPaymentInitial - totalPayment + ); + assertEq( + bondToken.balanceOf(MAKER), + makerBondInitial - solution.bondAmount + ); + assertEq(paymentToken.balanceOf(address(zkRail)), totalPayment); + assertEq(bondToken.balanceOf(address(zkRail)), solution.bondAmount); + + // Step 2: Settle after off-chain payment + vm.prank(taker); + zkRail.settle(INTENT_ID); + + // Verify final balances + uint256 collateral = (solution.paymentAmount * 50) / 100; // 50% collateral returned to taker + assertEq( + paymentToken.balanceOf(taker), + takerPaymentInitial - solution.paymentAmount + ); + assertEq(bondToken.balanceOf(MAKER), makerBondInitial); + + // Verify settlement state + ( + IZKRail.IntentSolution memory storedSolution, + bool isSettled, + uint256 commitTime + ) = zkRail.getIntentState(INTENT_ID); + + assertTrue(isSettled); + assertEq(commitTime > 0, true); + assertEq(storedSolution.intentId, solution.intentId); + } + + function testCannotSettleTwice() public { + // Setup and commit solution + testHappyPath(); + + // Try to settle again + vm.prank(taker); + vm.expectRevert(IZKRail.AlreadySettled.selector); + zkRail.settle(INTENT_ID); + } +} diff --git a/packages/foundry/script/Deploy.s.sol b/packages/foundry/script/Deploy.s.sol index b64aad9..6618453 100644 --- a/packages/foundry/script/Deploy.s.sol +++ b/packages/foundry/script/Deploy.s.sol @@ -1,31 +1,22 @@ -pragma solidity ^0.8.20; +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.19; import "forge-std/Script.sol"; import "../contracts/rails/ZKRailUPI.sol"; -import "@openzeppelin/contracts/utils/Create2.sol"; contract DeployZKRail is Script { - bytes32 public constant SALT = bytes32(uint256(0x1234)); - // OpenZeppelin's Create2 Deployer address (same on all chains) - address constant CREATE2_DEPLOYER = - 0x4e59b44847b379578588920cA78FbF26c0B4956C; - function run() external { + // Retrieve private key from environment uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); + + // Start broadcasting transactions vm.startBroadcast(deployerPrivateKey); - // Compute the deployment address - bytes memory creationCode = type(ZKRailUPI).creationCode; - address computedAddress = Create2.computeAddress( - SALT, - keccak256(creationCode), - CREATE2_DEPLOYER - ); - console.log("Computed deployment address:", computedAddress); - - address token = Create2.deploy(0, SALT, creationCode); - require(token == computedAddress, "Deployment address mismatch"); + // Deploy ZKRailUPI + ZKRailUPI zkRail = new ZKRailUPI(); + + console.log("ZKRailUPI deployed to:", address(zkRail)); vm.stopBroadcast(); } -} +} \ No newline at end of file diff --git a/packages/foundry/test/.gitkeep b/packages/foundry/test/.gitkeep deleted file mode 100644 index 073c054..0000000 --- a/packages/foundry/test/.gitkeep +++ /dev/null @@ -1,2 +0,0 @@ -# Write tests for your smart contract in this directory -# Example: YourContract.t.sol diff --git a/packages/foundry/test/ZKRailUPI.t.sol b/packages/foundry/test/ZKRailUPI.t.sol deleted file mode 100644 index d827537..0000000 --- a/packages/foundry/test/ZKRailUPI.t.sol +++ /dev/null @@ -1,154 +0,0 @@ -pragma solidity ^0.8.19; - -import "forge-std/Test.sol"; -import "./helpers/TestZKRailUPI.sol"; -import "../contracts/interfaces/IZKRail.sol"; -import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; - -contract MockERC20 is ERC20 { - constructor(string memory name, string memory symbol) ERC20(name, symbol) {} - - function mint(address to, uint256 amount) external { - _mint(to, amount); - } -} - -contract ZKRailUPITest is Test { - TestZKRailUPI public zkRail; - MockERC20 public paymentToken; - MockERC20 public bondToken; - - address maker; - uint256 makerPrivateKey; - address taker; - - function setUp() public { - // Generate maker address and private key - makerPrivateKey = 0xA11CE; // Example private key - maker = vm.addr(makerPrivateKey); - taker = address(0x2); - - // Deploy contracts - zkRail = new TestZKRailUPI(); - paymentToken = new MockERC20("Payment", "PAY"); - bondToken = new MockERC20("Bond", "BOND"); - - // Setup maker and taker with tokens - paymentToken.mint(taker, 1000e18); - bondToken.mint(maker, 1000e18); - - vm.label(maker, "Maker"); - vm.label(taker, "Taker"); - } - - function createSignedSolution( - address _maker, - address _taker, - uint256 paymentAmount - ) - public - returns (IZKRail.IntentSolution memory solution, bytes memory signature) - { - // Create intent - IZKRail.Intent memory intent = IZKRail.Intent({ - railType: "UPI", - recipientAddress: "test@upi", - railAmount: 1000 // 10.00 INR in paise - }); - - // Generate intentId (this would normally come from indexer) - bytes32 intentId = keccak256( - abi.encodePacked( - intent.railType, - intent.recipientAddress, - intent.railAmount, - block.timestamp - ) - ); - - // Create solution - solution = IZKRail.IntentSolution({ - intentId: intentId, - intent: intent, - paymentToken: address(paymentToken), - paymentAmount: paymentAmount, - bondToken: address(bondToken), - bondAmount: 500 * 10 ** 18, // 500 tokens - intentCreator: _taker - }); - - // Sign solution as maker - bytes32 structHash = zkRail.hashIntentSolution(solution); - bytes32 digest = zkRail.DOMAIN_SEPARATOR(); // Note this change too - digest = keccak256(abi.encodePacked("\x19\x01", digest, structHash)); - - (uint8 v, bytes32 r, bytes32 s) = vm.sign(makerPrivateKey, digest); - signature = abi.encodePacked(r, s, v); - - return (solution, signature); - } - - function testHappyPathFlow() public { - uint256 paymentAmount = 100 * 10 ** 18; // 100 tokens - - // Get initial balances - uint256 initialTakerPaymentBalance = paymentToken.balanceOf(taker); - uint256 initialMakerBondBalance = bondToken.balanceOf(maker); - - // Create and sign solution as maker - ( - IZKRail.IntentSolution memory solution, - bytes memory signature - ) = createSignedSolution(maker, taker, paymentAmount); - - // Approve tokens - vm.startPrank(taker); - paymentToken.approve(address(zkRail), type(uint256).max); - vm.stopPrank(); - - vm.startPrank(maker); - bondToken.approve(address(zkRail), type(uint256).max); - vm.stopPrank(); - - // Commit to solution as taker - vm.startPrank(taker); - zkRail.commitToSolution(solution, signature); - vm.stopPrank(); - - // Check balances after commitment - uint256 requiredTakerAmount = zkRail.calculateTotalAmount( - paymentAmount - ); - assertEq( - paymentToken.balanceOf(taker), - initialTakerPaymentBalance - requiredTakerAmount, - "Incorrect taker payment deduction" - ); - assertEq( - bondToken.balanceOf(maker), - initialMakerBondBalance - solution.bondAmount, - "Incorrect maker bond deduction" - ); - - // Settle as taker - vm.startPrank(taker); - zkRail.settle(solution.intentId); - vm.stopPrank(); - - // Check final balances - // Taker should get collateral back (50% of payment) - uint256 collateralAmount = (paymentAmount * 50) / 100; - assertEq( - paymentToken.balanceOf(taker), - initialTakerPaymentBalance - paymentAmount, - "Incorrect final taker balance" - ); - - // Maker should get bond back - assertEq( - bondToken.balanceOf(maker), - initialMakerBondBalance, - "Maker should get full bond back" - ); - } -} diff --git a/packages/foundry/test/helpers/TestZKRailUPI.sol b/packages/foundry/test/helpers/TestZKRailUPI.sol deleted file mode 100644 index 65a4f4f..0000000 --- a/packages/foundry/test/helpers/TestZKRailUPI.sol +++ /dev/null @@ -1,19 +0,0 @@ -// test/helpers/TestZKRailUPI.sol -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.19; - -import "../../contracts/rails/ZKRailUPI.sol"; - -contract TestZKRailUPI is ZKRailUPI { - function hashIntentSolution( - IntentSolution calldata solution - ) external pure returns (bytes32) { - return _hashIntentSolution(solution); - } - - function hashIntent( - Intent calldata intent - ) external pure returns (bytes32) { - return _hashIntent(intent); - } -} diff --git a/packages/intent-aggregator/migrations/0002_outstanding_vector.sql b/packages/intent-aggregator/migrations/0002_outstanding_vector.sql new file mode 100644 index 0000000..313a6eb --- /dev/null +++ b/packages/intent-aggregator/migrations/0002_outstanding_vector.sql @@ -0,0 +1 @@ +ALTER TABLE `intents` DROP COLUMN `payment_token_amount`; \ No newline at end of file diff --git a/packages/intent-aggregator/migrations/meta/0002_snapshot.json b/packages/intent-aggregator/migrations/meta/0002_snapshot.json new file mode 100644 index 0000000..99bf7f4 --- /dev/null +++ b/packages/intent-aggregator/migrations/meta/0002_snapshot.json @@ -0,0 +1,239 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "cd4faace-9877-4a01-befd-774569391bb8", + "prevId": "f3fbab36-02e8-413c-8991-deca90e9a2c0", + "tables": { + "intents": { + "name": "intents", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "payment_token": { + "name": "payment_token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "rail_type": { + "name": "rail_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "recipient_address": { + "name": "recipient_address", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "rail_amount": { + "name": "rail_amount", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "creator_address": { + "name": "creator_address", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "chain_id": { + "name": "chain_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "state": { + "name": "state", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'CREATED'" + }, + "winning_solution_id": { + "name": "winning_solution_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "resolution_tx_hash": { + "name": "resolution_tx_hash", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "creator_idx": { + "name": "creator_idx", + "columns": [ + "creator_address" + ], + "isUnique": false + }, + "state_idx": { + "name": "state_idx", + "columns": [ + "state" + ], + "isUnique": false + }, + "rail_idx": { + "name": "rail_idx", + "columns": [ + "rail_type" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "solutions": { + "name": "solutions", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "intent_id": { + "name": "intent_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "solver_address": { + "name": "solver_address", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "amount_wei": { + "name": "amount_wei", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "signature": { + "name": "signature", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "CURRENT_TIMESTAMP" + }, + "commitment_tx_hash": { + "name": "commitment_tx_hash", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "settlement_tx_hash": { + "name": "settlement_tx_hash", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "resolution_tx_hash": { + "name": "resolution_tx_hash", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "payment_metadata": { + "name": "payment_metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "intent_solutions_idx": { + "name": "intent_solutions_idx", + "columns": [ + "intent_id" + ], + "isUnique": false + }, + "solver_idx": { + "name": "solver_idx", + "columns": [ + "solver_address" + ], + "isUnique": false + } + }, + "foreignKeys": { + "solutions_intent_id_intents_id_fk": { + "name": "solutions_intent_id_intents_id_fk", + "tableFrom": "solutions", + "tableTo": "intents", + "columnsFrom": [ + "intent_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/packages/intent-aggregator/migrations/meta/_journal.json b/packages/intent-aggregator/migrations/meta/_journal.json index 50db088..ad89f50 100644 --- a/packages/intent-aggregator/migrations/meta/_journal.json +++ b/packages/intent-aggregator/migrations/meta/_journal.json @@ -15,6 +15,13 @@ "when": 1733551783982, "tag": "0001_dazzling_deathstrike", "breakpoints": true + }, + { + "idx": 2, + "version": "6", + "when": 1733579347394, + "tag": "0002_outstanding_vector", + "breakpoints": true } ] } \ No newline at end of file diff --git a/packages/intent-aggregator/src/db/schema/index.ts b/packages/intent-aggregator/src/db/schema/index.ts index 42d10ce..1f37446 100644 --- a/packages/intent-aggregator/src/db/schema/index.ts +++ b/packages/intent-aggregator/src/db/schema/index.ts @@ -35,7 +35,6 @@ export const intents = sqliteTable( { id: text("id").primaryKey(), paymentToken: text("payment_token").notNull(), - paymentTokenAmount: text("payment_token_amount").notNull(), railType: text("rail_type").notNull().$type(), recipientAddress: text("recipient_address").notNull(), @@ -60,6 +59,13 @@ export const intents = sqliteTable( }) ); +export const intentsRelations = relations(intents, ({ one }) => ({ + winningSolution: one(solutions, { + fields: [intents.winningSolutionId], + references: [solutions.id], + }), +})); + export const solutions = sqliteTable( "solutions", { @@ -78,7 +84,7 @@ export const solutions = sqliteTable( .default(sql`CURRENT_TIMESTAMP`), commitmentTxHash: text("commitment_tx_hash"), - + // Settlement is the optimistic path settlementTxHash: text("settlement_tx_hash"), diff --git a/packages/intent-aggregator/src/index.ts b/packages/intent-aggregator/src/index.ts index f6969e1..45a52c6 100644 --- a/packages/intent-aggregator/src/index.ts +++ b/packages/intent-aggregator/src/index.ts @@ -12,7 +12,7 @@ import { dbMiddleware } from "./db/middleware"; import { intents, solutions } from "./db/schema"; import { createSelectSchema } from "drizzle-zod"; import { apiReference } from "@scalar/hono-api-reference"; -import { eq } from "drizzle-orm"; +import { desc, eq } from "drizzle-orm"; const api = new OpenAPIHono(); // Create Intent @@ -57,6 +57,33 @@ api.openapi(createIntent, async (c) => { return c.json({ intentId: intent.id }); }); +const getIntents = createRoute({ + method: "get", + path: "/api/intents", + responses: { + 200: { + content: { + "application/json": { + schema: z.object({ + intents: z.array(createSelectSchema(intents)), + }), + }, + }, + description: "Intents retrieved successfully", + }, + }, +}); + +api.openapi(getIntents, async (c) => { + const receivedIntents = await c.var.db.query.intents.findMany({ + with: { + winningSolution: true, + }, + orderBy: desc(intents.createdAt), + }); + return c.json({ intents: receivedIntents }); +}); + // Get Intent const getIntent = createRoute({ method: "get", diff --git a/packages/intent-aggregator/src/schemas.ts b/packages/intent-aggregator/src/schemas.ts index f5cb0fa..b3695a9 100644 --- a/packages/intent-aggregator/src/schemas.ts +++ b/packages/intent-aggregator/src/schemas.ts @@ -27,7 +27,6 @@ const chainIdSchema = z.number().int().positive(); // Request schemas export const CreateIntentSchema = z.object({ paymentToken: addressSchema, - paymentTokenAmount: tokenAmountSchema, railType: railTypeSchema, recipientAddress: z.string(), // Different validation per rail type railAmount: tokenAmountSchema, diff --git a/packages/upi-maker/.env b/packages/upi-maker/.env new file mode 100644 index 0000000..ce17dda --- /dev/null +++ b/packages/upi-maker/.env @@ -0,0 +1 @@ +VITE_THIRDWEB_CLIENT_ID=9ecccaf4581f172262d9f7d9d6814ad4 \ No newline at end of file diff --git a/packages/upi-maker/.gitignore b/packages/upi-maker/.gitignore new file mode 100644 index 0000000..ed335a7 --- /dev/null +++ b/packages/upi-maker/.gitignore @@ -0,0 +1,18 @@ +# Local +.DS_Store +*.local +*.log* + +# Dist +node_modules +dist/ +.vinxi +.output +.vercel +.netlify +.wrangler + +# IDE +.vscode/* +!.vscode/extensions.json +.idea diff --git a/packages/upi-maker/components.json b/packages/upi-maker/components.json new file mode 100644 index 0000000..1d282e6 --- /dev/null +++ b/packages/upi-maker/components.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "tailwind.config.js", + "css": "src/index.css", + "baseColor": "neutral", + "cssVariables": true, + "prefix": "" + }, + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "iconLibrary": "lucide" +} \ No newline at end of file diff --git a/packages/upi-maker/index.html b/packages/upi-maker/index.html new file mode 100644 index 0000000..d93394e --- /dev/null +++ b/packages/upi-maker/index.html @@ -0,0 +1,25 @@ + + + + + + zkRail UPI | intent solver network + + + + + +
+ + + diff --git a/packages/upi-maker/package.json b/packages/upi-maker/package.json new file mode 100644 index 0000000..2bb908d --- /dev/null +++ b/packages/upi-maker/package.json @@ -0,0 +1,44 @@ +{ + "name": "upi-maker", + "version": "0.0.0", + "private": true, + "type": "module", + "scripts": { + "typecheck": "tsc --noEmit", + "dev": "vite --port=3001", + "build": "vite build", + "serve": "vite preview", + "start": "vite" + }, + "devDependencies": { + "@tanstack/router-plugin": "^1.86.0", + "@types/node": "^22.10.1", + "@types/react": "^18.3.3", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^4.3.2", + "autoprefixer": "^10.4.20", + "postcss": "^8.4.49", + "tailwindcss": "^3.4.16", + "vite": "^6.0.3" + }, + "dependencies": { + "@radix-ui/react-label": "^2.1.0", + "@radix-ui/react-scroll-area": "^1.2.1", + "@radix-ui/react-slot": "^1.1.0", + "@tanstack/react-query": "^5.62.3", + "@tanstack/react-router": "^1.86.0", + "@tanstack/router-devtools": "^1.86.0", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "ky": "^1.7.2", + "lucide-react": "^0.468.0", + "next-themes": "^0.4.4", + "react": "^18.3.1", + "react-dom": "^18.3.1", + "sonner": "^1.7.0", + "tailwind-merge": "^2.5.5", + "tailwindcss-animate": "^1.0.7", + "thirdweb": "^5.74.0", + "viem": "^2.21.54" + } +} \ No newline at end of file diff --git a/packages/upi-maker/postcss.config.js b/packages/upi-maker/postcss.config.js new file mode 100644 index 0000000..2e7af2b --- /dev/null +++ b/packages/upi-maker/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/packages/upi-maker/src/client.ts b/packages/upi-maker/src/client.ts new file mode 100644 index 0000000..20d20e6 --- /dev/null +++ b/packages/upi-maker/src/client.ts @@ -0,0 +1,5 @@ +import { createThirdwebClient } from "thirdweb"; + +export const client = createThirdwebClient({ + clientId: import.meta.env.VITE_THIRDWEB_CLIENT_ID, +}); diff --git a/packages/upi-maker/src/components/intent-details.tsx b/packages/upi-maker/src/components/intent-details.tsx new file mode 100644 index 0000000..6c58100 --- /dev/null +++ b/packages/upi-maker/src/components/intent-details.tsx @@ -0,0 +1,266 @@ +import { useState } from 'react' +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import { Button } from "@/components/ui/button" +import { Loader2, CheckCircle } from 'lucide-react' +import { toast } from "sonner" +import { intentQueryOptions } from '@/queries/intent' +import { useMutation, useQuery } from '@tanstack/react-query' +import { Skeleton } from './ui/skeleton' +import { useActiveAccount } from 'thirdweb/react' +import { keccak256, toBytes, toUnits, toWei, toTokens } from 'thirdweb' +import { baseSepolia } from 'thirdweb/chains' +import { intentAggregatorApi } from '@/queries/conts' +import { solutionsQuery, solutionsQueryOptions } from '@/queries/solutions' + +// EIP-712 Type Definitions +const DOMAIN = { + name: 'ZKRail', + version: '1', + chainId: 84532, + verifyingContract: '0x926B9bD1905CfeC995B0955DE7392bEdECE2FDC9', // ZKRailUPI contract address +} as const + +const TYPES = { + IntentSolution: [ + { name: 'intentId', type: 'bytes32' }, + { name: 'railType', type: 'string' }, + { name: 'recipientAddress', type: 'string' }, + { name: 'railAmount', type: 'uint256' }, + { name: 'paymentToken', type: 'address' }, + { name: 'paymentAmount', type: 'uint256' }, + { name: 'bondToken', type: 'address' }, + { name: 'bondAmount', type: 'uint256' }, + { name: 'intentCreator', type: 'address' } + ] +} as const + +function intentIdToBytes32(intentId: string): `0x${string}` { + // If already hex + if (intentId.startsWith('0x')) { + return intentId as `0x${string}` + } + // If base58/UUID style, hash it + return keccak256(toBytes(intentId)) as `0x${string}` +} + +type IntentMutationArgs = { + solverAddress: string, + amountWei: bigint, + signature: string +} + +export function IntentDetails({ intentId }: { intentId: string }) { + const [quoteAmount, setQuoteAmount] = useState('') + const intentQuery = useQuery(intentQueryOptions(intentId)); + const solutionsQuery = useQuery(solutionsQueryOptions(intentId)); + + const account = useActiveAccount(); + + const mySolution = solutionsQuery.data?.find((solution) => solution.solverAddress === account?.address); + const loading = intentQuery.isLoading; + const intent = intentQuery.data; + + const submitIntentMutation = useMutation({ + mutationFn: async (args: IntentMutationArgs) => { + await intentAggregatorApi.post(`intents/${intentId}/solutions`, { + json: { + solverAddress: args.solverAddress, + amountWei: args.amountWei.toString(), + signature: args.signature + } + }) + + intentQuery.refetch(); + } + }) + + const handleSubmit = async () => { + if (!account) { + toast.error("Please connect your wallet to submit the solution"); + return; + } + + if (!intent) { + toast.error("Intent not found"); + return; + } + + const solution = { + intentId: intentIdToBytes32(intentId), + railType: intent.railType, + recipientAddress: intent.recipientAddress, + railAmount: BigInt(intent.railAmount), + paymentToken: intent.paymentToken, + paymentAmount: toUnits(parseFloat(quoteAmount).toString(), 6), + bondToken: intent.paymentToken, + bondAmount: toUnits("500", 6), + intentCreator: intent.creatorAddress + }; + + console.log(solution); + + // Sign the solution + const signature = await account.signTypedData({ + types: TYPES, + domain: DOMAIN, + primaryType: 'IntentSolution', + // @ts-ignore + message: solution + }) + + console.log(signature); + console.log(solution); + console.log(intentIdToBytes32(intentId)); + + await submitIntentMutation.mutateAsync({ + amountWei: toUnits(parseFloat(quoteAmount).toString(), 6), + signature, + solverAddress: account.address + }); + + toast.promise( + new Promise((resolve) => setTimeout(resolve, 2000)), + { + loading: 'Submitting solution...', + success: 'Solution submitted successfully!', + error: 'Failed to submit solution', + } + ) + } + + const handlePaymentConfirmation = () => { + toast.success("Payment confirmation received. Awaiting settlement.") + } + + if (loading) { + return ( +
+ + + + + + + + +
+ + + + +
+ +
+
+ + + + + + + +
+ ) + } + + if (!intent) { + return
Intent not found
+ } + + return ( +
+

Intent Details + {intent.id} {intent.state} +

+ + + Payment Details + Review the payment details and submit your solution + + + {intent.state === "SOLUTION_COMMITTED" && ( +
+
+ QR Code Stub +
+
+ )} +
+
+ +
+ {intent.railType === "UPI" ? "₹" : ""} + {(parseInt(intent.railAmount) / 100).toLocaleString('en-IN')} +
+
{intent.recipientAddress}
+
+
+ + {(intent.state === "CREATED" && !mySolution) ? ( + setQuoteAmount(e.target.value)} + /> + ) : ( +
+ {intent.winningSolution?.amountWei ?? (mySolution?.amountWei ? toTokens(BigInt(mySolution.amountWei), 6) : undefined)} {intent.paymentToken} +
+ )} +
+
+
+ Polygon Logo + Payment will be received on Polygon +
+ {intent.state === "CREATED" && ( + + )} + {intent.state === "SOLUTION_COMMITTED" && ( +
+
+

Your solution was accepted. 500 USDC has been locked as bond.

+

+ Transaction Hash: {intent.winningSolution?.commitmentTxHash} +

+
+ +
+ )} +
+
+ + +

+ If your solution is accepted, 500 USDC will be locked as bond to ensure you complete the payment. In case the payment is not received, the bond amount will be lost. +

+

+ Once the payment is made and the transaction is settled by the taker, the bond will be refunded to you. +

+

+ In case the UPI transaction is made by you, but the transaction is maliciously not settled by the taker, then you can generate a zkproof and submit it on chain, which will refund the bond, and also pay you the original USDC amount from the taker plus a 50% collateral as compensation for the inconvenience caused. +

+
+
+
+ ) +} \ No newline at end of file diff --git a/packages/upi-maker/src/components/intents-list.tsx b/packages/upi-maker/src/components/intents-list.tsx new file mode 100644 index 0000000..ab43429 --- /dev/null +++ b/packages/upi-maker/src/components/intents-list.tsx @@ -0,0 +1,51 @@ +import { intentsQueryOptions } from "@/queries/intents"; +import { ScrollArea } from "./ui/scroll-area"; +import { useQuery } from "@tanstack/react-query"; +import { CheckCircle, Loader2 } from 'lucide-react' +import { Skeleton } from "./ui/skeleton"; +import { d1DateStringToLocaleString } from "@/queries/utils"; + +export function IntentsList({ + onSelectIntent, +}: { + onSelectIntent: (intentId: string) => void; +}) { + const intentsQuery = useQuery({ ...intentsQueryOptions, refetchInterval: 5000 }); + const intents = intentsQuery.data ?? []; + + const skeletonsArray = Array.from({ length: 20 }).fill(null); + + return ( + +

Intents

+
+
+ { + intentsQuery.isLoading && skeletonsArray.map((_, index) => ( + + )) + } + {intents.map((intent) => ( + + ))} +
+
+
+ ) +} diff --git a/packages/upi-maker/src/components/ui/button.tsx b/packages/upi-maker/src/components/ui/button.tsx new file mode 100644 index 0000000..65d4fcd --- /dev/null +++ b/packages/upi-maker/src/components/ui/button.tsx @@ -0,0 +1,57 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", + { + variants: { + variant: { + default: + "bg-primary text-primary-foreground shadow hover:bg-primary/90", + destructive: + "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90", + outline: + "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground", + secondary: + "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-9 px-4 py-2", + sm: "h-8 rounded-md px-3 text-xs", + lg: "h-10 rounded-md px-8", + icon: "h-9 w-9", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +) + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean +} + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button" + return ( + + ) + } +) +Button.displayName = "Button" + +export { Button, buttonVariants } diff --git a/packages/upi-maker/src/components/ui/card.tsx b/packages/upi-maker/src/components/ui/card.tsx new file mode 100644 index 0000000..cabfbfc --- /dev/null +++ b/packages/upi-maker/src/components/ui/card.tsx @@ -0,0 +1,76 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +const Card = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +Card.displayName = "Card" + +const CardHeader = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardHeader.displayName = "CardHeader" + +const CardTitle = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardTitle.displayName = "CardTitle" + +const CardDescription = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardDescription.displayName = "CardDescription" + +const CardContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardContent.displayName = "CardContent" + +const CardFooter = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)) +CardFooter.displayName = "CardFooter" + +export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } diff --git a/packages/upi-maker/src/components/ui/input.tsx b/packages/upi-maker/src/components/ui/input.tsx new file mode 100644 index 0000000..69b64fb --- /dev/null +++ b/packages/upi-maker/src/components/ui/input.tsx @@ -0,0 +1,22 @@ +import * as React from "react" + +import { cn } from "@/lib/utils" + +const Input = React.forwardRef>( + ({ className, type, ...props }, ref) => { + return ( + + ) + } +) +Input.displayName = "Input" + +export { Input } diff --git a/packages/upi-maker/src/components/ui/label.tsx b/packages/upi-maker/src/components/ui/label.tsx new file mode 100644 index 0000000..683faa7 --- /dev/null +++ b/packages/upi-maker/src/components/ui/label.tsx @@ -0,0 +1,24 @@ +import * as React from "react" +import * as LabelPrimitive from "@radix-ui/react-label" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const labelVariants = cva( + "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" +) + +const Label = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & + VariantProps +>(({ className, ...props }, ref) => ( + +)) +Label.displayName = LabelPrimitive.Root.displayName + +export { Label } diff --git a/packages/upi-maker/src/components/ui/scroll-area.tsx b/packages/upi-maker/src/components/ui/scroll-area.tsx new file mode 100644 index 0000000..cf253cf --- /dev/null +++ b/packages/upi-maker/src/components/ui/scroll-area.tsx @@ -0,0 +1,46 @@ +import * as React from "react" +import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area" + +import { cn } from "@/lib/utils" + +const ScrollArea = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + {children} + + + + +)) +ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName + +const ScrollBar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, orientation = "vertical", ...props }, ref) => ( + + + +)) +ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName + +export { ScrollArea, ScrollBar } diff --git a/packages/upi-maker/src/components/ui/skeleton.tsx b/packages/upi-maker/src/components/ui/skeleton.tsx new file mode 100644 index 0000000..d7e45f7 --- /dev/null +++ b/packages/upi-maker/src/components/ui/skeleton.tsx @@ -0,0 +1,15 @@ +import { cn } from "@/lib/utils" + +function Skeleton({ + className, + ...props +}: React.HTMLAttributes) { + return ( +
+ ) +} + +export { Skeleton } diff --git a/packages/upi-maker/src/components/ui/sonner.tsx b/packages/upi-maker/src/components/ui/sonner.tsx new file mode 100644 index 0000000..1128edf --- /dev/null +++ b/packages/upi-maker/src/components/ui/sonner.tsx @@ -0,0 +1,29 @@ +import { useTheme } from "next-themes" +import { Toaster as Sonner } from "sonner" + +type ToasterProps = React.ComponentProps + +const Toaster = ({ ...props }: ToasterProps) => { + const { theme = "system" } = useTheme() + + return ( + + ) +} + +export { Toaster } diff --git a/packages/upi-maker/src/index.css b/packages/upi-maker/src/index.css new file mode 100644 index 0000000..47fac8d --- /dev/null +++ b/packages/upi-maker/src/index.css @@ -0,0 +1,50 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; +@layer base { + :root { + --background: 0 0% 3.9%; + --foreground: 0 0% 98%; + --card: 0 0% 3.9%; + --card-foreground: 0 0% 98%; + --popover: 0 0% 3.9%; + --popover-foreground: 0 0% 98%; + --primary: 0 0% 98%; + --primary-foreground: 0 0% 9%; + --secondary: 0 0% 14.9%; + --secondary-foreground: 0 0% 98%; + --muted: 0 0% 14.9%; + --muted-foreground: 0 0% 63.9%; + --accent: 0 0% 14.9%; + --accent-foreground: 0 0% 98%; + --destructive: 0 62.8% 30.6%; + --destructive-foreground: 0 0% 98%; + --border: 0 0% 14.9%; + --input: 0 0% 14.9%; + --ring: 0 0% 83.1%; + --chart-1: 220 70% 50%; + --chart-2: 160 60% 45%; + --chart-3: 30 80% 55%; + --chart-4: 280 65% 60%; + --chart-5: 340 75% 55%; + --radius: 0.5rem; + } +} +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} + +#html, +body { + height: 100vh; + max-height: 100vh; +} + +#app { + height: 100vh; +} diff --git a/packages/upi-maker/src/lib/utils.ts b/packages/upi-maker/src/lib/utils.ts new file mode 100644 index 0000000..bd0c391 --- /dev/null +++ b/packages/upi-maker/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { clsx, type ClassValue } from "clsx" +import { twMerge } from "tailwind-merge" + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)) +} diff --git a/packages/upi-maker/src/main.tsx b/packages/upi-maker/src/main.tsx new file mode 100644 index 0000000..df5a405 --- /dev/null +++ b/packages/upi-maker/src/main.tsx @@ -0,0 +1,34 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import { RouterProvider, createRouter } from '@tanstack/react-router' +import { routeTree } from './routeTree.gen' +import "./index.css"; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { Toaster } from './components/ui/sonner'; + +// Set up a Router instance +const router = createRouter({ + routeTree, + defaultPreload: 'intent', +}) + +// Register things for typesafety +declare module '@tanstack/react-router' { + interface Register { + router: typeof router + } +} + +const queryClient = new QueryClient() + +const rootElement = document.getElementById('app')! + +if (!rootElement.innerHTML) { + const root = ReactDOM.createRoot(rootElement) + root.render( + + + + + ) +} diff --git a/packages/upi-maker/src/queries/conts.ts b/packages/upi-maker/src/queries/conts.ts new file mode 100644 index 0000000..0f8b22e --- /dev/null +++ b/packages/upi-maker/src/queries/conts.ts @@ -0,0 +1,7 @@ +import ky from "ky"; + +export const API_URL = "https://zkrail-intent-aggregator.d4mr.workers.dev/api/"; + +export const intentAggregatorApi = ky.create({ + prefixUrl: API_URL, +}) \ No newline at end of file diff --git a/packages/upi-maker/src/queries/intent.ts b/packages/upi-maker/src/queries/intent.ts new file mode 100644 index 0000000..83a8fb9 --- /dev/null +++ b/packages/upi-maker/src/queries/intent.ts @@ -0,0 +1,15 @@ +import { queryOptions } from "@tanstack/react-query"; +import { intentAggregatorApi } from "./conts"; +import { Intent } from "./intents"; + +export const intentQueryOptions = (intentId: string) => + queryOptions({ + queryKey: ["intent", intentId], + queryFn: async () => { + const res = await intentAggregatorApi + .get(`intents/${intentId}`) + .json(); + + return res; + }, + }); diff --git a/packages/upi-maker/src/queries/intents.ts b/packages/upi-maker/src/queries/intents.ts new file mode 100644 index 0000000..2910e28 --- /dev/null +++ b/packages/upi-maker/src/queries/intents.ts @@ -0,0 +1,59 @@ +import { queryOptions } from "@tanstack/react-query"; +import { intentAggregatorApi } from "./conts"; + +export type IntentState = + | "CREATED" + | "SOLUTION_COMMITTED" + | "PAYMENT_CLAIMED" + | "RESOLVED" + | "SETTLED"; + +export type RailType = "UPI" | "BTC"; // Add more rail types as needed + +export type PaymentMetadata = { + transactionId: string; + timestamp: string; + railSpecificData: { + ANY_ADDITIONAL_PROPERTY: null | string; + [key: string]: unknown; + }; +}; + +export type Solution = { + id: string; + intentId: string; + solverAddress: string; + amountWei: string; + signature: string; + createdAt: string; + commitmentTxHash: string; + settlementTxHash: string; + resolutionTxHash: string | null; + paymentMetadata: string; // JSON string of PaymentMetadata +}; + +export type Intent = { + id: string; + paymentToken: string; + railType: RailType; + recipientAddress: string; + railAmount: string; + creatorAddress: string; + chainId: number; + createdAt: string; + state: IntentState; + winningSolutionId: string | null; + resolutionTxHash: string | null; + winningSolution: Solution | null; +}; + +export const intentsQueryOptions = queryOptions({ + queryKey: ["intents"], + queryFn: async () => { + const res = await intentAggregatorApi + .get<{ intents: Intent[] }>("intents") + .json(); + + return res.intents; + }, +}); diff --git a/packages/upi-maker/src/queries/solutions.ts b/packages/upi-maker/src/queries/solutions.ts new file mode 100644 index 0000000..ba0c4be --- /dev/null +++ b/packages/upi-maker/src/queries/solutions.ts @@ -0,0 +1,14 @@ +import { queryOptions } from "@tanstack/react-query"; +import { intentAggregatorApi } from "./conts"; +import { Solution } from "./intents"; + +export const solutionsQueryOptions = (intentId: string) => + queryOptions({ + queryKey: ["solutions", intentId], + queryFn: async () => { + const res = await intentAggregatorApi + .get<{ solutions: Solution[] }>(`intents/${intentId}/solutions`) + .json(); + return res.solutions; + }, + }); diff --git a/packages/upi-maker/src/queries/utils.ts b/packages/upi-maker/src/queries/utils.ts new file mode 100644 index 0000000..4d9b0e7 --- /dev/null +++ b/packages/upi-maker/src/queries/utils.ts @@ -0,0 +1,4 @@ +export function d1DateStringToLocaleString(utcString: string): string { + const date = new Date(utcString.replace(" ", "T") + "Z"); + return date.toLocaleString(); +} diff --git a/packages/upi-maker/src/routeTree.gen.ts b/packages/upi-maker/src/routeTree.gen.ts new file mode 100644 index 0000000..5e68293 --- /dev/null +++ b/packages/upi-maker/src/routeTree.gen.ts @@ -0,0 +1,88 @@ +/* eslint-disable */ + +// @ts-nocheck + +// noinspection JSUnusedGlobalSymbols + +// This file was automatically generated by TanStack Router. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +// Import Routes + +import { Route as rootRoute } from './routes/__root' +import { Route as IndexImport } from './routes/index' + +// Create/Update Routes + +const IndexRoute = IndexImport.update({ + id: '/', + path: '/', + getParentRoute: () => rootRoute, +} as any) + +// Populate the FileRoutesByPath interface + +declare module '@tanstack/react-router' { + interface FileRoutesByPath { + '/': { + id: '/' + path: '/' + fullPath: '/' + preLoaderRoute: typeof IndexImport + parentRoute: typeof rootRoute + } + } +} + +// Create and export the route tree + +export interface FileRoutesByFullPath { + '/': typeof IndexRoute +} + +export interface FileRoutesByTo { + '/': typeof IndexRoute +} + +export interface FileRoutesById { + __root__: typeof rootRoute + '/': typeof IndexRoute +} + +export interface FileRouteTypes { + fileRoutesByFullPath: FileRoutesByFullPath + fullPaths: '/' + fileRoutesByTo: FileRoutesByTo + to: '/' + id: '__root__' | '/' + fileRoutesById: FileRoutesById +} + +export interface RootRouteChildren { + IndexRoute: typeof IndexRoute +} + +const rootRouteChildren: RootRouteChildren = { + IndexRoute: IndexRoute, +} + +export const routeTree = rootRoute + ._addFileChildren(rootRouteChildren) + ._addFileTypes() + +/* ROUTE_MANIFEST_START +{ + "routes": { + "__root__": { + "filePath": "__root.tsx", + "children": [ + "/" + ] + }, + "/": { + "filePath": "index.tsx" + } + } +} +ROUTE_MANIFEST_END */ diff --git a/packages/upi-maker/src/routes/__root.tsx b/packages/upi-maker/src/routes/__root.tsx new file mode 100644 index 0000000..d6edbc2 --- /dev/null +++ b/packages/upi-maker/src/routes/__root.tsx @@ -0,0 +1,32 @@ +import * as React from 'react' +import { Link, Outlet, createRootRoute } from '@tanstack/react-router' +import { TanStackRouterDevtools } from '@tanstack/router-devtools' +import { ConnectButton, ThirdwebProvider } from 'thirdweb/react' +import { client } from '@/client' + +export const Route = createRootRoute({ + component: RootComponent, +}) + +function RootComponent() { + return ( + <> + +
+
+

+
zkrail
+
UPI Intent Solver
+

+
+ +
+
+
+ +
+ +
+ + ) +} diff --git a/packages/upi-maker/src/routes/index.tsx b/packages/upi-maker/src/routes/index.tsx new file mode 100644 index 0000000..dc589e1 --- /dev/null +++ b/packages/upi-maker/src/routes/index.tsx @@ -0,0 +1,22 @@ +import * as React from 'react' +import { createFileRoute } from '@tanstack/react-router' +import { IntentsList } from '@/components/intents-list' +import { IntentDetails } from '@/components/intent-details'; + +export const Route = createFileRoute('/')({ + component: HomeComponent, +}) + +function HomeComponent() { + const [intentId, setIntentId] = React.useState(null); + + return ( +
+ + { + intentId && + + } +
+ ) +} diff --git a/packages/upi-maker/tailwind.config.js b/packages/upi-maker/tailwind.config.js new file mode 100644 index 0000000..b65262e --- /dev/null +++ b/packages/upi-maker/tailwind.config.js @@ -0,0 +1,57 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + darkMode: ["class"], + content: ["./index.html", "./src/**/*.{ts,tsx,js,jsx}"], + theme: { + extend: { + borderRadius: { + lg: 'var(--radius)', + md: 'calc(var(--radius) - 2px)', + sm: 'calc(var(--radius) - 4px)' + }, + colors: { + background: 'hsl(var(--background))', + foreground: 'hsl(var(--foreground))', + card: { + DEFAULT: 'hsl(var(--card))', + foreground: 'hsl(var(--card-foreground))' + }, + popover: { + DEFAULT: 'hsl(var(--popover))', + foreground: 'hsl(var(--popover-foreground))' + }, + primary: { + DEFAULT: 'hsl(var(--primary))', + foreground: 'hsl(var(--primary-foreground))' + }, + secondary: { + DEFAULT: 'hsl(var(--secondary))', + foreground: 'hsl(var(--secondary-foreground))' + }, + muted: { + DEFAULT: 'hsl(var(--muted))', + foreground: 'hsl(var(--muted-foreground))' + }, + accent: { + DEFAULT: 'hsl(var(--accent))', + foreground: 'hsl(var(--accent-foreground))' + }, + destructive: { + DEFAULT: 'hsl(var(--destructive))', + foreground: 'hsl(var(--destructive-foreground))' + }, + border: 'hsl(var(--border))', + input: 'hsl(var(--input))', + ring: 'hsl(var(--ring))', + chart: { + '1': 'hsl(var(--chart-1))', + '2': 'hsl(var(--chart-2))', + '3': 'hsl(var(--chart-3))', + '4': 'hsl(var(--chart-4))', + '5': 'hsl(var(--chart-5))' + } + } + } + }, + plugins: [require("tailwindcss-animate")], +} \ No newline at end of file diff --git a/packages/upi-maker/tsconfig.json b/packages/upi-maker/tsconfig.json new file mode 100644 index 0000000..60b23b5 --- /dev/null +++ b/packages/upi-maker/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "strict": true, + "esModuleInterop": true, + "jsx": "react-jsx", + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "Bundler", + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + } +} diff --git a/packages/upi-maker/vite-env.d.ts b/packages/upi-maker/vite-env.d.ts new file mode 100644 index 0000000..b456e21 --- /dev/null +++ b/packages/upi-maker/vite-env.d.ts @@ -0,0 +1,10 @@ +/// + +interface ImportMetaEnv { + readonly VITE_THIRDWEB_CLIENT_ID: string + // more env variables... +} + +interface ImportMeta { + readonly env: ImportMetaEnv +} \ No newline at end of file diff --git a/packages/upi-maker/vite.config.ts b/packages/upi-maker/vite.config.ts new file mode 100644 index 0000000..0385358 --- /dev/null +++ b/packages/upi-maker/vite.config.ts @@ -0,0 +1,14 @@ +import path from "path"; +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; +import { TanStackRouterVite } from "@tanstack/router-plugin/vite"; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [TanStackRouterVite({}), react()], + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, +}); diff --git a/packages/upi-taker/package.json b/packages/upi-taker/package.json index f71258e..16b8c67 100644 --- a/packages/upi-taker/package.json +++ b/packages/upi-taker/package.json @@ -24,10 +24,12 @@ "dependencies": { "@radix-ui/react-slot": "^1.1.0", "@radix-ui/react-tooltip": "^1.1.4", + "@tanstack/react-query": "^5.62.3", "@tanstack/react-router": "^1.86.0", "@tanstack/router-devtools": "^1.86.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "ky": "^1.7.2", "lucide-react": "^0.468.0", "react": "^18.3.1", "react-dom": "^18.3.1", diff --git a/packages/upi-taker/src/main.tsx b/packages/upi-taker/src/main.tsx index a1318d2..bd96206 100644 --- a/packages/upi-taker/src/main.tsx +++ b/packages/upi-taker/src/main.tsx @@ -2,6 +2,7 @@ import React from 'react' import ReactDOM from 'react-dom/client' import { RouterProvider, createRouter } from '@tanstack/react-router' import { routeTree } from './routeTree.gen' +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import "./index.css"; // Set up a Router instance @@ -17,9 +18,14 @@ declare module '@tanstack/react-router' { } } +const queryClient = new QueryClient(); const rootElement = document.getElementById('app')! if (!rootElement.innerHTML) { const root = ReactDOM.createRoot(rootElement) - root.render() + root.render( + + + + ) } diff --git a/packages/upi-taker/src/queries/conts.ts b/packages/upi-taker/src/queries/conts.ts new file mode 100644 index 0000000..0f8b22e --- /dev/null +++ b/packages/upi-taker/src/queries/conts.ts @@ -0,0 +1,7 @@ +import ky from "ky"; + +export const API_URL = "https://zkrail-intent-aggregator.d4mr.workers.dev/api/"; + +export const intentAggregatorApi = ky.create({ + prefixUrl: API_URL, +}) \ No newline at end of file diff --git a/packages/upi-taker/src/queries/intent.ts b/packages/upi-taker/src/queries/intent.ts new file mode 100644 index 0000000..83a8fb9 --- /dev/null +++ b/packages/upi-taker/src/queries/intent.ts @@ -0,0 +1,15 @@ +import { queryOptions } from "@tanstack/react-query"; +import { intentAggregatorApi } from "./conts"; +import { Intent } from "./intents"; + +export const intentQueryOptions = (intentId: string) => + queryOptions({ + queryKey: ["intent", intentId], + queryFn: async () => { + const res = await intentAggregatorApi + .get(`intents/${intentId}`) + .json(); + + return res; + }, + }); diff --git a/packages/upi-taker/src/queries/intents.ts b/packages/upi-taker/src/queries/intents.ts new file mode 100644 index 0000000..2910e28 --- /dev/null +++ b/packages/upi-taker/src/queries/intents.ts @@ -0,0 +1,59 @@ +import { queryOptions } from "@tanstack/react-query"; +import { intentAggregatorApi } from "./conts"; + +export type IntentState = + | "CREATED" + | "SOLUTION_COMMITTED" + | "PAYMENT_CLAIMED" + | "RESOLVED" + | "SETTLED"; + +export type RailType = "UPI" | "BTC"; // Add more rail types as needed + +export type PaymentMetadata = { + transactionId: string; + timestamp: string; + railSpecificData: { + ANY_ADDITIONAL_PROPERTY: null | string; + [key: string]: unknown; + }; +}; + +export type Solution = { + id: string; + intentId: string; + solverAddress: string; + amountWei: string; + signature: string; + createdAt: string; + commitmentTxHash: string; + settlementTxHash: string; + resolutionTxHash: string | null; + paymentMetadata: string; // JSON string of PaymentMetadata +}; + +export type Intent = { + id: string; + paymentToken: string; + railType: RailType; + recipientAddress: string; + railAmount: string; + creatorAddress: string; + chainId: number; + createdAt: string; + state: IntentState; + winningSolutionId: string | null; + resolutionTxHash: string | null; + winningSolution: Solution | null; +}; + +export const intentsQueryOptions = queryOptions({ + queryKey: ["intents"], + queryFn: async () => { + const res = await intentAggregatorApi + .get<{ intents: Intent[] }>("intents") + .json(); + + return res.intents; + }, +}); diff --git a/packages/upi-taker/src/queries/solutions.ts b/packages/upi-taker/src/queries/solutions.ts new file mode 100644 index 0000000..ba0c4be --- /dev/null +++ b/packages/upi-taker/src/queries/solutions.ts @@ -0,0 +1,14 @@ +import { queryOptions } from "@tanstack/react-query"; +import { intentAggregatorApi } from "./conts"; +import { Solution } from "./intents"; + +export const solutionsQueryOptions = (intentId: string) => + queryOptions({ + queryKey: ["solutions", intentId], + queryFn: async () => { + const res = await intentAggregatorApi + .get<{ solutions: Solution[] }>(`intents/${intentId}/solutions`) + .json(); + return res.solutions; + }, + }); diff --git a/packages/upi-taker/src/queries/utils.ts b/packages/upi-taker/src/queries/utils.ts new file mode 100644 index 0000000..4d9b0e7 --- /dev/null +++ b/packages/upi-taker/src/queries/utils.ts @@ -0,0 +1,4 @@ +export function d1DateStringToLocaleString(utcString: string): string { + const date = new Date(utcString.replace(" ", "T") + "Z"); + return date.toLocaleString(); +} diff --git a/packages/upi-taker/src/routeTree.gen.ts b/packages/upi-taker/src/routeTree.gen.ts index 7e0823f..dd9bda7 100644 --- a/packages/upi-taker/src/routeTree.gen.ts +++ b/packages/upi-taker/src/routeTree.gen.ts @@ -19,7 +19,7 @@ import { Route as HomeNavImport } from './routes/home/_nav' import { Route as HomeNavScanImport } from './routes/home/_nav.scan' import { Route as HomeNavOrdersImport } from './routes/home/_nav.orders' import { Route as PayVpaNameIndexImport } from './routes/pay.$vpa.$name/index' -import { Route as PayVpaNameAmountQuoteImport } from './routes/pay.$vpa.$name/$amount.quote' +import { Route as PayVpaNameIntentQuoteImport } from './routes/pay.$vpa.$name/$intent.quote' // Create Virtual Routes @@ -68,9 +68,9 @@ const PayVpaNameIndexRoute = PayVpaNameIndexImport.update({ getParentRoute: () => rootRoute, } as any) -const PayVpaNameAmountQuoteRoute = PayVpaNameAmountQuoteImport.update({ - id: '/pay/$vpa/$name/$amount/quote', - path: '/pay/$vpa/$name/$amount/quote', +const PayVpaNameIntentQuoteRoute = PayVpaNameIntentQuoteImport.update({ + id: '/pay/$vpa/$name/$intent/quote', + path: '/pay/$vpa/$name/$intent/quote', getParentRoute: () => rootRoute, } as any) @@ -127,11 +127,11 @@ declare module '@tanstack/react-router' { preLoaderRoute: typeof PayVpaNameIndexImport parentRoute: typeof rootRoute } - '/pay/$vpa/$name/$amount/quote': { - id: '/pay/$vpa/$name/$amount/quote' - path: '/pay/$vpa/$name/$amount/quote' - fullPath: '/pay/$vpa/$name/$amount/quote' - preLoaderRoute: typeof PayVpaNameAmountQuoteImport + '/pay/$vpa/$name/$intent/quote': { + id: '/pay/$vpa/$name/$intent/quote' + path: '/pay/$vpa/$name/$intent/quote' + fullPath: '/pay/$vpa/$name/$intent/quote' + preLoaderRoute: typeof PayVpaNameIntentQuoteImport parentRoute: typeof rootRoute } } @@ -171,7 +171,7 @@ export interface FileRoutesByFullPath { '/home/orders': typeof HomeNavOrdersRoute '/home/scan': typeof HomeNavScanRoute '/pay/$vpa/$name': typeof PayVpaNameIndexRoute - '/pay/$vpa/$name/$amount/quote': typeof PayVpaNameAmountQuoteRoute + '/pay/$vpa/$name/$intent/quote': typeof PayVpaNameIntentQuoteRoute } export interface FileRoutesByTo { @@ -180,7 +180,7 @@ export interface FileRoutesByTo { '/home/orders': typeof HomeNavOrdersRoute '/home/scan': typeof HomeNavScanRoute '/pay/$vpa/$name': typeof PayVpaNameIndexRoute - '/pay/$vpa/$name/$amount/quote': typeof PayVpaNameAmountQuoteRoute + '/pay/$vpa/$name/$intent/quote': typeof PayVpaNameIntentQuoteRoute } export interface FileRoutesById { @@ -192,7 +192,7 @@ export interface FileRoutesById { '/home/_nav/orders': typeof HomeNavOrdersRoute '/home/_nav/scan': typeof HomeNavScanRoute '/pay/$vpa/$name/': typeof PayVpaNameIndexRoute - '/pay/$vpa/$name/$amount/quote': typeof PayVpaNameAmountQuoteRoute + '/pay/$vpa/$name/$intent/quote': typeof PayVpaNameIntentQuoteRoute } export interface FileRouteTypes { @@ -204,7 +204,7 @@ export interface FileRouteTypes { | '/home/orders' | '/home/scan' | '/pay/$vpa/$name' - | '/pay/$vpa/$name/$amount/quote' + | '/pay/$vpa/$name/$intent/quote' fileRoutesByTo: FileRoutesByTo to: | '/' @@ -212,7 +212,7 @@ export interface FileRouteTypes { | '/home/orders' | '/home/scan' | '/pay/$vpa/$name' - | '/pay/$vpa/$name/$amount/quote' + | '/pay/$vpa/$name/$intent/quote' id: | '__root__' | '/' @@ -222,7 +222,7 @@ export interface FileRouteTypes { | '/home/_nav/orders' | '/home/_nav/scan' | '/pay/$vpa/$name/' - | '/pay/$vpa/$name/$amount/quote' + | '/pay/$vpa/$name/$intent/quote' fileRoutesById: FileRoutesById } @@ -230,14 +230,14 @@ export interface RootRouteChildren { IndexRoute: typeof IndexRoute HomeRoute: typeof HomeRouteWithChildren PayVpaNameIndexRoute: typeof PayVpaNameIndexRoute - PayVpaNameAmountQuoteRoute: typeof PayVpaNameAmountQuoteRoute + PayVpaNameIntentQuoteRoute: typeof PayVpaNameIntentQuoteRoute } const rootRouteChildren: RootRouteChildren = { IndexRoute: IndexRoute, HomeRoute: HomeRouteWithChildren, PayVpaNameIndexRoute: PayVpaNameIndexRoute, - PayVpaNameAmountQuoteRoute: PayVpaNameAmountQuoteRoute, + PayVpaNameIntentQuoteRoute: PayVpaNameIntentQuoteRoute, } export const routeTree = rootRoute @@ -253,7 +253,7 @@ export const routeTree = rootRoute "/", "/home", "/pay/$vpa/$name/", - "/pay/$vpa/$name/$amount/quote" + "/pay/$vpa/$name/$intent/quote" ] }, "/": { @@ -289,8 +289,8 @@ export const routeTree = rootRoute "/pay/$vpa/$name/": { "filePath": "pay.$vpa.$name/index.tsx" }, - "/pay/$vpa/$name/$amount/quote": { - "filePath": "pay.$vpa.$name/$amount.quote.tsx" + "/pay/$vpa/$name/$intent/quote": { + "filePath": "pay.$vpa.$name/$intent.quote.tsx" } } } diff --git a/packages/upi-taker/src/routes/pay.$vpa.$name/$amount.quote.tsx b/packages/upi-taker/src/routes/pay.$vpa.$name/$amount.quote.tsx deleted file mode 100644 index ae4be7e..0000000 --- a/packages/upi-taker/src/routes/pay.$vpa.$name/$amount.quote.tsx +++ /dev/null @@ -1,192 +0,0 @@ -import { createFileRoute, Link } from '@tanstack/react-router' -import { useState, useEffect } from 'react' -import { Button, buttonVariants } from "@/components/ui/button" -import { Loader2, HelpCircle, ArrowLeftRight } from 'lucide-react' -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip" -import { Card, CardContent } from "@/components/ui/card" - - -export const Route = createFileRoute('/pay/$vpa/$name/$amount/quote')({ - component: RouteComponent, -}) - -function RouteComponent() { - const { vpa, name, amount: stringAmount } = Route.useParams(); - const amount = parseFloat(stringAmount); - - const [loading, setLoading] = useState(true) - const [countdown, setCountdown] = useState(5) - const [refreshing, setRefreshing] = useState(false) - - - const [quote, setQuote] = useState<{ - address: string - usdcAmount: number - collateral: number - bondAmount: number - } | null>(null) - - useEffect(() => { - // Initial quote fetch - const timer = setTimeout(() => { - setQuote({ - address: '0x1234...5678', - usdcAmount: amount / 80, // Assuming 1 USD = 80 INR - collateral: (amount / 80) * 0.5, // 50% collateral - bondAmount: (amount / 80) * 0.1 // 10% bond amount (example) - }) - setLoading(false) - }, 2000) - - return () => clearTimeout(timer) - }, [amount]) - - useEffect(() => { - if (!loading) { - const interval = setInterval(() => { - setCountdown((prev) => { - if (prev <= 1) { - setRefreshing(true) - setTimeout(() => { - setRefreshing(false) - // Simulate quote refresh - setQuote(prev => { - if (!prev) return null - const newUsdcAmount = prev.usdcAmount * (0.995 + Math.random() * 0.01) - return { - ...prev, - usdcAmount: newUsdcAmount, - collateral: newUsdcAmount * 0.5 // Refresh collateral amount - } - }) - }, 1000) - return 5 - } - return prev - 1 - }) - }, 1000) - - return () => clearInterval(interval) - } - }, [loading]) - - if (loading) { - return ( -
- -

Fetching best rates...

-
- ) - } - - return ( -
-
-
-

Quote

-
- {refreshing ? ( - - - REFRESHED - - ) : ( - REFRESHING BEST QUOTE IN {countdown} - )} -
-
- - - -
- Polygon Logo -

{quote?.address}

-
- -
-
- Quote amount - {quote?.usdcAmount.toFixed(2)} USDC -
-
-
- Refundable collateral - - - - - - -

A 50% collateral is required. This amount will be fully refunded after the transaction is confirmed.

-
-
-
-
-
- {quote?.collateral.toFixed(2)} USDC - -
-
-
-
- Bond amount - - - - - - -

Bond amount is promised by the maker. If the maker fails to make a payment within 48 hours, the bond + the payment amount is refunded to you.

-
-
-
-
- {quote?.bondAmount.toFixed(2)} USDC -
-
-
- Total to pay now - - {((quote?.usdcAmount || 0) + (quote?.collateral || 0)).toFixed(2)} USDC - -
-
- {quote?.collateral.toFixed(2)} USDC will be refunded after confirmation -
-
-
-
-
-
- -
- - - Cancel - -
-
- ) -} diff --git a/packages/upi-taker/src/routes/pay.$vpa.$name/$intent.quote.tsx b/packages/upi-taker/src/routes/pay.$vpa.$name/$intent.quote.tsx new file mode 100644 index 0000000..eb8e819 --- /dev/null +++ b/packages/upi-taker/src/routes/pay.$vpa.$name/$intent.quote.tsx @@ -0,0 +1,254 @@ +import { createFileRoute, Link } from '@tanstack/react-router' +import { useState, useEffect } from 'react' +import { Button, buttonVariants } from '@/components/ui/button' +import { Loader2, HelpCircle, ArrowLeftRight } from 'lucide-react' +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from '@/components/ui/tooltip' +import { Card, CardContent } from '@/components/ui/card' +import { useMutation, useQuery } from '@tanstack/react-query' +import { solutionsQueryOptions } from '@/queries/solutions' +import { intentQueryOptions } from '@/queries/intent' +import { getContract, Hex, keccak256, prepareContractCall, readContract, sendTransaction, stringToHex, toBytes, toTokens, toUnits } from 'thirdweb' +import { shortenAddress } from 'thirdweb/utils' +import { ConnectButton, useActiveAccount } from 'thirdweb/react' +import { client } from '@/client' +import { baseSepolia } from 'thirdweb/chains' +import { zkRailUsdc } from '.' +import { error } from 'console' + +export const zkRailUPI = "0x926B9bD1905CfeC995B0955DE7392bEdECE2FDC9"; + +export const Route = createFileRoute('/pay/$vpa/$name/$intent/quote')({ + component: RouteComponent, +}) + +// Helper for converting intent ID to bytes32 + +function intentIdToBytes32(intentId: string): `0x${string}` { + // If already hex + if (intentId.startsWith('0x')) { + return intentId as `0x${string}` + } + // If base58/UUID style, hash it + return keccak256(toBytes(intentId)) as `0x${string}` +} +function RouteComponent() { + const { vpa, name, intent: intentId } = Route.useParams(); + const account = useActiveAccount(); + + const intentSolutionsQuery = useQuery({ ...solutionsQueryOptions(intentId), refetchInterval: 2000 }); + const intentQuery = useQuery(intentQueryOptions(intentId)); + + + const lowestQuote = intentSolutionsQuery.data?.[0]; + const lowestQuoteAmount = intentSolutionsQuery.data?.[0]?.amountWei ? BigInt(intentSolutionsQuery.data?.[0].amountWei) : undefined; + const lowestQuoteCollateral = intentSolutionsQuery.data?.[0]?.amountWei ? BigInt(intentSolutionsQuery.data?.[0].amountWei) / 2n : undefined; + const lowestQuoteTotal = lowestQuoteAmount && lowestQuoteCollateral ? lowestQuoteAmount + lowestQuoteCollateral : undefined; + + const loading = intentSolutionsQuery.isLoading || !lowestQuote; + const refreshing = intentQuery.isFetching; + + const commitSolutionMutation = useMutation({ + mutationFn: async () => { + if (!lowestQuoteAmount || !lowestQuote || !intentQuery.data || !account) { + console.error("error"); + throw new Error("no data") + }; + const intent = intentQuery.data; + + const zkUpiContract = getContract({ + address: zkRailUPI, + chain: baseSepolia, + client + }); + + // const totalAmount = await readContract({ + // contract: zkUpiContract, + // method: 'function calculateTotalAmount(uint256 paymentAmount) external view returns (uint256)', + // params: [lowestQuoteAmount] + // }) + + const formattedSolution = [ + intentIdToBytes32(lowestQuote.intentId), + intent.railType as string, + intent.recipientAddress as string, + BigInt(intent.railAmount), + intent.paymentToken, + lowestQuoteAmount, + zkRailUsdc, + toUnits("500", 6), + account.address + ] as const; + + console.log('Formatted solution:', formattedSolution); + console.log('Signature:', lowestQuote.signature); + + // The contract function now expects a single struct + console.log(keccak256(stringToHex( + 'IntentSolution(bytes32 intentId,string railType,string recipientAddress,uint256 railAmount,address paymentToken,uint256 paymentAmount,address bondToken,uint256 bondAmount,address intentCreator)' + ))) + + const transaction = prepareContractCall({ + contract: zkUpiContract, + method: "function commitToSolution((bytes32,string,string,uint256,address,uint256,address,uint256,address),bytes)" as const, + params: [formattedSolution, lowestQuote.signature as Hex], + }); + + const { transactionHash } = await sendTransaction({ + account, + transaction, + }); + console.log(transactionHash); + }, + onError: (error) => { + console.error(error) + } + } + + ); + + + if (loading) { + return ( +
+ +

Fetching best rates...

+
+ ) + } + + return ( +
+
+
+

Quote

+
+ {refreshing ? ( + + + REFRESHED + + ) : ( + REFRESHING BEST QUOTE IN 2 SECONDS + )} +
+
+ + + +
+ Polygon Logo +

{shortenAddress(lowestQuote?.solverAddress)}

+
+ +
+
+ Quote amount + + {toTokens(BigInt(lowestQuote.amountWei), 6)} USDC + +
+
+
+ + Refundable collateral + + + + + + + +

+ A 50% collateral is required. This amount will be + fully refunded after the transaction is confirmed. +

+
+
+
+
+
+ + {lowestQuoteCollateral ? toTokens(lowestQuoteCollateral, 6) : "..."} USDC + + +
+
+
+
+ + Bond amount + + + + + + + +

+ Bond amount is promised by the maker. If the maker + fails to make a payment within 48 hours, the bond + + the payment amount is refunded to you. +

+
+
+
+
+ + 500 USDC + +
+
+
+ + Total to pay now + + + {lowestQuoteTotal ? toTokens(lowestQuoteTotal, 6) : "..."} + USDC + +
+
+ + {lowestQuoteCollateral ? toTokens(lowestQuoteCollateral, 6) : "..."} USDC will be refunded after + confirmation + +
+
+
+
+
+
+ +
+ + + + + Cancel + +
+
+ ) +} diff --git a/packages/upi-taker/src/routes/pay.$vpa.$name/index.tsx b/packages/upi-taker/src/routes/pay.$vpa.$name/index.tsx index a53a15a..37a5e3b 100644 --- a/packages/upi-taker/src/routes/pay.$vpa.$name/index.tsx +++ b/packages/upi-taker/src/routes/pay.$vpa.$name/index.tsx @@ -1,6 +1,14 @@ import { createFileRoute, Link, useNavigate, useParams } from '@tanstack/react-router' import { useState, useEffect, useCallback } from 'react' import { Button, buttonVariants } from "@/components/ui/button" +import { useMutation } from '@tanstack/react-query' +import { intentAggregatorApi } from '@/queries/conts' +import { ConnectButton, useActiveAccount } from 'thirdweb/react' +import { Loader2 } from 'lucide-react' +import { client } from '@/client' + +export const zkRailUsdc = "0x215D8DC520791a5fECa4D302798D8C47aD7E0588"; +const chainId = 84532; interface PaymentScreenProps { recipient: string @@ -15,6 +23,7 @@ function RouteComponent() { const [amount, setAmount] = useState('') const { name, vpa } = Route.useParams(); const navigate = useNavigate(); + const account = useActiveAccount(); const handleNumberInput = useCallback((num: string) => { if (amount.includes('.') && num === '.') return @@ -27,15 +36,36 @@ function RouteComponent() { const handleDelete = useCallback(() => { setAmount(prev => prev.slice(0, -1)) - }, []) + }, []); + + const submitIntentMutation = useMutation({ + mutationFn: async (amount: string) => { + if (!account) throw new Error("Wallet not connected"); + + return await intentAggregatorApi.post<{ intentId: string }>(`intents`, { + json: { + paymentToken: zkRailUsdc, + railType: "UPI", + recipientAddress: vpa, + railAmount: amount, + creatorAddress: account.address, + chainId + } + }).json() + } + }); + - const handlePay = () => { - const numAmount = parseFloat(amount) + const handlePay = async () => { + const numAmount = parseFloat(amount); if (!isNaN(numAmount) && numAmount > 0) { + const intent = await submitIntentMutation.mutateAsync((numAmount * 100).toString()); + console.log(intent); + navigate({ - to: "/pay/$vpa/$name/$amount/quote", + to: "/pay/$vpa/$name/$intent/quote", params: { - name, vpa, amount: numAmount.toString() + name, vpa, intent: intent.intentId } }) } @@ -103,10 +133,16 @@ function RouteComponent() {
+ + =14'} + '@radix-ui/number@1.1.0': + resolution: {integrity: sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ==} + '@radix-ui/primitive@1.1.0': resolution: {integrity: sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA==} @@ -1463,6 +1557,15 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-direction@1.1.0': + resolution: {integrity: sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@radix-ui/react-dismissable-layer@1.1.1': resolution: {integrity: sha512-QSxg29lfr/xcev6kSz7MAlmDnzbP1eI/Dwn3Tp1ip0KT5CUELsxkekFEMVBEoykI3oV39hKT4TKZzBNMbcTZYQ==} peerDependencies: @@ -1512,6 +1615,19 @@ packages: '@types/react': optional: true + '@radix-ui/react-label@2.1.0': + resolution: {integrity: sha512-peLblDlFw/ngk3UWq0VnYaOLy6agTZZ+MUO/WhVfm14vJGML+xH4FAl2XQGLqdefjNb7ApRg6Yn7U42ZhmYXdw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-popper@1.2.0': resolution: {integrity: sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==} peerDependencies: @@ -1564,6 +1680,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-scroll-area@1.2.1': + resolution: {integrity: sha512-FnM1fHfCtEZ1JkyfH/1oMiTcFBQvHKl4vD9WnpwkLgtF+UmnXMCad6ECPTaAjcDjam+ndOEJWgHyKDGNteWSHw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-slot@1.1.0': resolution: {integrity: sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==} peerDependencies: @@ -1844,11 +1973,19 @@ packages: '@tanstack/query-core@5.62.1': resolution: {integrity: sha512-thYv90GkMcfumgmtp6sptC18SqxWwXTCKUuk7jyeHHn7kYouh0VJrowuuBffAIBiR3Z8OnsccmPUnP1leKJBVQ==} + '@tanstack/query-core@5.62.3': + resolution: {integrity: sha512-Jp/nYoz8cnO7kqhOlSv8ke/0MJRJVGuZ0P/JO9KQ+f45mpN90hrerzavyTKeSoT/pOzeoOUkv1Xd0wPsxAWXfg==} + '@tanstack/react-query@5.62.1': resolution: {integrity: sha512-gb4eglrgW+yOeiNPkpqFyN8oLrFafHrHE+q2LzVl7TfyA4fuQluH92NTl6Jed7ae35v+BNtAQng9mykywWLzfA==} peerDependencies: react: ^18 || ^19 + '@tanstack/react-query@5.62.3': + resolution: {integrity: sha512-y2zDNKuhgiuMgsKkqd4AcsLIBiCfEO8U11AdrtAUihmLbRNztPrlcZqx2lH1GacZsx+y1qRRbCcJLYTtF1vKsw==} + peerDependencies: + react: ^18 || ^19 + '@tanstack/react-router@1.86.0': resolution: {integrity: sha512-ywjRtykCoNv539s9ExcBuMEwyCLccBrrOOuZfR3ZVEHdkInmANa57WtSRPhzf7OzysNm80gTRPayDI7dVRODog==} engines: {node: '>=12'} @@ -2044,6 +2181,17 @@ packages: zod: optional: true + abitype@1.0.7: + resolution: {integrity: sha512-ZfYYSktDQUwc2eduYu8C4wOs+RDPmnRYMh7zNfzeMtGGgb0U+6tLGjixUic6mXf5xKKCcgT5Qp6cv39tOARVFw==} + peerDependencies: + typescript: '>=5.0.4' + zod: ^3 >=3.22.0 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true + acorn-walk@8.3.4: resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} engines: {node: '>=0.4.0'} @@ -2814,6 +2962,10 @@ packages: keyvaluestorage-interface@1.0.0: resolution: {integrity: sha512-8t6Q3TclQ4uZynJY9IGr2+SsIGwK9JHcO6ootkHCGA0CrQCRy+VkouYNO2xicET6b9al7QKzpebNow+gkpCL8g==} + ky@1.7.2: + resolution: {integrity: sha512-OzIvbHKKDpi60TnF9t7UUVAF1B4mcqc02z5PIvrm08Wyb+yOcz63GRvEuVxNT18a9E1SrNouhB4W2NNLeD7Ykg==} + engines: {node: '>=18'} + lilconfig@2.1.0: resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} engines: {node: '>=10'} @@ -2972,6 +3124,12 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + next-themes@0.4.4: + resolution: {integrity: sha512-LDQ2qIOJF0VnuVrrMSMLrWGjRMkq+0mpgl6e0juCLqdJ+oo8Q84JRWT6Wh11VDQKkMMe+dVzDKLWs5n87T+PkQ==} + peerDependencies: + react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + node-addon-api@7.1.1: resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} @@ -3419,6 +3577,12 @@ packages: sonic-boom@2.8.0: resolution: {integrity: sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg==} + sonner@1.7.0: + resolution: {integrity: sha512-W6dH7m5MujEPyug3lpI2l3TC3Pp1+LTgK0Efg+IHDrBbtEjyCmCHHo6yfNBOsf1tFZ6zf+jceWwB38baC8yO9g==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -3767,6 +3931,14 @@ packages: typescript: optional: true + viem@2.21.54: + resolution: {integrity: sha512-G9mmtbua3UtnVY9BqAtWdNp+3AO+oWhD0B9KaEsZb6gcrOWgmA4rz02yqEMg+qW9m6KgKGie7q3zcHqJIw6AqA==} + peerDependencies: + typescript: '>=5.0.4' + peerDependenciesMeta: + typescript: + optional: true + vite@6.0.3: resolution: {integrity: sha512-Cmuo5P0ENTN6HxLSo6IHsjCLn/81Vgrp81oaiFFMRa8gGDj5xEjIcEpf2ZymZtZR8oU0P2JX5WuUp/rlXcHkAw==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -5020,6 +5192,8 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true + '@radix-ui/number@1.1.0': {} + '@radix-ui/primitive@1.1.0': {} '@radix-ui/react-arrow@1.1.0(@types/react-dom@18.3.2)(@types/react@18.3.14)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': @@ -5071,6 +5245,12 @@ snapshots: '@types/react': 18.3.14 '@types/react-dom': 18.3.2 + '@radix-ui/react-direction@1.1.0(@types/react@18.3.14)(react@18.3.1)': + dependencies: + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.14 + '@radix-ui/react-dismissable-layer@1.1.1(@types/react-dom@18.3.2)(@types/react@18.3.14)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/primitive': 1.1.0 @@ -5112,6 +5292,15 @@ snapshots: optionalDependencies: '@types/react': 18.3.14 + '@radix-ui/react-label@2.1.0(@types/react-dom@18.3.2)(@types/react@18.3.14)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.2)(@types/react@18.3.14)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.14 + '@types/react-dom': 18.3.2 + '@radix-ui/react-popper@1.2.0(@types/react-dom@18.3.2)(@types/react@18.3.14)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@floating-ui/react-dom': 2.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -5159,6 +5348,23 @@ snapshots: '@types/react': 18.3.14 '@types/react-dom': 18.3.2 + '@radix-ui/react-scroll-area@1.2.1(@types/react-dom@18.3.2)(@types/react@18.3.14)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/number': 1.1.0 + '@radix-ui/primitive': 1.1.0 + '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.14)(react@18.3.1) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.14)(react@18.3.1) + '@radix-ui/react-direction': 1.1.0(@types/react@18.3.14)(react@18.3.1) + '@radix-ui/react-presence': 1.1.1(@types/react-dom@18.3.2)(@types/react@18.3.14)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.2)(@types/react@18.3.14)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-use-callback-ref': 1.1.0(@types/react@18.3.14)(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.3.14)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.14 + '@types/react-dom': 18.3.2 + '@radix-ui/react-slot@1.1.0(@types/react@18.3.14)(react@18.3.1)': dependencies: '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.14)(react@18.3.1) @@ -5416,11 +5622,18 @@ snapshots: '@tanstack/query-core@5.62.1': {} + '@tanstack/query-core@5.62.3': {} + '@tanstack/react-query@5.62.1(react@18.3.1)': dependencies: '@tanstack/query-core': 5.62.1 react: 18.3.1 + '@tanstack/react-query@5.62.3(react@18.3.1)': + dependencies: + '@tanstack/query-core': 5.62.3 + react: 18.3.1 + '@tanstack/react-router@1.86.0(@tanstack/router-generator@1.86.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@tanstack/history': 1.85.3 @@ -5880,6 +6093,10 @@ snapshots: optionalDependencies: zod: 3.23.8 + abitype@1.0.7(zod@3.23.8): + optionalDependencies: + zod: 3.23.8 + acorn-walk@8.3.4: dependencies: acorn: 8.14.0 @@ -6653,6 +6870,8 @@ snapshots: keyvaluestorage-interface@1.0.0: {} + ky@1.7.2: {} + lilconfig@2.1.0: {} lilconfig@3.1.3: {} @@ -6844,6 +7063,11 @@ snapshots: nanoid@3.3.8: {} + next-themes@0.4.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + node-addon-api@7.1.1: {} node-fetch-native@1.6.4: {} @@ -6899,9 +7123,9 @@ snapshots: '@adraffy/ens-normalize': 1.11.0 '@noble/curves': 1.7.0 '@noble/hashes': 1.6.1 - '@scure/bip32': 1.5.0 - '@scure/bip39': 1.4.0 - abitype: 1.0.6(zod@3.23.8) + '@scure/bip32': 1.6.0 + '@scure/bip39': 1.5.0 + abitype: 1.0.7(zod@3.23.8) eventemitter3: 5.0.1 transitivePeerDependencies: - zod @@ -7268,6 +7492,11 @@ snapshots: dependencies: atomic-sleep: 1.0.0 + sonner@1.7.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + source-map-js@1.2.1: {} source-map-support@0.5.21: @@ -7584,6 +7813,22 @@ snapshots: - utf-8-validate - zod + viem@2.21.54(zod@3.23.8): + dependencies: + '@noble/curves': 1.7.0 + '@noble/hashes': 1.6.1 + '@scure/bip32': 1.6.0 + '@scure/bip39': 1.5.0 + abitype: 1.0.7(zod@3.23.8) + isows: 1.0.6(ws@8.18.0) + ox: 0.1.2(zod@3.23.8) + webauthn-p256: 0.0.10 + ws: 8.18.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + - zod + vite@6.0.3(@types/node@22.10.1)(jiti@2.4.1)(tsx@4.19.2)(yaml@2.6.1): dependencies: esbuild: 0.24.0