@laceio/sdk 0.1.1 → 0.1.2-canary.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{TransactionBuilder-DrB3NVTi.cjs → TransactionBuilder-X1H9Gze6.cjs} +64 -14
- package/dist/{TransactionBuilder-V6aLx4SV.js → TransactionBuilder-bp2aMDhg.js} +23 -15
- package/dist/{_polyfill-buffer-patch-BnPVerlG.cjs → _polyfill-buffer-patch-CM8X7JiY.cjs} +21 -2
- package/dist/_polyfill-buffer-patch-yNxN4d5E.js +1467 -0
- package/dist/_web-crypto-random-bytes-Bo-GTcRS.js +197 -0
- package/dist/acc-module-4iIUv6My.cjs +27654 -0
- package/dist/acc-module-Cmj8EsIb.js +27624 -0
- package/dist/account-BOQruszJ.js +6 -0
- package/dist/account-BUOj4pYJ.cjs +11 -0
- package/dist/account-call-7wnopBq0.cjs +5 -0
- package/dist/account-call-B9d_2Xwi.js +4 -0
- package/dist/account-call-Bd4Rpbvt.cjs +323 -0
- package/dist/account-call-C3CkDqEC.js +276 -0
- package/dist/account-guards-BtjTGxDZ.cjs +42 -0
- package/dist/account-guards-D9Lu5T3W.js +36 -0
- package/dist/account-tokens-DvkOFVON.js +16 -0
- package/dist/account-tokens-nwcvwLu4.cjs +21 -0
- package/dist/{activity-type.stable-BJEfeLxL.cjs → activity-type-Ch6ljxBy.cjs} +2 -1
- package/dist/{activity-type.stable-C76_hWd7.js → activity-type-GsJGWs-3.js} +2 -1
- package/dist/address-B9ntKL8K.js +13761 -0
- package/dist/address-BXp-mY8H.cjs +11270 -0
- package/dist/{address-book-address-validator-DIUolI-s.js → address-book-address-validator-0J9XAADH.js} +2 -2
- package/dist/address-book-address-validator-DK0dnsRS.cjs +41 -0
- package/dist/address-book-address-validator-Di_ywo8M.js +39 -0
- package/dist/{address-book-address-validator-DNwQGlOB.cjs → address-book-address-validator-Dte_YQ2L.cjs} +2 -2
- package/dist/artefact-loader-BWWYAD7E.cjs +183 -0
- package/dist/artefact-loader-Dik4HIfv.js +160 -0
- package/dist/auto-dismiss-failure-on-success-C-qoJuid.cjs +37 -0
- package/dist/auto-dismiss-failure-on-success-s8MGDEIu.js +31 -0
- package/dist/bip32-D6wd_QMn.cjs +3851 -0
- package/dist/bitcoin-data-provider-BYPSmuZS.js +21 -0
- package/dist/bitcoin-data-provider-w1oEDSU3.cjs +26 -0
- package/dist/bitcoin.cjs +45 -0
- package/dist/bitcoin.d.ts +29906 -1
- package/dist/bitcoin.js +20 -0
- package/dist/{blockfrost-tx-submit-provider-DPTrapz-.js → blockfrost-tx-submit-provider-CBWQ0wK9.js} +5 -157
- package/dist/{blockfrost-tx-submit-provider-BAIzV5o3.cjs → blockfrost-tx-submit-provider-CLNQ5ycR.cjs} +3 -167
- package/dist/bn-d3nSOIf7.cjs +2553 -0
- package/dist/browser-B1eMbDwh.js +7468 -0
- package/dist/bytes.vo-BB7_4JK6.js +23 -0
- package/dist/bytes.vo-BNRquqaO.cjs +34 -0
- package/dist/cardano-DfPwhwm-.js +3 -0
- package/dist/{cardano-network-id.vo-DSxrFk9S.cjs → cardano-network-id.vo-BEDPn6Li.cjs} +1 -1
- package/dist/{cardano-network-id.vo-CK1tNQDg.js → cardano-network-id.vo-Cfpvbod9.js} +1 -1
- package/dist/cardano.cjs +22 -18
- package/dist/cardano.d.ts +16962 -1716
- package/dist/cardano.js +16 -11
- package/dist/client-DXBLHk7K.cjs +808 -0
- package/dist/codecs-Cswkg7Tm.cjs +4051 -0
- package/dist/codecs-Dc1Krpbt.js +3903 -0
- package/dist/{const-C84qHkjp.js → const-BJfIK_G-.js} +4 -4
- package/dist/const-BhYOdznB.cjs +42 -0
- package/dist/const-BsnjG2_Q.cjs +32071 -0
- package/dist/const-CUnCl5U0.js +13 -0
- package/dist/{const-DXk2tFyv.js → const-CjmfjBP3.js} +1 -1
- package/dist/{const-BDEg2Trq.cjs → const-D-eZIS4n.cjs} +4 -4
- package/dist/const-D0CbQlo4.js +154 -0
- package/dist/{const-BY8B3_0_.cjs → const-iwzZEE_w.cjs} +1 -1
- package/dist/contract-1R86jhSw.js +171 -0
- package/dist/contract-MKLzYVkW.cjs +189 -0
- package/dist/create-add-accounts-Brqk84vF.js +102 -0
- package/dist/create-add-accounts-DzXIh7Ot.cjs +114 -0
- package/dist/{delegation-tx-builder-CRpLP6jH.cjs → delegation-tx-builder-Dof_0N_d.cjs} +6 -6
- package/dist/{delegation-tx-builder-CGVqlaFE.js → delegation-tx-builder-Dy3-2Auz.js} +5 -5
- package/dist/{deregistration-tx-builder-DZGwB4cz.cjs → deregistration-tx-builder-CcLwyFpj.cjs} +6 -6
- package/dist/{deregistration-tx-builder-B-CrUyX6.js → deregistration-tx-builder-QkWW_gWl.js} +5 -5
- package/dist/device-commitment-hex.vo-5wFtQvDS.js +26 -0
- package/dist/device-commitment-hex.vo-CT3RmAug.cjs +31 -0
- package/dist/device-readers-CUHYoYOH.js +145 -0
- package/dist/device-readers-CdxS2btd.cjs +168 -0
- package/dist/device-readers-D_JZeNL2.cjs +8 -0
- package/dist/device-readers-DwSNCGPP.js +4 -0
- package/dist/dist-BMi5ZjEq.cjs +43175 -0
- package/dist/dist-BtIq4XFn.cjs +535 -0
- package/dist/dist-C3SHC_Ho.cjs +1394 -0
- package/dist/dist-CykEjYEX.cjs +3814 -0
- package/dist/dist-Dcsxh3be.cjs +3452 -0
- package/dist/dist-DqJfSlTd.cjs +4413 -0
- package/dist/dist-nTZ70qj7.cjs +1306 -0
- package/dist/{earn-rewards-tx-builder-D5sUT5v8.cjs → earn-rewards-tx-builder-BP5JMIKS.cjs} +6 -6
- package/dist/{earn-rewards-tx-builder-BDbTDZmD.js → earn-rewards-tx-builder-Cku4BmNU.js} +5 -5
- package/dist/enc-key-circuits-B7BjgUL9.js +13 -0
- package/dist/enc-key-circuits-BLrZrBVI.cjs +24 -0
- package/dist/english-Byb9M0E_.cjs +2057 -0
- package/dist/envelopes-BGoO_v8m.js +1621 -0
- package/dist/envelopes-CH25R-DN.cjs +1722 -0
- package/dist/errors-BIftM8ZN.cjs +688 -0
- package/dist/errors-DSq5wUwt.js +466 -0
- package/dist/esm-HBSUQw3w.js +384 -0
- package/dist/esm-LZuaZjMf.cjs +389 -0
- package/dist/experimental.cjs +7349 -0
- package/dist/experimental.d.ts +86279 -0
- package/dist/experimental.js +7184 -0
- package/dist/gated-call-CDCVZIK-.cjs +5 -0
- package/dist/gated-call-D-tT7P_t.js +722 -0
- package/dist/gated-call-D_VT2quk.js +4 -0
- package/dist/gated-call-DgJm1Mi_.cjs +787 -0
- package/dist/grant-circuits-DswmW3nI.cjs +71 -0
- package/dist/grant-circuits-Jxb5y1HW.js +42 -0
- package/dist/grant-rules-By07_eDi.js +6824 -0
- package/dist/grant-rules-BzVTWXS7.cjs +7099 -0
- package/dist/grant-spend-B3Md9L0n.js +215 -0
- package/dist/grant-spend-oWmzRsjH.cjs +217 -0
- package/dist/grant-status-B2y49iIu.js +2688 -0
- package/dist/grant-status-DOr3t_u8.cjs +2820 -0
- package/dist/grants-2BZ-qEVQ.js +5 -0
- package/dist/grants-BPoLSiMt.cjs +18 -0
- package/dist/grants-BoI5uwSF.cjs +272 -0
- package/dist/grants-CtofFu-e.js +213 -0
- package/dist/{group-cardano-addresses-by-account-B533oVXR.cjs → group-cardano-addresses-by-account-Bp0g4wEY.cjs} +3 -39
- package/dist/{group-cardano-addresses-by-account-RHKoEskR.js → group-cardano-addresses-by-account-SR8MMrZf.js} +5 -35
- package/dist/{guarded-transaction-signer-Bxl6_XNd.cjs → guarded-transaction-signer-MFpPg98D.cjs} +17 -18
- package/dist/{guarded-transaction-signer-CpKLj8Kp.js → guarded-transaction-signer-P6Rp1faj.js} +8 -15
- package/dist/hex-D9ITYbwt.cjs +263 -0
- package/dist/hex-mkXcV3pN.js +191 -0
- package/dist/http-client-B3N-TMxu.cjs +167 -0
- package/dist/http-client-TRlhDZGh.js +155 -0
- package/dist/identity-BMLuufva.cjs +263 -0
- package/dist/identity-DII6f-h7.js +233 -0
- package/dist/in-memory-wallet-integration-B2xzxORj.cjs +20741 -0
- package/dist/in-memory-wallet-integration-CBRiPjLO.js +130 -0
- package/dist/in-memory-wallet-integration-CULUB5Tf.cjs +240 -0
- package/dist/{in-memory-wallet-integration-D-qn65Kx.js → in-memory-wallet-integration-ChIOirMW.js} +5 -2
- package/dist/{in-memory-wallet-integration-Croiuopx.js → in-memory-wallet-integration-CljprQQV.js} +7 -104
- package/dist/{in-memory-wallet-integration-DVh9sRXa.cjs → in-memory-wallet-integration-Cm6P8sk6.cjs} +3 -2
- package/dist/in-memory-wallet-integration-TM9bBphA.js +20738 -0
- package/dist/{in-memory-wallet-integration-CnLYeX4-.cjs → in-memory-wallet-integration-t9I00R_V.cjs} +17 -108
- package/dist/index.cjs +84 -47
- package/dist/index.d.ts +37505 -10036
- package/dist/index.js +52 -24
- package/dist/{init-CLHuAMB-.js → init-0zzs9aqU.js} +4 -4
- package/dist/{init-U8c9yHYx.cjs → init-5KcGcBb5.cjs} +1 -1
- package/dist/{init-CigestoM.js → init-B3-1ghyx.js} +2 -2
- package/dist/init-B8U3ABhS.cjs +107 -0
- package/dist/init-BJn-8_hf.js +141 -0
- package/dist/init-BPU3j8sT.cjs +6 -0
- package/dist/init-BRzH6xu-2.cjs +2797 -0
- package/dist/init-BmzfDaKL.js +1142 -0
- package/dist/{init-C-jErzp5.cjs → init-BopV9ed4.cjs} +2 -2
- package/dist/init-BpHTq2R5.js +105 -0
- package/dist/init-BpSITBfF.js +39 -0
- package/dist/{init-DX4WyB0R.cjs → init-BrdVzxei.cjs} +3 -3
- package/dist/{init-LfyMo-sS.cjs → init-BwkU0ruo.cjs} +2 -2
- package/dist/{init-CB__aLD7.cjs → init-C-G32J12.cjs} +2 -2
- package/dist/init-C00gw1zi.js +422 -0
- package/dist/{init-TkPq_Ny_.js → init-C2RgrfZe.js} +1 -1
- package/dist/init-C5mYyFTv.js +3584 -0
- package/dist/{init-DcYY6zMD.js → init-C8URA2OX.js} +1 -1
- package/dist/init-CDkRynJa.js +2796 -0
- package/dist/{init-Cg9XdAru.js → init-CNM5m7M2.js} +4 -4
- package/dist/init-CR7BfztQ.cjs +18 -0
- package/dist/{init-CSHwHnfg.cjs → init-CSDpdu0Q.cjs} +2 -2
- package/dist/{init-aJHl-7AO.js → init-CX0AMQUn.js} +2 -2
- package/dist/{init-FMGDET-9.js → init-CfTbSEKy.js} +259 -60
- package/dist/{init-CR6tpw1B.js → init-Cigr_tKx.js} +47 -43
- package/dist/init-Clu8pxwQ.cjs +1181 -0
- package/dist/{init-CFYsq82V.js → init-CyAY4Lzl.js} +1 -1
- package/dist/{init-BKhH6mVR.cjs → init-D6BxBs7e.cjs} +1 -1
- package/dist/init-D8OeObDF.cjs +1141 -0
- package/dist/init-D9g1HXYf.cjs +40 -0
- package/dist/{init-CNLGJJRx.js → init-DA7zmptx.js} +1 -1
- package/dist/{init-DkIc5nqF.cjs → init-DFMiP2ZH.cjs} +1 -1
- package/dist/{init-zSzCjoor.js → init-DFjT8YvT.js} +4 -4
- package/dist/init-DGjXwWs2.cjs +143 -0
- package/dist/init-DHrCbpkW.cjs +121 -0
- package/dist/init-DRzJR02G.cjs +3585 -0
- package/dist/{init-B64zCLxG.cjs → init-DUF4ar8P.cjs} +4 -4
- package/dist/init-DlqJuHhl.js +119 -0
- package/dist/{init-y2Ra0vZP.js → init-Dnsv155v.js} +3 -3
- package/dist/init-DuYENxci.js +17 -0
- package/dist/{init-D6DBUsD3.cjs → init-Dv3zKj0r.cjs} +4 -4
- package/dist/{init-BtzMZ7Pk.cjs → init-Dy-05ktr.cjs} +1 -1
- package/dist/{init-BsCBAGWf.cjs → init-EP0CUWNK.cjs} +2 -2
- package/dist/{init-BJVU54pI.cjs → init-EhzD7a8i.cjs} +1 -1
- package/dist/{init-w9GEs73W.js → init-Fw89ZmrR.js} +2 -2
- package/dist/init-GsT2AEa4.cjs +424 -0
- package/dist/{init-Rxohwpmu.js → init-NCjgwCZy.js} +2 -2
- package/dist/{init-DxUHsN53.cjs → init-NdhG_VrF.cjs} +6 -6
- package/dist/{init-DDdhguVC.js → init-SZ01tARX2.js} +2 -2
- package/dist/{init-BAJJzBza.js → init-Y3mkB4XS.js} +2 -2
- package/dist/init-c4l6r-o-.js +5 -0
- package/dist/{init-Dku4b2lG.js → init-kEfUTuG2.js} +1 -1
- package/dist/{init-C7IeJwQR.cjs → init-lzHt4Cli.cjs} +256 -59
- package/dist/init-qSEd_Spq.js +1182 -0
- package/dist/{init-anYu6XB7.cjs → init-rmt7-fQE.cjs} +2 -2
- package/dist/{init-C4Bkib9u.cjs → init-zU-_9Gsp.cjs} +67 -65
- package/dist/{is-retriable-error-BU0e3hVI.js → is-retriable-error-BUiVJDwH.js} +1 -1
- package/dist/{is-retriable-error-CeeuHqDa.cjs → is-retriable-error-Dpt860if.cjs} +1 -1
- package/dist/jubjub-authoriser-D7zDXu3V.js +86 -0
- package/dist/jubjub-authoriser-Dgu6o3Sv.cjs +87 -0
- package/dist/key-source-5oUBFiC7.cjs +583 -0
- package/dist/key-source-B08HukZg.js +2550 -0
- package/dist/keyDerivation-D3k9XyHg.js +4077 -0
- package/dist/keyDerivation-u0nBA93T.cjs +274 -0
- package/dist/{lace-context-CZcNHr4M.js → lace-context-BZciB9c7.js} +4 -4
- package/dist/{lace-context-fJTDghdp.cjs → lace-context-DgR6vLli.cjs} +4 -4
- package/dist/lib--iqvW4O_.js +2354 -0
- package/dist/lib-Yk6Upl5D.cjs +2359 -0
- package/dist/{libsodium-wrappers-UH0LaOUE.js → libsodium-wrappers-BhbOA8dQ.js} +3 -1647
- package/dist/midnight-account-id.vo-0x9X-r3l.cjs +10 -0
- package/dist/midnight-account-id.vo-DjCAGcqc.js +5 -0
- package/dist/midnight-engine-DpemplKO.js +5 -0
- package/dist/midnight-engine-xU1wotne.cjs +6 -0
- package/dist/midnight-wallet-DIsAlSn6.js +18 -0
- package/dist/midnight-wallet-XTZc2li7.cjs +24 -0
- package/dist/midnight.cjs +1408 -0
- package/dist/midnight.d.ts +28934 -0
- package/dist/midnight.js +1352 -0
- package/dist/modules-cardano-D9Gs2j60.cjs +1108 -0
- package/dist/modules-cardano-VIM8fKu-.js +995 -0
- package/dist/node-relay-DWe1U0w2.cjs +49 -0
- package/dist/node-relay-h4i5IlAQ.js +48 -0
- package/dist/outputs-Bd2yZVjx.js +720 -0
- package/dist/outputs-CJoQBIA2.cjs +990 -0
- package/dist/pbkdf2-CIW-oWrm.cjs +1337 -0
- package/dist/pending-operation-B0_P78Jo.cjs +26 -0
- package/dist/pending-operation-BIS6mpjB.js +21 -0
- package/dist/providers-FjhM47BH.cjs +388 -0
- package/dist/providers-WtiSuxFu.js +365 -0
- package/dist/redacted-BmE2aXqr.js +81 -0
- package/dist/redacted-CRZJLS3w.cjs +86 -0
- package/dist/{retry-config-DC5IMaH7.cjs → retry-config-BaCfVC1H.cjs} +1 -1
- package/dist/{retry-config-BcUmMS--.js → retry-config-Dmgt28wM.js} +1 -1
- package/dist/safe-buffer-B_vMqJWU.js +43 -0
- package/dist/safe-buffer-DYOwEfHB.cjs +48 -0
- package/dist/sdk-Cb-gZnS9.js +1241 -0
- package/dist/sdk-DffwmX8b.cjs +1439 -0
- package/dist/sdk-init-Bln9rFtn.js +4138 -0
- package/dist/sdk-init-CYViTJY_.cjs +3841 -0
- package/dist/{seam-cardano-CATqBEyK.js → seam-cardano-B_etH4F4.js} +1 -1
- package/dist/{bytes.vo-TgiwogWF.js → secret-box-DUR0ACYz.js} +3 -25
- package/dist/{bytes.vo-Ck5u40RA.cjs → secret-box-DrjLZuS1.cjs} +1 -35
- package/dist/send-proof-progress-C-ljq1x5.js +30 -0
- package/dist/send-proof-progress-vmsaSfbz.cjs +47 -0
- package/dist/side-effects-BnqYz7Nl.js +768 -0
- package/dist/side-effects-CngaeXi0.cjs +804 -0
- package/dist/sign-bitcoin-transaction-with-seed-D4z62-jV.js +147 -0
- package/dist/sign-bitcoin-transaction-with-seed-DsLYXnCY.cjs +158 -0
- package/dist/signer-3fk8lZtE.cjs +7 -0
- package/dist/signer-CsL28DrK.cjs +121 -0
- package/dist/signer-DGluibtn.js +92 -0
- package/dist/signer-RqB5pu3K.js +2 -0
- package/dist/signer-factory-BA7WFJVZ.js +282 -0
- package/dist/signer-factory-Cwd6o-lG.cjs +281 -0
- package/dist/{signer-factory-9URFliA5.js → signer-factory-DObB55D4.js} +6 -3
- package/dist/signer-factory-DhZiE03y.cjs +149 -0
- package/dist/{signer-factory-BWGUmnvm.cjs → signer-factory-Ds6G2AZk.cjs} +4 -3
- package/dist/signer-factory-hzSRaIw2.js +148 -0
- package/dist/{slice-CuHUaPZx.cjs → slice-7G2xxYKJ.cjs} +3 -3
- package/dist/{slice-DZmQJNV8.cjs → slice-B4CdYoPu.cjs} +2 -2
- package/dist/slice-BPNuHKfw.js +9091 -0
- package/dist/{slice-DGcNrbPR.cjs → slice-Bg6HEr3K.cjs} +4 -4
- package/dist/{slice-DtaO72qY.cjs → slice-Bs2aMERu.cjs} +3 -3
- package/dist/{slice-HeHCv3bl.cjs → slice-C34iOOUH.cjs} +7 -7
- package/dist/{slice-Do2R2CYW.cjs → slice-C9TT5KhY.cjs} +6 -6
- package/dist/{slice-eIwcwKHI.js → slice-CK07EBCo.js} +4 -4
- package/dist/{slice-CnyWevM9.js → slice-CU80pbiu.js} +3 -3
- package/dist/{slice-CobanYgn.js → slice-CwyYrh1H.js} +2 -2
- package/dist/slice-Czfp6t84.cjs +436 -0
- package/dist/{slice-d0p6-xj5.js → slice-D-9aPKG-.js} +6 -6
- package/dist/{slice-maaskdUn.js → slice-DBpJ2QGf.js} +6 -6
- package/dist/{slice-mxLQ_FeY.cjs → slice-DTZTiJle.cjs} +352 -39
- package/dist/{slice-zJ9XVYjZ.js → slice-Da426sf9.js} +1 -1
- package/dist/{slice-D11m2EKl.cjs → slice-DayJvMRD.cjs} +1 -1
- package/dist/slice-DnBWfA-k.cjs +9109 -0
- package/dist/{slice-oqm_r1cS.cjs → slice-DnG-yvpI.cjs} +2 -2
- package/dist/{slice-BNu73oBa.js → slice-DyNs7oWp.js} +2 -2
- package/dist/{slice-CB4SnzMm.js → slice-GwiiJRoq.js} +3 -3
- package/dist/slice-oWnc7YVD.js +412 -0
- package/dist/{slice-B2PhoWAg.js → slice-qt0uBExh.js} +325 -37
- package/dist/slice-t8Gzj55G2.cjs +106 -0
- package/dist/slice-t8Q1cHm-.js +88 -0
- package/dist/src-BDzYIksE.cjs +20637 -0
- package/dist/src-BFoefPv_.js +20755 -0
- package/dist/store-B1Lq3cEf.cjs +66 -0
- package/dist/store-DuBG8qh5.js +37 -0
- package/dist/submit-Bs77dPn_.cjs +413 -0
- package/dist/submit-DOv8Z0Vf.js +336 -0
- package/dist/submit-bitcoin-tx-D6oYgH5S.js +983 -0
- package/dist/submit-bitcoin-tx-goFuRL7K.cjs +1049 -0
- package/dist/{sync-operation-utils-BYXLO80m.js → sync-operation-utils-31iFLExW.js} +2 -38
- package/dist/{sync-operation-utils-SdPbwFoD.cjs → sync-operation-utils-COIZ66-I.cjs} +1 -67
- package/dist/token-id-mapper-Bnds3xKH.cjs +18 -0
- package/dist/{token-id-mapper-DsPAL6Nh.cjs → token-id-mapper-CVyQJUKY.cjs} +2 -2
- package/dist/token-id-mapper-CnKHQ8DV.js +16 -0
- package/dist/{token-id-mapper-B2ivlLv3.js → token-id-mapper-D29Ggv8h.js} +2 -2
- package/dist/tokens-Cevp7rdU.cjs +62 -0
- package/dist/tokens-Diw4MLRM.js +44 -0
- package/dist/types-B8uiJn-X.js +12 -0
- package/dist/types-BHC12eSa.js +33 -0
- package/dist/types-CJT6XF2c.js +10 -0
- package/dist/types-CLRUYpfe.cjs +23 -0
- package/dist/types-Cc3mC8u0.cjs +50 -0
- package/dist/types-DWbVZpnF.cjs +15 -0
- package/dist/unwrap-provider-result-BZSiwabU.js +32 -0
- package/dist/unwrap-provider-result-ZqfBsTkk.cjs +39 -0
- package/dist/{util-CGzqQ8IV.cjs → util-Bu4W5lF4.cjs} +1 -1
- package/dist/{util-BaLzwa32.js → util-Cp5cZkfK.js} +1 -1
- package/dist/{utils-o8aMjfln.js → utils-BfBEUvWA.js} +2 -2
- package/dist/utils-DFwzEvbv.js +65 -0
- package/dist/{utils-5JvjbqH3.cjs → utils-DsElZgCI.cjs} +7 -1
- package/dist/utils-IXxR-Djh.cjs +112 -0
- package/dist/v8Signatures-CO_Uloy7.cjs +71 -0
- package/dist/{vote-delegation-tx-builder-CmKv6GoG.js → vote-delegation-tx-builder-BsBSDmcX.js} +5 -5
- package/dist/{vote-delegation-tx-builder-BpEMSti4.cjs → vote-delegation-tx-builder-DSs8nybk.cjs} +6 -6
- package/dist/watch-CUEvcP-V.js +21997 -0
- package/dist/watch-DMF2s-II.cjs +52281 -0
- package/package.json +96 -4
- package/dist/account-guards.stable-B1DSSh9D.cjs +0 -10
- package/dist/account-guards.stable-JRQ5qx2V.js +0 -5
- package/dist/codecs-B7X9pAsK.cjs +0 -1945
- package/dist/codecs-CC1Xjntz.js +0 -1882
- package/dist/init-Bv53hpLM.js +0 -19
- package/dist/init-CRbjI7p1.js +0 -3494
- package/dist/init-DAna1KCg.cjs +0 -3495
- package/dist/init-DGe47B22.cjs +0 -364
- package/dist/init-DMtyvYfC.cjs +0 -21
- package/dist/init-TkPDD750.js +0 -363
- package/dist/modules-cardano-BDvuL4Xx.js +0 -5248
- package/dist/modules-cardano-D2G3De2P.cjs +0 -5432
- package/dist/slice-CGVHXHDt.cjs +0 -125
- package/dist/slice-DhvF7L6X.js +0 -107
- /package/dist/{account-id.vo-LvCBVn5r.cjs → account-id.vo-DwqFjK5u.cjs} +0 -0
- /package/dist/{account-id.vo-MYSI7YFm.js → account-id.vo-OPz2v-JZ.js} +0 -0
- /package/dist/{actions-DdGbj7c7.cjs → actions-B2BJ4RTy.cjs} +0 -0
- /package/dist/{actions-9QSQR-GB.js → actions-iLXdgL5Y.js} +0 -0
- /package/dist/{apply-vkey-witnesses-ClZbpk5w.js → apply-vkey-witnesses-BKx3lcs0.js} +0 -0
- /package/dist/{apply-vkey-witnesses-CLzVSWxl.cjs → apply-vkey-witnesses-ZnFS0jnJ.cjs} +0 -0
- /package/dist/{asyncoption-Cw07zPH7.js → asyncoption-CruEYOBI.js} +0 -0
- /package/dist/{asyncoption-DYoGuQfP.cjs → asyncoption-i0VbqVTq.cjs} +0 -0
- /package/dist/{bignum.vo-B0rK_PQ1.js → bignum.vo-CEXOIew0.js} +0 -0
- /package/dist/{bignum.vo-DsG3kNiZ.cjs → bignum.vo-hx2kuqlA.cjs} +0 -0
- /package/dist/{bip32ed25519-1ApqeAZk.cjs → bip32ed25519-B7Yat217.cjs} +0 -0
- /package/dist/{bip32ed25519-DetAdGwD.js → bip32ed25519-FQ8qvdcq.js} +0 -0
- /package/dist/{blake2b-DOEVc57D.js → blake2b-BiQTw3GC.js} +0 -0
- /package/dist/{blake2b-B9tftbvG.cjs → blake2b-DEeVUdKR.cjs} +0 -0
- /package/dist/{blockchain-network-id.vo-BXpZhvvQ.cjs → blockchain-network-id.vo-BAKEwGjG.cjs} +0 -0
- /package/dist/{blockchain-network-id.vo-DNRkuT5B.js → blockchain-network-id.vo-CiVykuqG.js} +0 -0
- /package/dist/{blockingWithLatestFrom-C5wp_uA-.js → blockingWithLatestFrom-Cd8c8EPG.js} +0 -0
- /package/dist/{blockingWithLatestFrom-DY8OPg0w.cjs → blockingWithLatestFrom-D8kBPBMX.cjs} +0 -0
- /package/dist/{cardano-network-id-to-network-type-CrZfUcyP.js → cardano-network-id-to-network-type-BWwzeEtM.js} +0 -0
- /package/dist/{cardano-network-id-to-network-type-BDTF-HmK.cjs → cardano-network-id-to-network-type-C0ufJOyE.cjs} +0 -0
- /package/dist/{cardano-tx-id.vo-BPhV-AmZ.cjs → cardano-tx-id.vo-TLjJZHCI.cjs} +0 -0
- /package/dist/{cardano-tx-id.vo-DF9NzZXk.js → cardano-tx-id.vo-eVnKuzlm.js} +0 -0
- /package/dist/{composite-signer-factory-_46QsNBz.js → composite-signer-factory-CR8YHA1y.js} +0 -0
- /package/dist/{composite-signer-factory-BpF1mIYA.cjs → composite-signer-factory-m5cVs9h_.cjs} +0 -0
- /package/dist/{error-CNIquqT5.cjs → error-Cb3EnD0u.cjs} +0 -0
- /package/dist/{error-BCp9NkPi.js → error-DIZOY2Lw.js} +0 -0
- /package/dist/{esm-browser-C93Q-EOI.js → esm-browser-MG97cre9.js} +0 -0
- /package/dist/{esm-browser-DTc9IK3D.cjs → esm-browser-bweqfBlL.cjs} +0 -0
- /package/dist/{feature-flag-key.vo-ofrB6ZVQ.js → feature-flag-key.vo-DN_-4-sG.js} +0 -0
- /package/dist/{feature-flag-key.vo-BPz-ZAp6.cjs → feature-flag-key.vo-RlfHL3hq.cjs} +0 -0
- /package/dist/{first-state-of-status-OROkXcRv.cjs → first-state-of-status-CbT7hPa4.cjs} +0 -0
- /package/dist/{first-state-of-status-DQnMT3ya.js → first-state-of-status-unPynOuM.js} +0 -0
- /package/dist/{init-Es3wHW7D.js → init-829HRYcz.js} +0 -0
- /package/dist/{init-CKipPE_c.js → init-A-VyGSNW2.js} +0 -0
- /package/dist/{init-DFQQ9dTW.cjs → init-Atisw4x2.cjs} +0 -0
- /package/dist/{init-C5CEZ1m0.cjs → init-BFcvPHL-.cjs} +0 -0
- /package/dist/{init-IAk_CkGa.cjs → init-BgNobbNq.cjs} +0 -0
- /package/dist/{init-cqN3uX2j.js → init-atCFur0v.js} +0 -0
- /package/dist/{is-redux-persist-state-CTn3WZVh.cjs → is-redux-persist-state-BCFnSm36.cjs} +0 -0
- /package/dist/{is-redux-persist-state-Cxcd0_bM.js → is-redux-persist-state-yBfq0h_E.js} +0 -0
- /package/dist/{key-value-store-8cMzeNyG.js → key-value-store--W3SrMaw.js} +0 -0
- /package/dist/{key-value-store-DUAepXQf.cjs → key-value-store-C2Xt5Emp.cjs} +0 -0
- /package/dist/{repo-slice-WxetRhMY.cjs → repo-slice-7X4AYYVm.cjs} +0 -0
- /package/dist/{repo-slice-DwyMhCR1.js → repo-slice-RxFm0zDZ.js} +0 -0
- /package/dist/{reselect-CRDqmQY9.cjs → reselect-Bd94u0K-.cjs} +0 -0
- /package/dist/{reselect-C06X06oX.js → reselect-CGoLzEPv.js} +0 -0
- /package/dist/{serializable-B8GahgE1.js → serializable-BHdKIgk3.js} +0 -0
- /package/dist/{serializable-CRdnFaLZ.cjs → serializable-BxHkoPdk.cjs} +0 -0
- /package/dist/{slice-D11FHQuQ.cjs → slice-BiRsDKOK.cjs} +0 -0
- /package/dist/{slice-Be7hj4Iy.js → slice-Bk0Sv05J.js} +0 -0
- /package/dist/{slice-FioKeHtA.cjs → slice-Dqw1ecum.cjs} +0 -0
- /package/dist/{slice-B87b52iM.js → slice-obCSLm1x.js} +0 -0
- /package/dist/{src-vq1wS9sZ.js → src-BlxEp6Mm.js} +0 -0
- /package/dist/{src-BTPIvlDI.cjs → src-Cqp0B2M_.cjs} +0 -0
- /package/dist/{time.vo-CQ8pSXz2.cjs → time.vo-D3wWRw9L.cjs} +0 -0
- /package/dist/{time.vo-DkYYGYp6.js → time.vo-tNheinXm.js} +0 -0
- /package/dist/{toEmpty-CgAl3097.js → toEmpty-8Zax1MPd.js} +0 -0
- /package/dist/{toEmpty-DAMmNB5r.cjs → toEmpty-CYAbupM4.cjs} +0 -0
- /package/dist/{token-id.vo-ClsroxHO.js → token-id.vo-Bvwhr3ZE.js} +0 -0
- /package/dist/{token-id.vo-BxG9TG0O.cjs → token-id.vo-DXv5uS9n.cjs} +0 -0
- /package/dist/{util-DxzlYNS5.js → util-C8a4fA9p.js} +0 -0
- /package/dist/{util-CmdAhheh.cjs → util-CzeB3hfa.cjs} +0 -0
- /package/dist/{util-selector-CcK-GAdE.js → util-selector-BSTsxgne.js} +0 -0
- /package/dist/{util-selector-BcAncU4L.cjs → util-selector-BWPH68_l.cjs} +0 -0
- /package/dist/{while-active-BpppWuCs.js → while-active-B0lWy_6l.js} +0 -0
- /package/dist/{while-active-Dhc2LwOm.cjs → while-active-Dsowp0Fi.cjs} +0 -0
|
@@ -0,0 +1,3841 @@
|
|
|
1
|
+
const require_rolldown_runtime = require("./rolldown-runtime-Br2OG8yv.cjs");
|
|
2
|
+
const require__polyfill_buffer_patch = require("./_polyfill-buffer-patch-CM8X7JiY.cjs");
|
|
3
|
+
require("./codecs-Cswkg7Tm.cjs");
|
|
4
|
+
const require_bytes_vo = require("./bytes.vo-BNRquqaO.cjs");
|
|
5
|
+
const require_time_vo = require("./time.vo-D3wWRw9L.cjs");
|
|
6
|
+
const require_bignum_vo = require("./bignum.vo-hx2kuqlA.cjs");
|
|
7
|
+
const require_auto_dismiss_failure_on_success = require("./auto-dismiss-failure-on-success-C-qoJuid.cjs");
|
|
8
|
+
require("./retry-config-BaCfVC1H.cjs");
|
|
9
|
+
const require_activity_type = require("./activity-type-Ch6ljxBy.cjs");
|
|
10
|
+
const require_token_id_vo = require("./token-id.vo-DXv5uS9n.cjs");
|
|
11
|
+
const require_types = require("./types-DWbVZpnF.cjs");
|
|
12
|
+
require("./bn-d3nSOIf7.cjs");
|
|
13
|
+
const require_const = require("./const-BsnjG2_Q.cjs");
|
|
14
|
+
const require_watch = require("./watch-DMF2s-II.cjs");
|
|
15
|
+
const require_slice = require("./slice-Czfp6t84.cjs");
|
|
16
|
+
const require_utils = require("./utils-IXxR-Djh.cjs");
|
|
17
|
+
const require_midnight_wallet = require("./midnight-wallet-XTZc2li7.cjs");
|
|
18
|
+
const require_dist = require("./dist-BtIq4XFn.cjs");
|
|
19
|
+
require("./client-DXBLHk7K.cjs");
|
|
20
|
+
const require_send_proof_progress = require("./send-proof-progress-vmsaSfbz.cjs");
|
|
21
|
+
let _laceio_cardano_util = require("@laceio/cardano/util");
|
|
22
|
+
let rxjs = require("rxjs");
|
|
23
|
+
rxjs = require_rolldown_runtime.__toESM(rxjs);
|
|
24
|
+
let lodash_isEqual = require("lodash/isEqual.js");
|
|
25
|
+
lodash_isEqual = require_rolldown_runtime.__toESM(lodash_isEqual);
|
|
26
|
+
let _midnight_ntwrk_ledger_v8 = require("@midnight-ntwrk/ledger-v8");
|
|
27
|
+
_midnight_ntwrk_ledger_v8 = require_rolldown_runtime.__toESM(_midnight_ntwrk_ledger_v8);
|
|
28
|
+
//#region ../../packages/contract/midnight-context/src/value-objects/midnight-address.vo.ts
|
|
29
|
+
const MidnightShieldedAddress = (address) => address;
|
|
30
|
+
const MidnightUnshieldedAddress = (address) => address;
|
|
31
|
+
const MidnightDustAddress = (address) => address;
|
|
32
|
+
//#endregion
|
|
33
|
+
//#region ../../packages/contract/midnight-context/src/value-objects/serialised-wallet-state.vo.ts
|
|
34
|
+
/**
|
|
35
|
+
* Either encoding. Production only ever constructs this from the SDK's
|
|
36
|
+
* verbatim JSON; the hex form comes back from storage on older profiles.
|
|
37
|
+
*/
|
|
38
|
+
const SerialisedWalletState = (value) => value;
|
|
39
|
+
/**
|
|
40
|
+
* A heuristic over the values we actually persist, not a parse: hex and JSON
|
|
41
|
+
* overlap (`12345678` is both), so nothing can separate them in general. Every
|
|
42
|
+
* blob written here opens with `{`; `[` is headroom for a serialiser that
|
|
43
|
+
* returns a top-level array. Anything else reads as hex, and a wrong guess
|
|
44
|
+
* costs a rebuild from seed, which the restore path already handles.
|
|
45
|
+
*
|
|
46
|
+
* First character only: matching hex across the whole payload cost ~2500ms
|
|
47
|
+
* against 10k documents of 100k characters, against ~8ms here, and was
|
|
48
|
+
* case-sensitive so it missed uppercase hex besides.
|
|
49
|
+
*/
|
|
50
|
+
const isVerbatimJson = (value) => value.startsWith("{") || value.startsWith("[");
|
|
51
|
+
SerialisedWalletState.toJSON = (value) => isVerbatimJson(value) ? value : require_bytes_vo.HexBytes.toUTF8(value);
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region ../../packages/contract/midnight-context/src/midnight-accounts.ts
|
|
54
|
+
/** Two account lists are the same run of accounts when their ids line up in
|
|
55
|
+
* order — the identity the account stream re-emits on. */
|
|
56
|
+
const sameAccounts = (accounts1, accounts2) => {
|
|
57
|
+
if (accounts1.length !== accounts2.length) return false;
|
|
58
|
+
for (let index = 0; index < accounts1.length; index++) if (accounts1[index].accountId !== accounts2[index].accountId) return false;
|
|
59
|
+
return true;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* The in-memory Midnight accounts on the active Midnight network, as a stream
|
|
63
|
+
* that only re-emits when the run of account ids actually changes. Emits an
|
|
64
|
+
* empty list while the wallet repo is migrating, so a consumer never acts on a
|
|
65
|
+
* half-migrated repo. Nothing is emitted until a Midnight network is registered.
|
|
66
|
+
*/
|
|
67
|
+
const midnightAccounts$ = (state) => (0, rxjs.combineLatest)([
|
|
68
|
+
state.wallets.selectActiveNetworkAccounts$,
|
|
69
|
+
state.midnightContext.selectMidnightBlockchainNetworkId$.pipe((0, rxjs.filter)(Boolean)),
|
|
70
|
+
state.wallets.selectIsWalletRepoMigrating$
|
|
71
|
+
]).pipe((0, rxjs.map)(([accounts, activeNetwork, isWalletRepoMigrating]) => isWalletRepoMigrating ? [] : accounts.filter(require_utils.isInMemoryMidnightAccount).filter((account) => account.blockchainNetworkId === activeNetwork)), (0, rxjs.distinctUntilChanged)(sameAccounts));
|
|
72
|
+
//#endregion
|
|
73
|
+
//#region ../../packages/contract/midnight-context/src/register-midnight-blockchain-networks.ts
|
|
74
|
+
/**
|
|
75
|
+
* Registers the Midnight networks with the global network store once, the
|
|
76
|
+
* first time it reports Midnight absent. Every loadout with Midnight accounts
|
|
77
|
+
* needs this: `wallets.selectActiveNetworkAccounts` drops the accounts of an
|
|
78
|
+
* unregistered blockchain. The registration lands a tick after this decides,
|
|
79
|
+
* so it sets the networks only while Midnight still has none: a network the
|
|
80
|
+
* consumer selected in between keeps precedence.
|
|
81
|
+
*
|
|
82
|
+
* An existing Midnight account pins the testnet selection to its own network,
|
|
83
|
+
* so a profile created before the network store existed keeps syncing where
|
|
84
|
+
* its account lives; otherwise the default testnet is selected.
|
|
85
|
+
*/
|
|
86
|
+
const registerMidnightBlockchainNetworks = (_, { network: { selectBlockchainNetworks$ }, midnightContext: { selectDefaultTestNetNetworkId$ }, wallets: { selectAll$ } }, { actions }) => selectBlockchainNetworks$.pipe((0, rxjs.filter)((blockchainNetworks) => !blockchainNetworks?.Midnight), (0, rxjs.withLatestFrom)(selectDefaultTestNetNetworkId$, selectAll$.pipe((0, rxjs.map)((allWallets) => allWallets.flatMap((wallet) => wallet.accounts)))), (0, rxjs.map)(([, defaultTestNetNetworkId, accounts]) => {
|
|
87
|
+
const existingMidnightAccount = accounts.find((account) => account.blockchainName === "Midnight");
|
|
88
|
+
const testnetNetworkId = existingMidnightAccount ? existingMidnightAccount.blockchainSpecific.networkId : defaultTestNetNetworkId;
|
|
89
|
+
return actions.network.registerBlockchainNetworks({
|
|
90
|
+
blockchain: "Midnight",
|
|
91
|
+
mainnet: require_const.MidnightNetworkId("mainnet"),
|
|
92
|
+
testnet: require_const.MidnightNetworkId(testnetNetworkId)
|
|
93
|
+
});
|
|
94
|
+
}));
|
|
95
|
+
//#endregion
|
|
96
|
+
//#region ../../packages/lib/vendor/src/midnight-facade-reservations.ts
|
|
97
|
+
const NO_BALANCING_TRANSACTION = "No balancing transaction was created. Please check your transaction.";
|
|
98
|
+
const releasingOnFailure = async (build) => {
|
|
99
|
+
const releases = [];
|
|
100
|
+
const reserve = (transaction, holder) => {
|
|
101
|
+
if (transaction) releases.push(async () => holder.revertTransaction(transaction));
|
|
102
|
+
return transaction;
|
|
103
|
+
};
|
|
104
|
+
try {
|
|
105
|
+
return await build(reserve);
|
|
106
|
+
} catch (error) {
|
|
107
|
+
await Promise.allSettled(releases.map(async (release) => release()));
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
const merge$2 = (first, second) => first && second ? first.merge(second) : first ?? second;
|
|
112
|
+
const kindsToBalance = (tokenKindsToBalance = "all") => {
|
|
113
|
+
const kinds = tokenKindsToBalance === "all" ? [
|
|
114
|
+
"shielded",
|
|
115
|
+
"unshielded",
|
|
116
|
+
"dust"
|
|
117
|
+
] : tokenKindsToBalance;
|
|
118
|
+
return {
|
|
119
|
+
dust: kinds.includes("dust"),
|
|
120
|
+
shielded: kinds.includes("shielded"),
|
|
121
|
+
unshielded: kinds.includes("unshielded")
|
|
122
|
+
};
|
|
123
|
+
};
|
|
124
|
+
/**
|
|
125
|
+
* The wallet SDK's multi-step builds over `facade`, releasing the coins the
|
|
126
|
+
* completed steps reserved when a later step fails. The wallet SDK keeps
|
|
127
|
+
* them, and its caller gets an error with no recipe to release. Each build
|
|
128
|
+
* takes the same steps over the same sub-wallets as its `WalletFacade`
|
|
129
|
+
* namesake and returns the same recipe.
|
|
130
|
+
*/
|
|
131
|
+
const withReservationRelease = (facade) => ({
|
|
132
|
+
balanceFinalizedTransaction: async (transaction, { shieldedSecretKeys, dustSecretKey }, { ttl, tokenKindsToBalance }) => releasingOnFailure(async (reserve) => {
|
|
133
|
+
const balance = kindsToBalance(tokenKindsToBalance);
|
|
134
|
+
const unshieldedBalancing = balance.unshielded ? reserve(await facade.unshielded.balanceFinalizedTransaction(transaction), facade.unshielded) : void 0;
|
|
135
|
+
const tokenBalancing = merge$2(balance.shielded ? reserve(await facade.shielded.balanceTransaction(shieldedSecretKeys, transaction), facade.shielded) : void 0, unshieldedBalancing);
|
|
136
|
+
const balancingTransaction = merge$2(tokenBalancing, balance.dust ? await facade.dust.balanceTransactions(dustSecretKey, tokenBalancing ? [transaction, tokenBalancing] : [transaction], ttl) : void 0);
|
|
137
|
+
if (!balancingTransaction) throw new Error(NO_BALANCING_TRANSACTION);
|
|
138
|
+
return {
|
|
139
|
+
type: "FINALIZED_TRANSACTION",
|
|
140
|
+
originalTransaction: transaction,
|
|
141
|
+
balancingTransaction
|
|
142
|
+
};
|
|
143
|
+
}),
|
|
144
|
+
balanceUnboundTransaction: async (transaction, { shieldedSecretKeys, dustSecretKey }, { ttl, tokenKindsToBalance }) => releasingOnFailure(async (reserve) => {
|
|
145
|
+
const balance = kindsToBalance(tokenKindsToBalance);
|
|
146
|
+
const shieldedBalancing = balance.shielded ? reserve(await facade.shielded.balanceTransaction(shieldedSecretKeys, transaction), facade.shielded) : void 0;
|
|
147
|
+
const balancedUnshielded = balance.unshielded ? await facade.unshielded.balanceUnboundTransaction(transaction) : void 0;
|
|
148
|
+
const baseTransaction = balancedUnshielded ?? transaction;
|
|
149
|
+
const balancingTransaction = merge$2(shieldedBalancing, balance.dust ? await facade.dust.balanceTransactions(dustSecretKey, shieldedBalancing ? [baseTransaction, shieldedBalancing] : [baseTransaction], ttl) : void 0);
|
|
150
|
+
if (!balancingTransaction && !balancedUnshielded) throw new Error(NO_BALANCING_TRANSACTION);
|
|
151
|
+
return {
|
|
152
|
+
type: "UNBOUND_TRANSACTION",
|
|
153
|
+
baseTransaction,
|
|
154
|
+
balancingTransaction: balancingTransaction ?? void 0
|
|
155
|
+
};
|
|
156
|
+
}),
|
|
157
|
+
transferTransaction: async (outputs, { shieldedSecretKeys, dustSecretKey }, { ttl, payFees = true }) => releasingOnFailure(async (reserve) => {
|
|
158
|
+
const shieldedOutputs = outputs.flatMap((output) => output.type === "shielded" ? output.outputs : []);
|
|
159
|
+
const unshieldedOutputs = outputs.flatMap((output) => output.type === "unshielded" ? output.outputs : []);
|
|
160
|
+
if (unshieldedOutputs.length === 0 && shieldedOutputs.length === 0) throw new Error("At least one shielded or unshielded output is required.");
|
|
161
|
+
const transfer = merge$2(shieldedOutputs.length > 0 ? reserve(await facade.shielded.transferTransaction(shieldedSecretKeys, shieldedOutputs), facade.shielded) : void 0, unshieldedOutputs.length > 0 ? reserve(await facade.unshielded.transferTransaction(unshieldedOutputs, ttl), facade.unshielded) : void 0);
|
|
162
|
+
if (!transfer) throw new Error("Unexpected transaction state.");
|
|
163
|
+
return {
|
|
164
|
+
type: "UNPROVEN_TRANSACTION",
|
|
165
|
+
transaction: merge$2(transfer, payFees ? await facade.dust.balanceTransactions(dustSecretKey, [transfer], ttl) : void 0) ?? transfer
|
|
166
|
+
};
|
|
167
|
+
}),
|
|
168
|
+
initSwap: async ({ desiredInputs, desiredOutputs }, { shieldedSecretKeys, dustSecretKey }, { ttl, payFees = false }) => releasingOnFailure(async (reserve) => {
|
|
169
|
+
const { shielded: shieldedInputs, unshielded: unshieldedInputs } = desiredInputs;
|
|
170
|
+
const shieldedOutputs = desiredOutputs.flatMap((output) => output.type === "shielded" ? output.outputs : []);
|
|
171
|
+
const unshieldedOutputs = desiredOutputs.flatMap((output) => output.type === "unshielded" ? output.outputs : []);
|
|
172
|
+
const hasShieldedPart = !!shieldedInputs && Object.keys(shieldedInputs).length > 0 || shieldedOutputs.length > 0;
|
|
173
|
+
const hasUnshieldedPart = !!unshieldedInputs && Object.keys(unshieldedInputs).length > 0 || unshieldedOutputs.length > 0;
|
|
174
|
+
if (!hasShieldedPart && !hasUnshieldedPart) throw new Error("At least one shielded or unshielded swap is required.");
|
|
175
|
+
const swap = merge$2(hasShieldedPart && shieldedInputs !== void 0 ? reserve(await facade.shielded.initSwap(shieldedSecretKeys, shieldedInputs, shieldedOutputs), facade.shielded) : void 0, hasUnshieldedPart && unshieldedInputs !== void 0 ? reserve(await facade.unshielded.initSwap(unshieldedInputs, unshieldedOutputs, ttl), facade.unshielded) : void 0);
|
|
176
|
+
if (!swap) throw new Error("Unexpected transaction state.");
|
|
177
|
+
return {
|
|
178
|
+
type: "UNPROVEN_TRANSACTION",
|
|
179
|
+
transaction: merge$2(swap, payFees ? await facade.dust.balanceTransactions(dustSecretKey, [swap], ttl) : void 0) ?? swap
|
|
180
|
+
};
|
|
181
|
+
})
|
|
182
|
+
});
|
|
183
|
+
//#endregion
|
|
184
|
+
//#region ../../packages/lib/vendor/src/midnight-submission-service.ts
|
|
185
|
+
const observers = /* @__PURE__ */ new WeakMap();
|
|
186
|
+
const awaitDisconnection = (client) => require_const.async((resume) => {
|
|
187
|
+
if (!client.api.isConnected) {
|
|
188
|
+
resume(require_const._void);
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
const disconnected = () => {
|
|
192
|
+
resume(require_const._void);
|
|
193
|
+
};
|
|
194
|
+
client.api.once("disconnected", disconnected);
|
|
195
|
+
return require_const.sync(() => client.api.off("disconnected", disconnected));
|
|
196
|
+
});
|
|
197
|
+
/** Preserve facade submission/rollback semantics while observing its single stream. */
|
|
198
|
+
const createProgressSubmissionService = ({ relayURL }) => {
|
|
199
|
+
const scope = require_const.runSync(require_const.make$3());
|
|
200
|
+
const submissions = require_const.runSync(require_const.makeSemaphore(1));
|
|
201
|
+
const connection = require_watch.PolkadotNodeClient.make({ nodeURL: relayURL }).pipe(require_const.provideService(require_const.Scope, scope), require_const.tap(awaitDisconnection), require_const.cached, require_const.runSync);
|
|
202
|
+
const submit = async (tx, waitFor = "InBlock") => {
|
|
203
|
+
const serialized = require_const.from(tx);
|
|
204
|
+
return connection.pipe(require_const.flatMap((client) => client.sendMidnightTransaction(serialized).pipe(require_watch.tap((event) => require_const.sync(() => observers.get(tx)?.(event._tag))), require_watch.find((event) => event._tag === waitFor), require_watch.runHead, require_const.flatMap(require_const.match$3({
|
|
205
|
+
onSome: require_const.succeed,
|
|
206
|
+
onNone: () => require_const.fail$1(new require_watch.TransactionProgressError({
|
|
207
|
+
message: "Transaction did not reach desired stage",
|
|
208
|
+
txData: serialized,
|
|
209
|
+
desiredStage: waitFor
|
|
210
|
+
}))
|
|
211
|
+
})), require_const.ensuring(awaitDisconnection(client)))), submissions.withPermits(1), require_const.mapError$1((cause) => new require_watch.SubmissionError({
|
|
212
|
+
message: "Transaction submission error",
|
|
213
|
+
cause
|
|
214
|
+
})), require_const.runPromise);
|
|
215
|
+
};
|
|
216
|
+
return {
|
|
217
|
+
submitTransaction: submit,
|
|
218
|
+
close: async () => require_const.close(scope, require_const.void_).pipe(require_const.ignoreLogged, require_const.runPromise)
|
|
219
|
+
};
|
|
220
|
+
};
|
|
221
|
+
//#endregion
|
|
222
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-dust-wallet/dist/v1/CoreWallet.js
|
|
223
|
+
const PublicKey = { fromSecretKey: (secretKey) => {
|
|
224
|
+
return { publicKey: secretKey.publicKey };
|
|
225
|
+
} };
|
|
226
|
+
const CoreWallet$1 = {
|
|
227
|
+
init(localState, secretKey, networkId) {
|
|
228
|
+
return CoreWallet$1.empty(localState, PublicKey.fromSecretKey(secretKey), networkId);
|
|
229
|
+
},
|
|
230
|
+
initEmpty(dustParameters, secretKey, networkId) {
|
|
231
|
+
return CoreWallet$1.empty(new _midnight_ntwrk_ledger_v8.DustLocalState(dustParameters), PublicKey.fromSecretKey(secretKey), networkId);
|
|
232
|
+
},
|
|
233
|
+
empty(localState, publicKey, networkId) {
|
|
234
|
+
return {
|
|
235
|
+
state: localState,
|
|
236
|
+
publicKey,
|
|
237
|
+
networkId,
|
|
238
|
+
pendingDust: [],
|
|
239
|
+
progress: require_const.createSyncProgress(),
|
|
240
|
+
protocolVersion: require_const.MinSupportedVersion
|
|
241
|
+
};
|
|
242
|
+
},
|
|
243
|
+
restore(localState, publicKey, pendingTokens, syncProgress, protocolVersion, networkId) {
|
|
244
|
+
return {
|
|
245
|
+
state: localState,
|
|
246
|
+
publicKey,
|
|
247
|
+
networkId,
|
|
248
|
+
pendingDust: pendingTokens,
|
|
249
|
+
progress: require_const.createSyncProgress(syncProgress),
|
|
250
|
+
protocolVersion: require_const.ProtocolVersion(protocolVersion)
|
|
251
|
+
};
|
|
252
|
+
},
|
|
253
|
+
applyEventsWithChanges(wallet, secretKey, events, currentTime) {
|
|
254
|
+
const stateWithChanges = wallet.state.replayEventsWithChanges(secretKey, events);
|
|
255
|
+
const updatedState = stateWithChanges.state.processTtls(currentTime);
|
|
256
|
+
const availableNonces = updatedState.utxos.map((utxo) => utxo.nonce);
|
|
257
|
+
return [{
|
|
258
|
+
...wallet,
|
|
259
|
+
state: updatedState,
|
|
260
|
+
pendingDust: wallet.pendingDust.filter((t) => availableNonces.includes(t.nonce))
|
|
261
|
+
}, stateWithChanges.changes];
|
|
262
|
+
},
|
|
263
|
+
applyFailed(wallet, tx) {
|
|
264
|
+
const pendingSpendsMap = CoreWallet$1.pendingDustToMap(wallet.pendingDust);
|
|
265
|
+
const [updatedState, removedNullifiers] = require_const.pipe(require_const.pipe([...tx.intents?.values() ?? []], require_const.flatMap$3((intent) => {
|
|
266
|
+
const spendTime = intent.dustActions?.ctime;
|
|
267
|
+
return (intent.dustActions?.spends ?? []).map((spend) => ({
|
|
268
|
+
spend,
|
|
269
|
+
spendTime
|
|
270
|
+
}));
|
|
271
|
+
}), require_const.filterMap$1(({ spend, spendTime }) => require_const.pipe(require_const.fromNullable(pendingSpendsMap.get(spend.oldNullifier)), require_const.map$8(() => ({
|
|
272
|
+
spend,
|
|
273
|
+
spendTime
|
|
274
|
+
}))))), require_const.reduce$3([wallet.state, []], ([state, removed], { spend, spendTime }) => [state.processTtls(require_watch.addSeconds(spendTime, wallet.state.params.dustGracePeriodSeconds)), require_const.append$1(removed, spend.oldNullifier)]));
|
|
275
|
+
return {
|
|
276
|
+
...wallet,
|
|
277
|
+
state: updatedState,
|
|
278
|
+
pendingDust: wallet.pendingDust.filter((coin) => !removedNullifiers.includes(coin.nullifier))
|
|
279
|
+
};
|
|
280
|
+
},
|
|
281
|
+
revertTransaction(wallet, tx) {
|
|
282
|
+
return CoreWallet$1.applyFailed(wallet, tx);
|
|
283
|
+
},
|
|
284
|
+
updateProgress(wallet, { appliedIndex, highestRelevantWalletIndex, highestIndex, highestRelevantIndex, isConnected }) {
|
|
285
|
+
const updatedProgress = require_const.createSyncProgress({
|
|
286
|
+
appliedIndex: appliedIndex ?? wallet.progress.appliedIndex,
|
|
287
|
+
highestRelevantWalletIndex: highestRelevantWalletIndex ?? wallet.progress.highestRelevantWalletIndex,
|
|
288
|
+
highestIndex: highestIndex ?? wallet.progress.highestIndex,
|
|
289
|
+
highestRelevantIndex: highestRelevantIndex ?? wallet.progress.highestRelevantIndex,
|
|
290
|
+
isConnected: isConnected ?? wallet.progress.isConnected
|
|
291
|
+
});
|
|
292
|
+
return {
|
|
293
|
+
...wallet,
|
|
294
|
+
progress: updatedProgress
|
|
295
|
+
};
|
|
296
|
+
},
|
|
297
|
+
spendCoins(wallet, secretKey, coins, currentTime) {
|
|
298
|
+
const [output, newState, newPending] = require_const.pipe(coins, require_const.reduce$3([
|
|
299
|
+
[],
|
|
300
|
+
wallet.state,
|
|
301
|
+
wallet.pendingDust
|
|
302
|
+
], ([spends, localState, pending], { token: coinToSpend, value: takeFee }) => {
|
|
303
|
+
const [newState, dustSpend] = localState.spend(secretKey, coinToSpend, takeFee, currentTime);
|
|
304
|
+
const newPending = [...pending, {
|
|
305
|
+
...coinToSpend,
|
|
306
|
+
nullifier: dustSpend.oldNullifier
|
|
307
|
+
}];
|
|
308
|
+
return [
|
|
309
|
+
require_const.append$1(spends, dustSpend),
|
|
310
|
+
newState,
|
|
311
|
+
newPending
|
|
312
|
+
];
|
|
313
|
+
}));
|
|
314
|
+
return [output, {
|
|
315
|
+
...wallet,
|
|
316
|
+
state: newState,
|
|
317
|
+
pendingDust: newPending
|
|
318
|
+
}];
|
|
319
|
+
},
|
|
320
|
+
pendingDustToMap(coins) {
|
|
321
|
+
return new Map(coins.map(({ nullifier, ...coins }) => [nullifier, coins]));
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
//#endregion
|
|
325
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-dust-wallet/dist/v1/WalletError.js
|
|
326
|
+
var OtherWalletError$1 = class extends require_const.TaggedError("Wallet.Other") {};
|
|
327
|
+
var SyncWalletError$1 = class extends require_const.TaggedError("Wallet.Sync") {};
|
|
328
|
+
var TransactingError = class extends require_const.TaggedError("Wallet.Transacting") {};
|
|
329
|
+
var InsufficientFundsError$1 = class extends require_const.TaggedError("Wallet.InsufficientFunds") {};
|
|
330
|
+
var TransactionHistoryError$1 = class extends require_const.TaggedError("Wallet.TransactionHistory") {};
|
|
331
|
+
//#endregion
|
|
332
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-dust-wallet/dist/v1/RunningV1Variant.js
|
|
333
|
+
const progress$1 = (state) => {
|
|
334
|
+
const appliedIndex = state.progress?.appliedIndex ?? 0n;
|
|
335
|
+
const highestRelevantWalletIndex = state.progress?.highestRelevantWalletIndex ?? 0n;
|
|
336
|
+
const sourceGap = (state.progress?.highestIndex ?? 0n) - (state.progress?.highestRelevantIndex ?? 0n);
|
|
337
|
+
const applyGap = highestRelevantWalletIndex - appliedIndex;
|
|
338
|
+
return [require_watch.ProgressUpdate({
|
|
339
|
+
sourceGap,
|
|
340
|
+
applyGap
|
|
341
|
+
})];
|
|
342
|
+
};
|
|
343
|
+
const protocolVersionChange$1 = (previous, current) => {
|
|
344
|
+
return previous.protocolVersion != current.protocolVersion ? [require_watch.VersionChange({ change: require_watch.Version({ version: require_const.ProtocolVersion(current.protocolVersion) }) })] : [];
|
|
345
|
+
};
|
|
346
|
+
const V1Tag$1 = Symbol("V1");
|
|
347
|
+
var RunningV1Variant$1 = class {
|
|
348
|
+
__polyTag__ = V1Tag$1;
|
|
349
|
+
#scope;
|
|
350
|
+
#context;
|
|
351
|
+
#v1Context;
|
|
352
|
+
state;
|
|
353
|
+
constructor(scope, context, v1Context) {
|
|
354
|
+
this.#scope = scope;
|
|
355
|
+
this.#context = context;
|
|
356
|
+
this.#v1Context = v1Context;
|
|
357
|
+
this.state = require_watch.fromEffect(context.stateRef.get).pipe(require_watch.flatMap((initialState) => context.stateRef.changes.pipe(require_watch.mapAccum(initialState, (previous, current) => {
|
|
358
|
+
return [current, [previous, current]];
|
|
359
|
+
}))), require_watch.mapConcat(([previous, current]) => {
|
|
360
|
+
return [
|
|
361
|
+
require_watch.State({ state: current }),
|
|
362
|
+
...progress$1(current),
|
|
363
|
+
...protocolVersionChange$1(previous, current)
|
|
364
|
+
];
|
|
365
|
+
}));
|
|
366
|
+
}
|
|
367
|
+
startSyncInBackground(startAux) {
|
|
368
|
+
return this.startSync(startAux).pipe(require_watch.runScoped(require_watch.drain), require_const.forkScoped, require_const.provideService(require_const.Scope, this.#scope));
|
|
369
|
+
}
|
|
370
|
+
startSync(startAux) {
|
|
371
|
+
return require_const.pipe(require_watch.get(this.#context.stateRef), require_watch.fromEffect, require_watch.flatMap((state) => this.#v1Context.syncService.updates(state, startAux)), require_watch.mapEffect((update) => require_watch.modifyEffect(this.#context.stateRef, (state) => require_const.try_({
|
|
372
|
+
try: () => {
|
|
373
|
+
const [newState, changesResult] = this.#v1Context.syncCapability.applyUpdate(state, update);
|
|
374
|
+
return [changesResult, newState];
|
|
375
|
+
},
|
|
376
|
+
catch: (err) => new OtherWalletError$1({
|
|
377
|
+
message: "Error while applying sync update",
|
|
378
|
+
cause: err
|
|
379
|
+
})
|
|
380
|
+
})).pipe(require_const.flatMap(({ changes, protocolVersion }) => changes.length === 0 ? require_const._void : require_const.pipe(require_const.forEach(changes, (change) => require_const.pipe(this.#v1Context.transactionHistoryService.getTransactionDetails(change.source), require_const.flatMap((metadata) => this.#v1Context.transactionHistoryService.put(change, metadata, protocolVersion)), require_const.catchAllCause((cause) => require_watch.error("Error processing tx history metadata", cause))), {
|
|
381
|
+
discard: true,
|
|
382
|
+
concurrency: "unbounded"
|
|
383
|
+
}), require_const.forkScoped)), require_const.provideService(require_const.Scope, this.#scope))), require_watch.tapError((error$2) => require_watch.error(error$2)), require_watch.retry(require_const.pipe(require_watch.exponential(require_const.seconds(1), 2), require_watch.map$1((delay) => {
|
|
384
|
+
const maxDelay = require_const.minutes(2);
|
|
385
|
+
const jitter = require_const.millis(Math.floor(Math.random() * 1e3));
|
|
386
|
+
const delayWithJitter = require_const.toMillis(delay) + require_const.toMillis(jitter);
|
|
387
|
+
return require_const.millis(Math.min(delayWithJitter, require_const.toMillis(maxDelay)));
|
|
388
|
+
}))));
|
|
389
|
+
}
|
|
390
|
+
createDustGenerationTransaction(currentTime, ttl, nightUtxos, nightVerifyingKey, dustReceiverAddress) {
|
|
391
|
+
if (nightUtxos.some((utxo) => utxo.type !== (0, _midnight_ntwrk_ledger_v8.nativeToken)().raw)) return require_const.fail$1(new OtherWalletError$1({ message: "Token of a non-Night type received" }));
|
|
392
|
+
return require_const.gen(this, function* () {
|
|
393
|
+
const currentState = yield* require_watch.get(this.#context.stateRef);
|
|
394
|
+
const blockData = yield* this.#v1Context.syncService.blockData();
|
|
395
|
+
const resolvedTime = currentTime ?? blockData.timestamp;
|
|
396
|
+
const utxosWithDustValue = this.#v1Context.coinsAndBalancesCapability.estimateDustGeneration(currentState, nightUtxos, resolvedTime);
|
|
397
|
+
return yield* this.#v1Context.transactingCapability.createDustGenerationTransaction(resolvedTime, ttl, utxosWithDustValue, nightVerifyingKey, dustReceiverAddress).pipe(require_watch.toEffect);
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
splitNightUtxosForDustRegistration(currentTime, nightUtxos, isRegistration) {
|
|
401
|
+
if (nightUtxos.some((utxo) => utxo.type !== (0, _midnight_ntwrk_ledger_v8.nativeToken)().raw)) return require_const.fail$1(new OtherWalletError$1({ message: "Token of a non-Night type received" }));
|
|
402
|
+
return require_const.gen(this, function* () {
|
|
403
|
+
const currentState = yield* require_watch.get(this.#context.stateRef);
|
|
404
|
+
const utxosWithDustValue = this.#v1Context.coinsAndBalancesCapability.estimateDustGeneration(currentState, nightUtxos, currentTime);
|
|
405
|
+
return this.#v1Context.transactingCapability.splitNightUtxosForDustRegistration(utxosWithDustValue, isRegistration);
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
attachDustRegistration(transaction, currentTime, nightVerifyingKey, dustReceiverAddress, feePayment) {
|
|
409
|
+
return this.#v1Context.transactingCapability.attachDustRegistration(transaction, currentTime, nightVerifyingKey, dustReceiverAddress, feePayment).pipe(require_watch.toEffect);
|
|
410
|
+
}
|
|
411
|
+
addDustGenerationSignature(transaction, signature) {
|
|
412
|
+
return this.#v1Context.transactingCapability.addDustGenerationSignature(transaction, signature).pipe(require_watch.toEffect);
|
|
413
|
+
}
|
|
414
|
+
addDustRegistrationSignature(transaction, signature) {
|
|
415
|
+
return this.#v1Context.transactingCapability.addDustRegistrationSignature(transaction, signature).pipe(require_watch.toEffect);
|
|
416
|
+
}
|
|
417
|
+
calculateFee(transactions) {
|
|
418
|
+
return require_const.pipe(this.#v1Context.syncService.blockData(), require_const.map((blockData) => require_const.pipe(transactions, require_const.map$6((transaction) => this.#v1Context.transactingCapability.calculateFee(transaction, blockData.ledgerParameters)), require_watch.sumBigInt)));
|
|
419
|
+
}
|
|
420
|
+
estimateFee(secretKey, transactions, ttl, currentTime) {
|
|
421
|
+
return require_const.pipe(require_const.all([require_watch.get(this.#context.stateRef), this.#v1Context.syncService.blockData()]), require_const.flatMap(([state, blockData]) => require_const.pipe(this.#v1Context.transactingCapability.estimateFee(secretKey, state, transactions, ttl, currentTime ?? blockData.timestamp, blockData.ledgerParameters), require_watch.toEffect)));
|
|
422
|
+
}
|
|
423
|
+
balanceTransactions(secretKey, transactions, ttl, currentTime) {
|
|
424
|
+
return require_watch.modifyEffect(this.#context.stateRef, (state) => {
|
|
425
|
+
return require_const.pipe(this.#v1Context.syncService.blockData(), require_const.flatMap((blockData) => this.#v1Context.transactingCapability.balanceTransactions(secretKey, state, transactions, ttl, currentTime ?? blockData.timestamp, blockData.ledgerParameters)));
|
|
426
|
+
});
|
|
427
|
+
}
|
|
428
|
+
revertTransaction(transaction) {
|
|
429
|
+
return require_watch.updateEffect(this.#context.stateRef, (state) => {
|
|
430
|
+
return require_const.pipe(this.#v1Context.transactingCapability.revertTransaction(state, transaction), require_watch.toEffect);
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
};
|
|
434
|
+
//#endregion
|
|
435
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-dust-wallet/dist/v1/Serialization.js
|
|
436
|
+
require__polyfill_buffer_patch.init__polyfill_buffer_patch();
|
|
437
|
+
const StateSchema$1 = require_const.declare((input) => input instanceof _midnight_ntwrk_ledger_v8.DustLocalState).annotations({ identifier: "ledger.DustLocalState" });
|
|
438
|
+
const Uint8ArraySchema$2 = require_const.declare((input) => input instanceof Uint8Array).annotations({ identifier: "Uint8Array" });
|
|
439
|
+
const StateFromUInt8Array$1 = require_const.asSchema(require_const.transformOrFail(Uint8ArraySchema$2, StateSchema$1, {
|
|
440
|
+
encode: (state) => {
|
|
441
|
+
return require_const.try_({
|
|
442
|
+
try: () => {
|
|
443
|
+
return state.serialize();
|
|
444
|
+
},
|
|
445
|
+
catch: (err) => {
|
|
446
|
+
return new require_const.Unexpected(err, "Could not serialize local state");
|
|
447
|
+
}
|
|
448
|
+
});
|
|
449
|
+
},
|
|
450
|
+
decode: (bytes) => require_const.try_({
|
|
451
|
+
try: () => _midnight_ntwrk_ledger_v8.DustLocalState.deserialize(bytes),
|
|
452
|
+
catch: (err) => {
|
|
453
|
+
return new require_const.Unexpected(err, "Could not deserialize local state");
|
|
454
|
+
}
|
|
455
|
+
})
|
|
456
|
+
}));
|
|
457
|
+
const HexedState$1 = require_const.pipe(require_const.Uint8ArrayFromHex, require_const.compose(StateFromUInt8Array$1));
|
|
458
|
+
const SnapshotSchema = require_const.Struct({
|
|
459
|
+
publicKey: require_const.Struct({ publicKey: require_const.BigInt$ }),
|
|
460
|
+
state: HexedState$1,
|
|
461
|
+
protocolVersion: require_const.BigInt$,
|
|
462
|
+
networkId: require_const.String$,
|
|
463
|
+
offset: require_const.optional(require_const.BigInt$)
|
|
464
|
+
});
|
|
465
|
+
const makeDefaultV1SerializationCapability$1 = () => {
|
|
466
|
+
return {
|
|
467
|
+
serialize: (wallet) => {
|
|
468
|
+
const buildSnapshot = (w) => ({
|
|
469
|
+
publicKey: w.publicKey,
|
|
470
|
+
state: w.state,
|
|
471
|
+
protocolVersion: w.protocolVersion,
|
|
472
|
+
networkId: w.networkId,
|
|
473
|
+
offset: w.progress?.appliedIndex
|
|
474
|
+
});
|
|
475
|
+
return require_const.pipe(wallet, buildSnapshot, require_const.encodeSync(SnapshotSchema), JSON.stringify);
|
|
476
|
+
},
|
|
477
|
+
deserialize: (aux, serialized) => {
|
|
478
|
+
return require_const.pipe(serialized, require_const.decodeUnknownEither(require_const.parseJson(SnapshotSchema)), require_const.mapLeft((err) => new OtherWalletError$1({
|
|
479
|
+
message: "Error while deserializing snapshot",
|
|
480
|
+
cause: err
|
|
481
|
+
})), require_const.flatMap$4((snapshot) => require_const.try_$1({
|
|
482
|
+
try: () => CoreWallet$1.restore(snapshot.state, snapshot.publicKey, [], {
|
|
483
|
+
appliedIndex: snapshot.offset ?? 0n,
|
|
484
|
+
highestRelevantWalletIndex: 0n,
|
|
485
|
+
highestIndex: 0n,
|
|
486
|
+
highestRelevantIndex: 0n
|
|
487
|
+
}, snapshot.protocolVersion, snapshot.networkId),
|
|
488
|
+
catch: (err) => new OtherWalletError$1({
|
|
489
|
+
message: "Error while restoring core wallet",
|
|
490
|
+
cause: err
|
|
491
|
+
})
|
|
492
|
+
})));
|
|
493
|
+
}
|
|
494
|
+
};
|
|
495
|
+
};
|
|
496
|
+
//#endregion
|
|
497
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-dust-wallet/dist/v1/Sync.js
|
|
498
|
+
const LedgerEventSchema$1 = require_const.declare((input) => input instanceof _midnight_ntwrk_ledger_v8.Event).annotations({ identifier: "ledger.Event" });
|
|
499
|
+
const LedgerEventFromUInt8Array = require_const.asSchema(require_const.transformOrFail(Uint8ArraySchema$2, LedgerEventSchema$1, {
|
|
500
|
+
encode: (e) => require_const.try_({
|
|
501
|
+
try: () => e.serialize(),
|
|
502
|
+
catch: (err) => new require_const.Unexpected(err, "Could not serialize Ledger Event")
|
|
503
|
+
}),
|
|
504
|
+
decode: (bytes) => require_const.try_({
|
|
505
|
+
try: () => _midnight_ntwrk_ledger_v8.Event.deserialize(bytes),
|
|
506
|
+
catch: (err) => new require_const.Unexpected(err, "Could not deserialize Ledger Event")
|
|
507
|
+
})
|
|
508
|
+
}));
|
|
509
|
+
const HexedEvent = require_const.pipe(require_const.Uint8ArrayFromHex, require_const.compose(LedgerEventFromUInt8Array));
|
|
510
|
+
const SyncEventsUpdateSchema = require_const.Struct({
|
|
511
|
+
id: require_const.Number$,
|
|
512
|
+
raw: HexedEvent,
|
|
513
|
+
maxId: require_const.Number$
|
|
514
|
+
});
|
|
515
|
+
const WalletSyncUpdate$1 = { create: (updates, secretKey, timestamp) => {
|
|
516
|
+
return {
|
|
517
|
+
updates,
|
|
518
|
+
secretKey,
|
|
519
|
+
timestamp
|
|
520
|
+
};
|
|
521
|
+
} };
|
|
522
|
+
const makeDefaultSyncService = (config) => {
|
|
523
|
+
const indexerSyncService = makeIndexerSyncService(config);
|
|
524
|
+
return {
|
|
525
|
+
updates: (state, secretKey) => {
|
|
526
|
+
const batchSize = config.batchUpdates?.size ?? 10;
|
|
527
|
+
const batchTimeout = require_const.millis(config.batchUpdates?.timeout ?? 1);
|
|
528
|
+
const batchSpacing = config.batchUpdates?.spacing ?? 4;
|
|
529
|
+
return require_const.pipe(indexerSyncService.subscribeWallet(state), require_watch.groupedWithin(batchSize, batchTimeout), require_watch.map(require_const.toArray), require_watch.map((data) => WalletSyncUpdate$1.create(data, secretKey, /* @__PURE__ */ new Date())), batchSpacing > 0 ? require_watch.schedule(require_watch.spaced(require_const.millis(batchSpacing))) : (eventsStream) => eventsStream, require_watch.provideSomeLayer(indexerSyncService.connectionLayer()));
|
|
530
|
+
},
|
|
531
|
+
blockData: () => {
|
|
532
|
+
return require_const.gen(function* () {
|
|
533
|
+
return (yield* (yield* require_watch.BlockHash)({ offset: null })).block;
|
|
534
|
+
}).pipe(require_const.provide(indexerSyncService.queryClient()), require_const.scoped$1, require_const.catchAll((err) => require_const.fail$1(new OtherWalletError$1({
|
|
535
|
+
message: `Encountered unexpected error: ${err.message}`,
|
|
536
|
+
cause: err
|
|
537
|
+
}))), require_const.flatMap((blockData) => {
|
|
538
|
+
if (!blockData) throw new OtherWalletError$1({ message: "Unable to fetch block data" });
|
|
539
|
+
return require_watch.ledgerTry(() => ({
|
|
540
|
+
hash: blockData.hash,
|
|
541
|
+
height: blockData.height,
|
|
542
|
+
ledgerParameters: _midnight_ntwrk_ledger_v8.LedgerParameters.deserialize(require__polyfill_buffer_patch.import_buffer.Buffer.from(blockData.ledgerParameters, "hex")),
|
|
543
|
+
timestamp: new Date(blockData.timestamp)
|
|
544
|
+
}));
|
|
545
|
+
}));
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
};
|
|
549
|
+
const makeIndexerSyncService = (config) => {
|
|
550
|
+
return {
|
|
551
|
+
queryClient() {
|
|
552
|
+
return require_const.pipe(require_watch.layer$1({ url: config.indexerClientConnection.indexerHttpUrl }), require_const.mapError((error) => new OtherWalletError$1(error)));
|
|
553
|
+
},
|
|
554
|
+
connectionLayer() {
|
|
555
|
+
const { indexerClientConnection } = config;
|
|
556
|
+
return require_watch.createWebSocketUrl(indexerClientConnection.indexerHttpUrl, indexerClientConnection.indexerWsUrl).pipe(require_const.flatMap$4((url) => require_watch.make(url)), require_const.match$4({
|
|
557
|
+
onLeft: (error) => require_const.fail(error),
|
|
558
|
+
onRight: (url) => require_watch.layer({
|
|
559
|
+
url,
|
|
560
|
+
keepAlive: indexerClientConnection.keepAlive
|
|
561
|
+
})
|
|
562
|
+
}), require_const.mapError((e) => new SyncWalletError$1({
|
|
563
|
+
message: "Failed to to obtain correct indexer URLs",
|
|
564
|
+
cause: e
|
|
565
|
+
})));
|
|
566
|
+
},
|
|
567
|
+
subscribeWallet(state) {
|
|
568
|
+
const { appliedIndex } = state.progress;
|
|
569
|
+
const bufferSize = config.indexerClientConnection.bufferSize ?? 1e4;
|
|
570
|
+
const resumeThreshold = config.indexerClientConnection.resumeThreshold ?? 100;
|
|
571
|
+
const resumeFrom = appliedIndex - 1n;
|
|
572
|
+
return require_const.pipe(require_watch.DustLedgerEvents.runWithBackpressure({
|
|
573
|
+
bufferSize,
|
|
574
|
+
resumeThreshold,
|
|
575
|
+
from: resumeFrom,
|
|
576
|
+
variables: (cursor) => ({ id: cursor < 0n ? null : Number(cursor) }),
|
|
577
|
+
key: (r) => BigInt(r.dustLedgerEvents.id)
|
|
578
|
+
}), require_watch.mapEffect((subscription) => require_const.pipe(require_const.decodeUnknownEither(SyncEventsUpdateSchema)(subscription.dustLedgerEvents), require_const.mapLeft((err) => new SyncWalletError$1(err)), require_watch.toEffect)), require_watch.mapError((error) => new SyncWalletError$1(error)));
|
|
579
|
+
}
|
|
580
|
+
};
|
|
581
|
+
};
|
|
582
|
+
const makeDefaultSyncCapability = () => {
|
|
583
|
+
return { applyUpdate(state, wrappedUpdate) {
|
|
584
|
+
const { updates, secretKey } = wrappedUpdate;
|
|
585
|
+
if (updates.length === 0) return [state, {
|
|
586
|
+
changes: [],
|
|
587
|
+
protocolVersion: Number(state.protocolVersion)
|
|
588
|
+
}];
|
|
589
|
+
const appliedIndex = state.progress.appliedIndex;
|
|
590
|
+
const freshUpdates = updates.filter((u) => BigInt(u.id) > appliedIndex);
|
|
591
|
+
const highestRelevantWalletIndex = BigInt(updates.at(-1).maxId);
|
|
592
|
+
const [newState, changes] = freshUpdates.length === 0 ? [state, []] : CoreWallet$1.applyEventsWithChanges(state, secretKey, freshUpdates.map((u) => u.raw), wrappedUpdate.timestamp);
|
|
593
|
+
const updatedState = CoreWallet$1.updateProgress(newState, {
|
|
594
|
+
appliedIndex: freshUpdates.length === 0 ? appliedIndex : BigInt(freshUpdates.at(-1).id),
|
|
595
|
+
highestRelevantWalletIndex,
|
|
596
|
+
isConnected: true
|
|
597
|
+
});
|
|
598
|
+
return [updatedState, {
|
|
599
|
+
changes,
|
|
600
|
+
protocolVersion: Number(updatedState.protocolVersion)
|
|
601
|
+
}];
|
|
602
|
+
} };
|
|
603
|
+
};
|
|
604
|
+
//#endregion
|
|
605
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-dust-wallet/dist/v1/TransactionHistory.js
|
|
606
|
+
const DustUtxoInfoSchema = require_const.Struct({
|
|
607
|
+
initialValue: require_const.BigInt$,
|
|
608
|
+
nonce: require_const.BigInt$,
|
|
609
|
+
seq: require_const.Number$,
|
|
610
|
+
backingNight: require_const.String$,
|
|
611
|
+
mtIndex: require_const.BigInt$
|
|
612
|
+
});
|
|
613
|
+
const DustSectionSchema = require_const.Struct({
|
|
614
|
+
receivedUtxos: require_const.Array$(DustUtxoInfoSchema),
|
|
615
|
+
spentUtxos: require_const.Array$(DustUtxoInfoSchema)
|
|
616
|
+
});
|
|
617
|
+
require_const.Struct({
|
|
618
|
+
hash: require_const.TransactionHashSchema,
|
|
619
|
+
protocolVersion: require_const.Number$,
|
|
620
|
+
status: require_const.TransactionHistoryStatusSchema,
|
|
621
|
+
dust: DustSectionSchema
|
|
622
|
+
});
|
|
623
|
+
const utxoEquals = require_const.equivalence(DustUtxoInfoSchema);
|
|
624
|
+
const mergeDustSections = (existing, incoming) => ({
|
|
625
|
+
receivedUtxos: require_const.unionWith$1(existing.receivedUtxos, incoming.receivedUtxos, utxoEquals),
|
|
626
|
+
spentUtxos: require_const.unionWith$1(existing.spentUtxos, incoming.spentUtxos, utxoEquals)
|
|
627
|
+
});
|
|
628
|
+
const convertQualifiedDustOutput = (utxo) => ({
|
|
629
|
+
initialValue: utxo.initialValue,
|
|
630
|
+
nonce: utxo.nonce,
|
|
631
|
+
seq: utxo.seq,
|
|
632
|
+
backingNight: utxo.backingNight,
|
|
633
|
+
mtIndex: utxo.mtIndex
|
|
634
|
+
});
|
|
635
|
+
const convertUpdateToStorageEntry$1 = (changes, metadata, protocolVersion) => ({
|
|
636
|
+
hash: changes.source,
|
|
637
|
+
protocolVersion,
|
|
638
|
+
status: metadata.status,
|
|
639
|
+
dust: {
|
|
640
|
+
receivedUtxos: changes.receivedUtxos.map(convertQualifiedDustOutput),
|
|
641
|
+
spentUtxos: changes.spentUtxos.map(convertQualifiedDustOutput)
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
const upsertDustEntry = (txHistoryStorage, entry) => require_const.tryPromise({
|
|
645
|
+
try: () => txHistoryStorage.upsert(entry),
|
|
646
|
+
catch: (e) => new TransactionHistoryError$1({
|
|
647
|
+
message: `Failed to upsert history entry for ${entry.hash}`,
|
|
648
|
+
cause: e
|
|
649
|
+
})
|
|
650
|
+
});
|
|
651
|
+
const makeDefaultTransactionHistoryService$1 = (config, _getContext) => {
|
|
652
|
+
const txHistoryStorage = config.txHistoryStorage;
|
|
653
|
+
const queryClientLayer = require_watch.layer$1({ url: config.indexerClientConnection.indexerHttpUrl });
|
|
654
|
+
return {
|
|
655
|
+
put: (changes, metadata, protocolVersion) => {
|
|
656
|
+
return upsertDustEntry(txHistoryStorage, convertUpdateToStorageEntry$1(changes, metadata, protocolVersion));
|
|
657
|
+
},
|
|
658
|
+
getTransactionDetails: (hash) => require_const.gen(function* () {
|
|
659
|
+
const tx = (yield* (yield* require_watch.TransactionHistoryDetail)({ transactionHash: hash })).transactions[0];
|
|
660
|
+
const rawStatus = tx.__typename === "RegularTransaction" ? tx.transactionResult.status : void 0;
|
|
661
|
+
const status = rawStatus === "FAILURE" || rawStatus === "PARTIAL_SUCCESS" ? rawStatus : "SUCCESS";
|
|
662
|
+
return {
|
|
663
|
+
hash: tx.hash,
|
|
664
|
+
timestamp: tx.block.timestamp,
|
|
665
|
+
status
|
|
666
|
+
};
|
|
667
|
+
}).pipe(require_const.provide(queryClientLayer), require_const.scoped$1, require_const.retry(require_watch.exponential(require_const.seconds(1)).pipe(require_watch.compose(require_watch.recurs(3)))), require_const.mapError$1((cause) => new TransactionHistoryError$1({
|
|
668
|
+
message: `Failed to fetch transaction metadata for ${hash}`,
|
|
669
|
+
cause
|
|
670
|
+
})))
|
|
671
|
+
};
|
|
672
|
+
};
|
|
673
|
+
//#endregion
|
|
674
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-dust-wallet/dist/v1/Keys.js
|
|
675
|
+
const makeDefaultKeysCapability$1 = () => {
|
|
676
|
+
return {
|
|
677
|
+
getPublicKey: (state) => {
|
|
678
|
+
return state.publicKey.publicKey;
|
|
679
|
+
},
|
|
680
|
+
getAddress: (state) => {
|
|
681
|
+
return new require_dist.DustAddress(state.publicKey.publicKey);
|
|
682
|
+
}
|
|
683
|
+
};
|
|
684
|
+
};
|
|
685
|
+
//#endregion
|
|
686
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-dust-wallet/dist/v1/CoinsAndBalances.js
|
|
687
|
+
const chooseCoin = (coins) => coins.filter((coin) => coin.value > 0n).toSorted((a, b) => Number(a.value - b.value)).at(0);
|
|
688
|
+
const FAKE_NONCE = "0".repeat(64);
|
|
689
|
+
const makeDefaultCoinsAndBalancesCapability$1 = (_config, getContext) => {
|
|
690
|
+
const getWalletBalance = (state, time) => {
|
|
691
|
+
return state.state.walletBalance(time);
|
|
692
|
+
};
|
|
693
|
+
const getGenerationInfo = (state, coin) => {
|
|
694
|
+
const info = state.state.generationInfo(coin);
|
|
695
|
+
return info && info.dtime ? {
|
|
696
|
+
...info,
|
|
697
|
+
dtime: /* @__PURE__ */ new Date(+info.dtime)
|
|
698
|
+
} : info;
|
|
699
|
+
};
|
|
700
|
+
const resolveTime = (state, time) => time ?? state.state.syncTime;
|
|
701
|
+
const toFullInfo = (state, coins, time) => coins.flatMap((coin) => {
|
|
702
|
+
const genInfo = getGenerationInfo(state, coin);
|
|
703
|
+
return genInfo ? [{
|
|
704
|
+
token: coin,
|
|
705
|
+
...getFullDustInfo(state.state.params, genInfo, coin, time)
|
|
706
|
+
}] : [];
|
|
707
|
+
});
|
|
708
|
+
const availableDustTokens = (state) => {
|
|
709
|
+
const pendingSpends = new Set([...state.pendingDust.values()].map((coin) => coin.nonce));
|
|
710
|
+
return require_const.pipe(state.state.utxos, require_const.filter$2((coin) => !pendingSpends.has(coin.nonce)));
|
|
711
|
+
};
|
|
712
|
+
const getAvailableCoins = (state, time) => toFullInfo(state, availableDustTokens(state), resolveTime(state, time));
|
|
713
|
+
const getPendingCoins = (state, time) => toFullInfo(state, state.pendingDust, resolveTime(state, time));
|
|
714
|
+
const getTotalCoins = (state, time) => {
|
|
715
|
+
const effectiveTime = resolveTime(state, time);
|
|
716
|
+
return [...getAvailableCoins(state, effectiveTime), ...getPendingCoins(state, effectiveTime)];
|
|
717
|
+
};
|
|
718
|
+
const getAvailableCoinsWithGeneratedDust = (state, currentTime) => getAvailableCoins(state, currentTime).map((info) => ({
|
|
719
|
+
token: info.token,
|
|
720
|
+
value: info.generatedNow
|
|
721
|
+
}));
|
|
722
|
+
const getFullDustInfo = (parameters, genInfo, coin, currentTime) => {
|
|
723
|
+
const generatedValue = _midnight_ntwrk_ledger_v8.updatedValue(coin.ctime, coin.initialValue, genInfo, currentTime, parameters);
|
|
724
|
+
return {
|
|
725
|
+
dtime: genInfo.dtime,
|
|
726
|
+
maxCap: genInfo.value * parameters.nightDustRatio,
|
|
727
|
+
maxCapReachedAt: require_watch.addSeconds(coin.ctime, parameters.timeToCapSeconds),
|
|
728
|
+
generatedNow: generatedValue,
|
|
729
|
+
rate: genInfo.value * parameters.generationDecayRate
|
|
730
|
+
};
|
|
731
|
+
};
|
|
732
|
+
const estimateDustGeneration = (state, nightUtxos, currentTime) => {
|
|
733
|
+
const dustPublicKey = getContext().keysCapability.getPublicKey(state);
|
|
734
|
+
return require_const.pipe(nightUtxos, require_const.map$6((utxo) => {
|
|
735
|
+
const genInfo = fakeGenerationInfo(utxo, dustPublicKey);
|
|
736
|
+
const fakeDustCoin = fakeDustToken(dustPublicKey, utxo);
|
|
737
|
+
return {
|
|
738
|
+
utxo,
|
|
739
|
+
dust: getFullDustInfo(state.state.params, genInfo, fakeDustCoin, currentTime)
|
|
740
|
+
};
|
|
741
|
+
}));
|
|
742
|
+
};
|
|
743
|
+
/** Create a fake generation info for a given Utxo. It allows to estimate the Dust generation from it */
|
|
744
|
+
const fakeGenerationInfo = (utxo, dustPublicKey) => {
|
|
745
|
+
return {
|
|
746
|
+
value: utxo.value,
|
|
747
|
+
owner: dustPublicKey,
|
|
748
|
+
nonce: FAKE_NONCE,
|
|
749
|
+
dtime: void 0
|
|
750
|
+
};
|
|
751
|
+
};
|
|
752
|
+
/** Create a fake dust coin for a given Utxo. It allows to estimate full details of the Dust generation from it */
|
|
753
|
+
const fakeDustToken = (dustPublicKey, utxo) => ({
|
|
754
|
+
initialValue: 0n,
|
|
755
|
+
owner: dustPublicKey,
|
|
756
|
+
nonce: 0n,
|
|
757
|
+
seq: 0,
|
|
758
|
+
ctime: utxo.ctime,
|
|
759
|
+
backingNight: "",
|
|
760
|
+
mtIndex: 0n
|
|
761
|
+
});
|
|
762
|
+
const splitNightUtxos = (utxos) => {
|
|
763
|
+
const [guaranteed, fallible] = require_const.pipe(utxos, require_const.sort(require_const.pipe(require_const.bigint, require_const.reverse, require_const.mapInput$1((coin) => coin.dust.generatedNow))), require_const.splitAt$1(1));
|
|
764
|
+
return {
|
|
765
|
+
guaranteed,
|
|
766
|
+
fallible
|
|
767
|
+
};
|
|
768
|
+
};
|
|
769
|
+
return {
|
|
770
|
+
getWalletBalance,
|
|
771
|
+
getAvailableCoins,
|
|
772
|
+
getPendingCoins,
|
|
773
|
+
getTotalCoins,
|
|
774
|
+
getAvailableCoinsWithGeneratedDust,
|
|
775
|
+
getGenerationInfo,
|
|
776
|
+
estimateDustGeneration,
|
|
777
|
+
splitNightUtxos
|
|
778
|
+
};
|
|
779
|
+
};
|
|
780
|
+
//#endregion
|
|
781
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-dust-wallet/dist/v1/Utils.js
|
|
782
|
+
const SignatureMarker = {
|
|
783
|
+
signature: "signature",
|
|
784
|
+
signatureErased: "signature-erased"
|
|
785
|
+
};
|
|
786
|
+
const ProofMarker = {
|
|
787
|
+
proof: "proof",
|
|
788
|
+
preProof: "pre-proof",
|
|
789
|
+
noProof: "no-proof"
|
|
790
|
+
};
|
|
791
|
+
const BindingMarker = {
|
|
792
|
+
binding: "binding",
|
|
793
|
+
preBinding: "pre-binding",
|
|
794
|
+
noBinding: "no-binding"
|
|
795
|
+
};
|
|
796
|
+
//#endregion
|
|
797
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-dust-wallet/dist/v1/Transacting.js
|
|
798
|
+
const makeDefaultTransactingCapability$1 = (config, getContext) => {
|
|
799
|
+
return new TransactingCapabilityImplementation$1(config.networkId, config.costParameters, () => getContext().coinSelection, () => getContext().coinsAndBalancesCapability, () => getContext().keysCapability);
|
|
800
|
+
};
|
|
801
|
+
/**
|
|
802
|
+
* Distributes the fee across multiple inputs, draining smaller inputs first when the fee exceeds any single input's
|
|
803
|
+
* value. Finds the next available intent segment id in a transaction.
|
|
804
|
+
*
|
|
805
|
+
* Fallible intent segments occupy the range `[1, 65535]`; segment `0` is reserved for the guaranteed section and is
|
|
806
|
+
* never returned.
|
|
807
|
+
*
|
|
808
|
+
* @param transaction - Transaction whose intent map is inspected.
|
|
809
|
+
* @returns `Some(segmentId)` with the lowest unused id, or `None` if all 65535 fallible segments are taken.
|
|
810
|
+
*/
|
|
811
|
+
const findAvailableSegmentId = (transaction) => {
|
|
812
|
+
const used = new Set(transaction.intents?.keys() ?? []);
|
|
813
|
+
return require_const.pipe(require_const.range$1(1, 65535), require_const.findFirst$2((segmentId) => !used.has(segmentId)));
|
|
814
|
+
};
|
|
815
|
+
/**
|
|
816
|
+
* Distributes the fee across multiple inputs, draining smaller inputs first when the fee exceeds any single input's
|
|
817
|
+
* value.
|
|
818
|
+
*/
|
|
819
|
+
const distributeFeeAcrossInputs = (inputs, fee) => inputs.reduce(({ result, remaining }, input) => {
|
|
820
|
+
const deduction = remaining >= input.value ? input.value : remaining;
|
|
821
|
+
return {
|
|
822
|
+
result: [...result, {
|
|
823
|
+
...input,
|
|
824
|
+
value: deduction
|
|
825
|
+
}],
|
|
826
|
+
remaining: remaining - deduction
|
|
827
|
+
};
|
|
828
|
+
}, {
|
|
829
|
+
result: [],
|
|
830
|
+
remaining: fee
|
|
831
|
+
}).result;
|
|
832
|
+
var TransactingCapabilityImplementation$1 = class TransactingCapabilityImplementation$1 {
|
|
833
|
+
networkId;
|
|
834
|
+
costParams;
|
|
835
|
+
getCoinSelection;
|
|
836
|
+
getCoins;
|
|
837
|
+
getKeys;
|
|
838
|
+
constructor(networkId, costParams, getCoinSelection, getCoins, getKeys) {
|
|
839
|
+
this.getCoins = getCoins;
|
|
840
|
+
this.networkId = networkId;
|
|
841
|
+
this.costParams = costParams;
|
|
842
|
+
this.getCoinSelection = getCoinSelection;
|
|
843
|
+
this.getKeys = getKeys;
|
|
844
|
+
}
|
|
845
|
+
createDustGenerationTransaction(currentTime, ttl, nightUtxos, nightVerifyingKey, dustReceiverAddress) {
|
|
846
|
+
const makeOffer = (utxos) => {
|
|
847
|
+
if (utxos.length === 0) return require_const.none();
|
|
848
|
+
const totalValue = require_const.pipe(utxos, require_const.map$7((coin) => coin.utxo.value), require_const.sumAll);
|
|
849
|
+
const inputs = utxos.map(({ utxo }) => ({
|
|
850
|
+
...utxo,
|
|
851
|
+
owner: nightVerifyingKey
|
|
852
|
+
}));
|
|
853
|
+
const output = {
|
|
854
|
+
owner: (0, _midnight_ntwrk_ledger_v8.addressFromKey)(nightVerifyingKey),
|
|
855
|
+
type: (0, _midnight_ntwrk_ledger_v8.nativeToken)().raw,
|
|
856
|
+
value: totalValue
|
|
857
|
+
};
|
|
858
|
+
return require_const.some(_midnight_ntwrk_ledger_v8.UnshieldedOffer.new(inputs, [output], []));
|
|
859
|
+
};
|
|
860
|
+
return require_const.gen$1(this, function* () {
|
|
861
|
+
const receiver = dustReceiverAddress ? dustReceiverAddress.data : void 0;
|
|
862
|
+
return yield* require_watch.ledgerTry(() => {
|
|
863
|
+
const network = this.networkId;
|
|
864
|
+
const splitResult = this.getCoins().splitNightUtxos(nightUtxos);
|
|
865
|
+
const feePayment = receiver ? require_const.pipe(splitResult.guaranteed, require_const.filter$3((coin) => !coin.utxo.registeredForDustGeneration), require_const.map$7((coin) => coin.dust.generatedNow), require_const.sumAll) : 0n;
|
|
866
|
+
const maybeGuaranteedOffer = makeOffer(splitResult.guaranteed);
|
|
867
|
+
const maybeFallibleOffer = makeOffer(splitResult.fallible);
|
|
868
|
+
const dustRegistration = new _midnight_ntwrk_ledger_v8.DustRegistration(SignatureMarker.signature, nightVerifyingKey, receiver, feePayment);
|
|
869
|
+
const dustActions = new _midnight_ntwrk_ledger_v8.DustActions(SignatureMarker.signature, ProofMarker.preProof, currentTime, [], [dustRegistration]);
|
|
870
|
+
const intent = require_const.pipe(_midnight_ntwrk_ledger_v8.Intent.new(ttl), (intent) => require_const.match$3(maybeGuaranteedOffer, {
|
|
871
|
+
onNone: () => intent,
|
|
872
|
+
onSome: (guaranteedOffer) => {
|
|
873
|
+
intent.guaranteedUnshieldedOffer = guaranteedOffer;
|
|
874
|
+
return intent;
|
|
875
|
+
}
|
|
876
|
+
}), (intent) => require_const.match$3(maybeFallibleOffer, {
|
|
877
|
+
onNone: () => intent,
|
|
878
|
+
onSome: (fallibleOffer) => {
|
|
879
|
+
intent.fallibleUnshieldedOffer = fallibleOffer;
|
|
880
|
+
return intent;
|
|
881
|
+
}
|
|
882
|
+
}), (intent) => {
|
|
883
|
+
intent.dustActions = dustActions;
|
|
884
|
+
return intent;
|
|
885
|
+
});
|
|
886
|
+
return _midnight_ntwrk_ledger_v8.Transaction.fromParts(network, void 0, void 0, intent);
|
|
887
|
+
});
|
|
888
|
+
});
|
|
889
|
+
}
|
|
890
|
+
splitNightUtxosForDustRegistration(utxosWithDustValue, isRegistration) {
|
|
891
|
+
const splitResult = this.getCoins().splitNightUtxos(utxosWithDustValue);
|
|
892
|
+
const feePayment = isRegistration ? require_const.pipe(splitResult.guaranteed, require_const.filter$3((coin) => !coin.utxo.registeredForDustGeneration), require_const.map$7((coin) => coin.dust.generatedNow), require_const.sumAll) : 0n;
|
|
893
|
+
return {
|
|
894
|
+
guaranteedUtxos: splitResult.guaranteed,
|
|
895
|
+
fallibleUtxos: splitResult.fallible,
|
|
896
|
+
feePayment
|
|
897
|
+
};
|
|
898
|
+
}
|
|
899
|
+
attachDustRegistration(transaction, currentTime, nightVerifyingKey, dustReceiverAddress, feePayment) {
|
|
900
|
+
return require_const.gen$1(this, function* () {
|
|
901
|
+
const intent = transaction.intents?.get(1);
|
|
902
|
+
if (!intent) return yield* require_const.left(new TransactingError({ message: "No intent found at segment 1; expected an intent built by rotateUtxos" }));
|
|
903
|
+
if (intent.dustActions !== void 0 && intent.dustActions.registrations.length > 0) return yield* require_const.left(new TransactingError({ message: "Intent at segment 1 already has a dust registration attached" }));
|
|
904
|
+
return yield* require_watch.ledgerTry(() => {
|
|
905
|
+
const receiver = dustReceiverAddress ? dustReceiverAddress.data : void 0;
|
|
906
|
+
const dustRegistration = new _midnight_ntwrk_ledger_v8.DustRegistration(SignatureMarker.signature, nightVerifyingKey, receiver, feePayment);
|
|
907
|
+
const dustActions = new _midnight_ntwrk_ledger_v8.DustActions(SignatureMarker.signature, ProofMarker.preProof, currentTime, [], [dustRegistration]);
|
|
908
|
+
const newIntent = _midnight_ntwrk_ledger_v8.Intent.deserialize(SignatureMarker.signature, ProofMarker.preProof, BindingMarker.preBinding, intent.serialize());
|
|
909
|
+
newIntent.dustActions = dustActions;
|
|
910
|
+
const newTransaction = _midnight_ntwrk_ledger_v8.Transaction.deserialize(SignatureMarker.signature, ProofMarker.preProof, BindingMarker.preBinding, transaction.serialize());
|
|
911
|
+
newTransaction.intents = newTransaction.intents.set(1, newIntent);
|
|
912
|
+
return newTransaction;
|
|
913
|
+
});
|
|
914
|
+
});
|
|
915
|
+
}
|
|
916
|
+
addDustRegistrationSignature(transaction, signatureData) {
|
|
917
|
+
return require_const.gen$1(this, function* () {
|
|
918
|
+
const intent = transaction.intents?.get(1);
|
|
919
|
+
if (!intent) return yield* require_const.left(new TransactingError({ message: "No intent found in the transaction intents with segment = 1" }));
|
|
920
|
+
const { dustActions } = intent;
|
|
921
|
+
if (!dustActions) return yield* require_const.left(new TransactingError({ message: "No dustActions found in intent" }));
|
|
922
|
+
const [registration, ...restRegistrations] = dustActions.registrations;
|
|
923
|
+
if (!registration) return yield* require_const.left(new TransactingError({ message: "No registrations found in dustActions" }));
|
|
924
|
+
return yield* require_watch.ledgerTry(() => {
|
|
925
|
+
const signature = new _midnight_ntwrk_ledger_v8.SignatureEnabled(signatureData);
|
|
926
|
+
const registrationWithSignature = new _midnight_ntwrk_ledger_v8.DustRegistration(signature.instance, registration.nightKey, registration.dustAddress, registration.allowFeePayment, signature);
|
|
927
|
+
const newDustActions = new _midnight_ntwrk_ledger_v8.DustActions(signature.instance, ProofMarker.preProof, dustActions.ctime, dustActions.spends, [registrationWithSignature, ...restRegistrations]);
|
|
928
|
+
const newIntent = _midnight_ntwrk_ledger_v8.Intent.deserialize(signature.instance, ProofMarker.preProof, BindingMarker.preBinding, intent.serialize());
|
|
929
|
+
newIntent.dustActions = newDustActions;
|
|
930
|
+
const newTransaction = _midnight_ntwrk_ledger_v8.Transaction.deserialize(signature.instance, ProofMarker.preProof, BindingMarker.preBinding, transaction.serialize());
|
|
931
|
+
newTransaction.intents = newTransaction.intents.set(1, newIntent);
|
|
932
|
+
return newTransaction;
|
|
933
|
+
});
|
|
934
|
+
});
|
|
935
|
+
}
|
|
936
|
+
addDustGenerationSignature(transaction, signatureData) {
|
|
937
|
+
return require_const.gen$1(this, function* () {
|
|
938
|
+
const intent = transaction.intents?.get(1);
|
|
939
|
+
if (!intent) return yield* require_const.left(new TransactingError({ message: "No intent found in the transaction intents with segment = 1" }));
|
|
940
|
+
const { dustActions, guaranteedUnshieldedOffer, fallibleUnshieldedOffer } = intent;
|
|
941
|
+
if (!dustActions) return yield* require_const.left(new TransactingError({ message: "No dustActions found in intent" }));
|
|
942
|
+
if (!guaranteedUnshieldedOffer) return yield* require_const.left(new TransactingError({ message: "No guaranteedUnshieldedOffer found in intent" }));
|
|
943
|
+
const [registration, ...restRegistrations] = dustActions.registrations;
|
|
944
|
+
if (!registration) return yield* require_const.left(new TransactingError({ message: "No registrations found in dustActions" }));
|
|
945
|
+
return yield* require_watch.ledgerTry(() => {
|
|
946
|
+
const signature = new _midnight_ntwrk_ledger_v8.SignatureEnabled(signatureData);
|
|
947
|
+
const registrationWithSignature = new _midnight_ntwrk_ledger_v8.DustRegistration(signature.instance, registration.nightKey, registration.dustAddress, registration.allowFeePayment, signature);
|
|
948
|
+
const newDustActions = new _midnight_ntwrk_ledger_v8.DustActions(signature.instance, ProofMarker.preProof, dustActions.ctime, dustActions.spends, [registrationWithSignature, ...restRegistrations]);
|
|
949
|
+
const newIntent = _midnight_ntwrk_ledger_v8.Intent.deserialize(signature.instance, ProofMarker.preProof, BindingMarker.preBinding, intent.serialize());
|
|
950
|
+
newIntent.dustActions = newDustActions;
|
|
951
|
+
const inputsLen = guaranteedUnshieldedOffer.inputs.length;
|
|
952
|
+
const signatures = [];
|
|
953
|
+
for (let i = 0; i < inputsLen; ++i) signatures.push(guaranteedUnshieldedOffer.signatures.at(i) ?? signatureData);
|
|
954
|
+
newIntent.guaranteedUnshieldedOffer = guaranteedUnshieldedOffer.addSignatures(signatures);
|
|
955
|
+
if (fallibleUnshieldedOffer) {
|
|
956
|
+
const inputsLen = fallibleUnshieldedOffer.inputs.length;
|
|
957
|
+
const signatures = [];
|
|
958
|
+
for (let i = 0; i < inputsLen; ++i) signatures.push(fallibleUnshieldedOffer.signatures.at(i) ?? signatureData);
|
|
959
|
+
newIntent.fallibleUnshieldedOffer = fallibleUnshieldedOffer.addSignatures(signatures);
|
|
960
|
+
}
|
|
961
|
+
const newTransaction = _midnight_ntwrk_ledger_v8.Transaction.deserialize(signature.instance, ProofMarker.preProof, BindingMarker.preBinding, transaction.serialize());
|
|
962
|
+
newTransaction.intents = newTransaction.intents.set(1, newIntent);
|
|
963
|
+
return newTransaction;
|
|
964
|
+
});
|
|
965
|
+
});
|
|
966
|
+
}
|
|
967
|
+
calculateFee(transaction, ledgerParams) {
|
|
968
|
+
return transaction.feesWithMargin(ledgerParams, this.costParams.feeBlocksMargin) + (this.costParams.additionalFeeOverhead ?? 0n);
|
|
969
|
+
}
|
|
970
|
+
dryRunFee(recipeInputs, transactions, secretKey, state, ttl, currentTime, ledgerParams) {
|
|
971
|
+
const network = this.networkId;
|
|
972
|
+
const [spends] = CoreWallet$1.spendCoins(state, secretKey, recipeInputs, currentTime);
|
|
973
|
+
const intent = _midnight_ntwrk_ledger_v8.Intent.new(ttl);
|
|
974
|
+
intent.dustActions = new _midnight_ntwrk_ledger_v8.DustActions(SignatureMarker.signature, ProofMarker.preProof, currentTime, [...spends], []);
|
|
975
|
+
const [first, ...rest] = transactions.map((tx) => tx.eraseProofs());
|
|
976
|
+
const mergedExisting = first ? rest.reduce((acc, tx) => acc.merge(tx), first) : void 0;
|
|
977
|
+
const segmentId = mergedExisting ? require_const.getOrElse(findAvailableSegmentId(mergedExisting), () => 1) : 1;
|
|
978
|
+
const erasedBalancing = _midnight_ntwrk_ledger_v8.Transaction.fromParts(network).addIntent({
|
|
979
|
+
tag: "specific",
|
|
980
|
+
value: segmentId
|
|
981
|
+
}, intent).eraseProofs();
|
|
982
|
+
const mergedTx = mergedExisting ? mergedExisting.merge(erasedBalancing) : erasedBalancing;
|
|
983
|
+
return this.calculateFee(mergedTx, ledgerParams);
|
|
984
|
+
}
|
|
985
|
+
static feeImbalance(transaction, totalFee) {
|
|
986
|
+
const [_, imbalance] = transaction.imbalances(0, totalFee).entries().find(([tt, _]) => tt.tag === "dust") ?? [];
|
|
987
|
+
return imbalance ?? 0n;
|
|
988
|
+
}
|
|
989
|
+
computeBalancingRecipe(secretKey, state, transactions, ttl, currentTime, ledgerParams) {
|
|
990
|
+
const initialFees = transactions.reduce((total, transaction) => total + TransactingCapabilityImplementation$1.feeImbalance(transaction, this.calculateFee(transaction, ledgerParams)), 0n);
|
|
991
|
+
const dust = this.getCoins().getAvailableCoinsWithGeneratedDust(state, currentTime);
|
|
992
|
+
return require_const.pipe(require_const.iterate({
|
|
993
|
+
currentFee: initialFees,
|
|
994
|
+
recipeInputs: [],
|
|
995
|
+
converged: false
|
|
996
|
+
}, {
|
|
997
|
+
while: (s) => !s.converged,
|
|
998
|
+
body: ({ currentFee }) => require_const.try_({
|
|
999
|
+
try: () => {
|
|
1000
|
+
const recipeInputs = require_watch.getBalanceRecipe({
|
|
1001
|
+
coins: dust.map((coin) => ({
|
|
1002
|
+
type: "dust",
|
|
1003
|
+
value: coin.value,
|
|
1004
|
+
token: coin.token
|
|
1005
|
+
})),
|
|
1006
|
+
initialImbalances: require_watch.Imbalances.fromEntry("dust", currentFee),
|
|
1007
|
+
feeTokenType: "dust",
|
|
1008
|
+
coinSelection: this.getCoinSelection(),
|
|
1009
|
+
transactionCostModel: {
|
|
1010
|
+
inputFeeOverhead: 0n,
|
|
1011
|
+
outputFeeOverhead: 0n
|
|
1012
|
+
},
|
|
1013
|
+
createOutput: (coin) => coin,
|
|
1014
|
+
isCoinEqual: (a, b) => a.token.nonce === b.token.nonce
|
|
1015
|
+
}).inputs.map(({ token, value }) => ({
|
|
1016
|
+
token,
|
|
1017
|
+
value
|
|
1018
|
+
}));
|
|
1019
|
+
const newFee = this.dryRunFee(recipeInputs, transactions, secretKey, state, ttl, currentTime, ledgerParams);
|
|
1020
|
+
return {
|
|
1021
|
+
currentFee: newFee,
|
|
1022
|
+
recipeInputs,
|
|
1023
|
+
converged: newFee <= recipeInputs.reduce((sum, input) => sum + input.value, 0n)
|
|
1024
|
+
};
|
|
1025
|
+
},
|
|
1026
|
+
catch: (err) => {
|
|
1027
|
+
if (err instanceof require_watch.InsufficientFundsError) return new InsufficientFundsError$1({
|
|
1028
|
+
message: err.message,
|
|
1029
|
+
tokenType: err.tokenType
|
|
1030
|
+
});
|
|
1031
|
+
else return new OtherWalletError$1({
|
|
1032
|
+
message: err instanceof Error ? err.message : "Dust balancing failed",
|
|
1033
|
+
cause: err
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
1036
|
+
})
|
|
1037
|
+
}), require_const.either, require_const.runSync, require_const.map$9(({ currentFee, recipeInputs }) => ({
|
|
1038
|
+
fee: currentFee,
|
|
1039
|
+
recipeInputs: distributeFeeAcrossInputs(recipeInputs, currentFee)
|
|
1040
|
+
})));
|
|
1041
|
+
}
|
|
1042
|
+
estimateFee(secretKey, state, transactions, ttl, currentTime, ledgerParams) {
|
|
1043
|
+
return require_const.pipe(this.computeBalancingRecipe(secretKey, state, transactions, ttl, currentTime, ledgerParams), require_const.map$9(({ fee }) => fee));
|
|
1044
|
+
}
|
|
1045
|
+
balanceTransactions(secretKey, state, transactions, ttl, currentTime, ledgerParams) {
|
|
1046
|
+
const networkId = this.networkId;
|
|
1047
|
+
return require_const.pipe(this.computeBalancingRecipe(secretKey, state, transactions, ttl, currentTime, ledgerParams), require_const.flatMap$4(({ recipeInputs }) => {
|
|
1048
|
+
return require_watch.ledgerTry(() => {
|
|
1049
|
+
const intent = _midnight_ntwrk_ledger_v8.Intent.new(ttl);
|
|
1050
|
+
const [spends, updatedState] = CoreWallet$1.spendCoins(state, secretKey, recipeInputs, currentTime);
|
|
1051
|
+
intent.dustActions = new _midnight_ntwrk_ledger_v8.DustActions(SignatureMarker.signature, ProofMarker.preProof, currentTime, [...spends], []);
|
|
1052
|
+
const [first, ...rest] = transactions.map((tx) => tx.eraseProofs());
|
|
1053
|
+
const mergedExisting = first ? rest.reduce((acc, tx) => acc.merge(tx), first) : void 0;
|
|
1054
|
+
const segmentId = mergedExisting ? require_const.getOrElse(findAvailableSegmentId(mergedExisting), () => 1) : 1;
|
|
1055
|
+
return [_midnight_ntwrk_ledger_v8.Transaction.fromParts(networkId).addIntent({
|
|
1056
|
+
tag: "specific",
|
|
1057
|
+
value: segmentId
|
|
1058
|
+
}, intent), updatedState];
|
|
1059
|
+
});
|
|
1060
|
+
}));
|
|
1061
|
+
}
|
|
1062
|
+
revertTransaction(state, transaction) {
|
|
1063
|
+
return require_const.try_$1({
|
|
1064
|
+
try: () => CoreWallet$1.revertTransaction(state, transaction),
|
|
1065
|
+
catch: (err) => {
|
|
1066
|
+
return new OtherWalletError$1({
|
|
1067
|
+
message: `Error while reverting transaction ${transaction.identifiers().at(0)}`,
|
|
1068
|
+
cause: err
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
1071
|
+
});
|
|
1072
|
+
}
|
|
1073
|
+
};
|
|
1074
|
+
//#endregion
|
|
1075
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-dust-wallet/dist/v1/V1Builder.js
|
|
1076
|
+
var V1Builder$1 = class V1Builder$1 {
|
|
1077
|
+
#buildState;
|
|
1078
|
+
constructor(buildState = {}) {
|
|
1079
|
+
this.#buildState = buildState;
|
|
1080
|
+
}
|
|
1081
|
+
withDefaults() {
|
|
1082
|
+
return this.withDefaultTransactionType().withSyncDefaults().withSerializationDefaults().withTransactingDefaults().withCoinsAndBalancesDefaults().withTransactionHistoryDefaults().withKeysDefaults().withCoinSelectionDefaults();
|
|
1083
|
+
}
|
|
1084
|
+
withTransactionType() {
|
|
1085
|
+
return new V1Builder$1({
|
|
1086
|
+
...this.#buildState,
|
|
1087
|
+
transactingCapability: void 0
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
1090
|
+
withDefaultTransactionType() {
|
|
1091
|
+
return this.withTransactionType();
|
|
1092
|
+
}
|
|
1093
|
+
withSyncDefaults() {
|
|
1094
|
+
return this.withSync(makeDefaultSyncService, makeDefaultSyncCapability);
|
|
1095
|
+
}
|
|
1096
|
+
withSync(syncService, syncCapability) {
|
|
1097
|
+
return new V1Builder$1({
|
|
1098
|
+
...this.#buildState,
|
|
1099
|
+
syncService,
|
|
1100
|
+
syncCapability
|
|
1101
|
+
});
|
|
1102
|
+
}
|
|
1103
|
+
withSerializationDefaults() {
|
|
1104
|
+
return this.withSerialization(makeDefaultV1SerializationCapability$1);
|
|
1105
|
+
}
|
|
1106
|
+
withSerialization(serializationCapability) {
|
|
1107
|
+
return new V1Builder$1({
|
|
1108
|
+
...this.#buildState,
|
|
1109
|
+
serializationCapability
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1112
|
+
withTransactingDefaults() {
|
|
1113
|
+
return this.withTransacting(makeDefaultTransactingCapability$1);
|
|
1114
|
+
}
|
|
1115
|
+
withTransacting(transactingCapability) {
|
|
1116
|
+
return new V1Builder$1({
|
|
1117
|
+
...this.#buildState,
|
|
1118
|
+
transactingCapability
|
|
1119
|
+
});
|
|
1120
|
+
}
|
|
1121
|
+
withCoinSelection(coinSelection) {
|
|
1122
|
+
return new V1Builder$1({
|
|
1123
|
+
...this.#buildState,
|
|
1124
|
+
coinSelection
|
|
1125
|
+
});
|
|
1126
|
+
}
|
|
1127
|
+
withCoinSelectionDefaults() {
|
|
1128
|
+
return this.withCoinSelection(() => chooseCoin);
|
|
1129
|
+
}
|
|
1130
|
+
withCoinsAndBalancesDefaults() {
|
|
1131
|
+
return this.withCoinsAndBalances(makeDefaultCoinsAndBalancesCapability$1);
|
|
1132
|
+
}
|
|
1133
|
+
withCoinsAndBalances(coinsAndBalancesCapability) {
|
|
1134
|
+
return new V1Builder$1({
|
|
1135
|
+
...this.#buildState,
|
|
1136
|
+
coinsAndBalancesCapability
|
|
1137
|
+
});
|
|
1138
|
+
}
|
|
1139
|
+
withTransactionHistoryDefaults() {
|
|
1140
|
+
return this.withTransactionHistory(makeDefaultTransactionHistoryService$1);
|
|
1141
|
+
}
|
|
1142
|
+
withTransactionHistory(transactionHistoryService) {
|
|
1143
|
+
return new V1Builder$1({
|
|
1144
|
+
...this.#buildState,
|
|
1145
|
+
transactionHistoryService
|
|
1146
|
+
});
|
|
1147
|
+
}
|
|
1148
|
+
withKeysDefaults() {
|
|
1149
|
+
return this.withKeys(makeDefaultKeysCapability$1);
|
|
1150
|
+
}
|
|
1151
|
+
withKeys(keysCapability) {
|
|
1152
|
+
return new V1Builder$1({
|
|
1153
|
+
...this.#buildState,
|
|
1154
|
+
keysCapability
|
|
1155
|
+
});
|
|
1156
|
+
}
|
|
1157
|
+
build(configuration) {
|
|
1158
|
+
const v1Context = this.#buildContextFromBuildState(configuration);
|
|
1159
|
+
return {
|
|
1160
|
+
__polyTag__: V1Tag$1,
|
|
1161
|
+
coinsAndBalances: v1Context.coinsAndBalancesCapability,
|
|
1162
|
+
keys: v1Context.keysCapability,
|
|
1163
|
+
serialization: v1Context.serializationCapability,
|
|
1164
|
+
transactionHistory: v1Context.transactionHistoryService,
|
|
1165
|
+
start(context) {
|
|
1166
|
+
return require_const.gen(function* () {
|
|
1167
|
+
return new RunningV1Variant$1(yield* require_const.Scope, context, v1Context);
|
|
1168
|
+
});
|
|
1169
|
+
},
|
|
1170
|
+
migrateState(prevState) {
|
|
1171
|
+
return require_const.succeed(prevState);
|
|
1172
|
+
},
|
|
1173
|
+
deserializeState: (serialized) => {
|
|
1174
|
+
return v1Context.serializationCapability.deserialize(null, serialized);
|
|
1175
|
+
}
|
|
1176
|
+
};
|
|
1177
|
+
}
|
|
1178
|
+
#buildContextFromBuildState(configuration) {
|
|
1179
|
+
if (!isBuildStateFull$1(this.#buildState)) throw new Error("Not all components are configured in V1 Builder");
|
|
1180
|
+
const { syncCapability, syncService, transactingCapability, serializationCapability, coinSelection, coinsAndBalancesCapability, keysCapability, transactionHistoryService } = this.#buildState;
|
|
1181
|
+
const getContext = () => context;
|
|
1182
|
+
const context = {
|
|
1183
|
+
serializationCapability: serializationCapability(configuration, getContext),
|
|
1184
|
+
syncCapability: syncCapability(configuration, getContext),
|
|
1185
|
+
syncService: syncService(configuration, getContext),
|
|
1186
|
+
transactingCapability: transactingCapability(configuration, getContext),
|
|
1187
|
+
coinsAndBalancesCapability: coinsAndBalancesCapability(configuration, getContext),
|
|
1188
|
+
keysCapability: keysCapability(configuration, getContext),
|
|
1189
|
+
coinSelection: coinSelection(configuration, getContext),
|
|
1190
|
+
transactionHistoryService: transactionHistoryService(configuration, getContext)
|
|
1191
|
+
};
|
|
1192
|
+
return context;
|
|
1193
|
+
}
|
|
1194
|
+
};
|
|
1195
|
+
const isBuildStateFull$1 = (buildState) => {
|
|
1196
|
+
return [
|
|
1197
|
+
"syncService",
|
|
1198
|
+
"syncCapability",
|
|
1199
|
+
"transactingCapability",
|
|
1200
|
+
"coinSelection",
|
|
1201
|
+
"serializationCapability",
|
|
1202
|
+
"coinsAndBalancesCapability",
|
|
1203
|
+
"keysCapability",
|
|
1204
|
+
"transactionHistoryService"
|
|
1205
|
+
].every((key) => typeof buildState[key] == "function");
|
|
1206
|
+
};
|
|
1207
|
+
//#endregion
|
|
1208
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-dust-wallet/dist/DustWallet.js
|
|
1209
|
+
var DustWalletState = class DustWalletState {
|
|
1210
|
+
static mapState = (variant) => (state) => {
|
|
1211
|
+
const { serialization, coinsAndBalances, keys } = variant;
|
|
1212
|
+
const { transactionHistory } = variant;
|
|
1213
|
+
return new DustWalletState(state, {
|
|
1214
|
+
serialization,
|
|
1215
|
+
coinsAndBalances,
|
|
1216
|
+
keys
|
|
1217
|
+
}, { transactionHistory });
|
|
1218
|
+
};
|
|
1219
|
+
protocolVersion;
|
|
1220
|
+
state;
|
|
1221
|
+
capabilities;
|
|
1222
|
+
services;
|
|
1223
|
+
get totalCoins() {
|
|
1224
|
+
return this.capabilities.coinsAndBalances.getTotalCoins(this.state);
|
|
1225
|
+
}
|
|
1226
|
+
get availableCoins() {
|
|
1227
|
+
return this.capabilities.coinsAndBalances.getAvailableCoins(this.state);
|
|
1228
|
+
}
|
|
1229
|
+
get pendingCoins() {
|
|
1230
|
+
return this.capabilities.coinsAndBalances.getPendingCoins(this.state);
|
|
1231
|
+
}
|
|
1232
|
+
get publicKey() {
|
|
1233
|
+
return this.capabilities.keys.getPublicKey(this.state);
|
|
1234
|
+
}
|
|
1235
|
+
get address() {
|
|
1236
|
+
return this.capabilities.keys.getAddress(this.state);
|
|
1237
|
+
}
|
|
1238
|
+
get progress() {
|
|
1239
|
+
return this.state.progress;
|
|
1240
|
+
}
|
|
1241
|
+
constructor(state, capabilities, services) {
|
|
1242
|
+
this.protocolVersion = state.version;
|
|
1243
|
+
this.state = state.state;
|
|
1244
|
+
this.capabilities = capabilities;
|
|
1245
|
+
this.services = services;
|
|
1246
|
+
}
|
|
1247
|
+
balance(time) {
|
|
1248
|
+
return this.capabilities.coinsAndBalances.getWalletBalance(this.state, time);
|
|
1249
|
+
}
|
|
1250
|
+
estimateDustGeneration(nightUtxos, currentTime) {
|
|
1251
|
+
return this.capabilities.coinsAndBalances.estimateDustGeneration(this.state, nightUtxos, currentTime);
|
|
1252
|
+
}
|
|
1253
|
+
serialize() {
|
|
1254
|
+
return this.capabilities.serialization.serialize(this.state);
|
|
1255
|
+
}
|
|
1256
|
+
};
|
|
1257
|
+
function DustWallet(configuration) {
|
|
1258
|
+
return CustomDustWallet(configuration, new V1Builder$1().withDefaults());
|
|
1259
|
+
}
|
|
1260
|
+
function CustomDustWallet(configuration, builder) {
|
|
1261
|
+
const buildArgs = [configuration];
|
|
1262
|
+
const BaseWallet = require_watch.WalletBuilder.init().withVariant(require_const.MinSupportedVersion, builder).build(...buildArgs);
|
|
1263
|
+
return class CustomDustWalletImplementation extends BaseWallet {
|
|
1264
|
+
static startWithSeed(seed, dustParameters) {
|
|
1265
|
+
const dustSecretKey = _midnight_ntwrk_ledger_v8.DustSecretKey.fromSeed(seed);
|
|
1266
|
+
return CustomDustWalletImplementation.startFirst(CustomDustWalletImplementation, CoreWallet$1.initEmpty(dustParameters, dustSecretKey, CustomDustWalletImplementation.configuration.networkId));
|
|
1267
|
+
}
|
|
1268
|
+
static startWithSecretKey(secretKey, dustParameters) {
|
|
1269
|
+
return CustomDustWalletImplementation.startFirst(CustomDustWalletImplementation, CoreWallet$1.initEmpty(dustParameters, secretKey, CustomDustWalletImplementation.configuration.networkId));
|
|
1270
|
+
}
|
|
1271
|
+
static restore(serializedState) {
|
|
1272
|
+
const deserialized = CustomDustWalletImplementation.allVariantsRecord()[V1Tag$1].variant.deserializeState(serializedState).pipe(require_const.getOrThrow$1);
|
|
1273
|
+
return CustomDustWalletImplementation.startFirst(CustomDustWalletImplementation, deserialized);
|
|
1274
|
+
}
|
|
1275
|
+
state;
|
|
1276
|
+
constructor(runtime, scope) {
|
|
1277
|
+
super(runtime, scope);
|
|
1278
|
+
this.state = this.rawState.pipe(rxjs.map(DustWalletState.mapState(CustomDustWalletImplementation.allVariantsRecord()[V1Tag$1].variant)), rxjs.shareReplay({
|
|
1279
|
+
refCount: true,
|
|
1280
|
+
bufferSize: 1
|
|
1281
|
+
}));
|
|
1282
|
+
}
|
|
1283
|
+
start(secretKey) {
|
|
1284
|
+
return this.runtime.dispatch({ [V1Tag$1]: (v1) => v1.startSyncInBackground(secretKey) }).pipe(require_const.runPromise);
|
|
1285
|
+
}
|
|
1286
|
+
async createDustGenerationTransaction(currentTime, ttl, nightUtxos, nightVerifyingKey, dustReceiverAddress) {
|
|
1287
|
+
return this.runtime.dispatch({ [V1Tag$1]: (v1) => v1.createDustGenerationTransaction(currentTime, ttl, nightUtxos, nightVerifyingKey, dustReceiverAddress) }).pipe(require_const.runPromise);
|
|
1288
|
+
}
|
|
1289
|
+
async splitNightUtxosForDustRegistration(currentTime, nightUtxos, isRegistration) {
|
|
1290
|
+
return this.runtime.dispatch({ [V1Tag$1]: (v1) => v1.splitNightUtxosForDustRegistration(currentTime, nightUtxos, isRegistration) }).pipe(require_const.runPromise);
|
|
1291
|
+
}
|
|
1292
|
+
async attachDustRegistration(transaction, currentTime, nightVerifyingKey, dustReceiverAddress, feePayment) {
|
|
1293
|
+
return this.runtime.dispatch({ [V1Tag$1]: (v1) => v1.attachDustRegistration(transaction, currentTime, nightVerifyingKey, dustReceiverAddress, feePayment) }).pipe(require_const.runPromise);
|
|
1294
|
+
}
|
|
1295
|
+
addDustGenerationSignature(transaction, signature) {
|
|
1296
|
+
return this.runtime.dispatch({ [V1Tag$1]: (v1) => v1.addDustGenerationSignature(transaction, signature) }).pipe(require_const.runPromise);
|
|
1297
|
+
}
|
|
1298
|
+
addDustRegistrationSignature(transaction, signature) {
|
|
1299
|
+
return this.runtime.dispatch({ [V1Tag$1]: (v1) => v1.addDustRegistrationSignature(transaction, signature) }).pipe(require_const.runPromise);
|
|
1300
|
+
}
|
|
1301
|
+
calculateFee(transactions) {
|
|
1302
|
+
return this.runtime.dispatch({ [V1Tag$1]: (v1) => v1.calculateFee(transactions) }).pipe(require_const.runPromise);
|
|
1303
|
+
}
|
|
1304
|
+
estimateFee(secretKey, transactions, ttl, currentTime) {
|
|
1305
|
+
const effectiveTtl = ttl ?? new Date(Date.now() + 3600 * 1e3);
|
|
1306
|
+
return this.runtime.dispatch({ [V1Tag$1]: (v1) => v1.estimateFee(secretKey, transactions, effectiveTtl, currentTime) }).pipe(require_const.runPromise);
|
|
1307
|
+
}
|
|
1308
|
+
balanceTransactions(secretKey, transactions, ttl, currentTime) {
|
|
1309
|
+
return this.runtime.dispatch({ [V1Tag$1]: (v1) => v1.balanceTransactions(secretKey, transactions, ttl, currentTime) }).pipe(require_const.runPromise);
|
|
1310
|
+
}
|
|
1311
|
+
revertTransaction(transaction) {
|
|
1312
|
+
return this.runtime.dispatch({ [V1Tag$1]: (v1) => v1.revertTransaction(transaction) }).pipe(require_const.runPromise);
|
|
1313
|
+
}
|
|
1314
|
+
waitForSyncedState(allowedGap = 0n) {
|
|
1315
|
+
return rxjs.firstValueFrom(this.state.pipe(rxjs.filter((state) => state.state.progress.isCompleteWithin(allowedGap))));
|
|
1316
|
+
}
|
|
1317
|
+
async waitForGeneratedDust(nightUtxos, requiredAmount, clock, opts) {
|
|
1318
|
+
if (nightUtxos.length === 0) throw Error("At least one Night UTXO is required.");
|
|
1319
|
+
if (requiredAmount <= 0n) return;
|
|
1320
|
+
const timeoutMs = opts?.timeoutMs ?? 3e5;
|
|
1321
|
+
await rxjs.firstValueFrom(rxjs.combineLatest([this.state, rxjs.timer(0, 1e3)]).pipe(rxjs.filter(([dustState]) => {
|
|
1322
|
+
return dustState.estimateDustGeneration(nightUtxos, clock.now()).filter((u) => !u.utxo.registeredForDustGeneration).reduce((max, u) => u.dust.generatedNow > max ? u.dust.generatedNow : max, 0n) >= requiredAmount;
|
|
1323
|
+
}), rxjs.timeout({ first: timeoutMs })));
|
|
1324
|
+
}
|
|
1325
|
+
serializeState() {
|
|
1326
|
+
return rxjs.firstValueFrom(this.state).then((state) => state.serialize());
|
|
1327
|
+
}
|
|
1328
|
+
getAddress() {
|
|
1329
|
+
return rxjs.firstValueFrom(this.state).then((state) => state.address);
|
|
1330
|
+
}
|
|
1331
|
+
};
|
|
1332
|
+
}
|
|
1333
|
+
//#endregion
|
|
1334
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-shielded/dist/v1/WalletError.js
|
|
1335
|
+
const WalletError = {
|
|
1336
|
+
other(err) {
|
|
1337
|
+
let message;
|
|
1338
|
+
if (err) if (typeof err == "object" && "message" in err) message = String(err.message);
|
|
1339
|
+
else if (typeof err == "string") message = err;
|
|
1340
|
+
else message = "";
|
|
1341
|
+
else message = "";
|
|
1342
|
+
return new OtherWalletError({
|
|
1343
|
+
message: `Other wallet error: ${message}`,
|
|
1344
|
+
cause: err
|
|
1345
|
+
});
|
|
1346
|
+
},
|
|
1347
|
+
submission(err) {
|
|
1348
|
+
return new SubmissionError({
|
|
1349
|
+
message: `Transaction submission error: ${err && typeof err == "object" && "message" in err ? String(err.message) : ""}`,
|
|
1350
|
+
cause: err
|
|
1351
|
+
});
|
|
1352
|
+
}
|
|
1353
|
+
};
|
|
1354
|
+
var OtherWalletError = class extends require_const.TaggedError("Wallet.Other") {};
|
|
1355
|
+
var SyncWalletError = class extends require_const.TaggedError("Wallet.Sync") {};
|
|
1356
|
+
var SubmissionError = class extends require_const.TaggedError("Wallet.SubmissionWalletError") {};
|
|
1357
|
+
var InsufficientFundsError = class extends require_const.TaggedError("Wallet.InsufficientFunds") {};
|
|
1358
|
+
var InvalidCoinHashesError = class extends require_const.TaggedError("Wallet.InvalidCoinHashes") {};
|
|
1359
|
+
var TransactionHistoryError = class extends require_const.TaggedError("Wallet.TransactionHistory") {};
|
|
1360
|
+
//#endregion
|
|
1361
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-shielded/dist/v1/RunningV1Variant.js
|
|
1362
|
+
const progress = (state) => {
|
|
1363
|
+
const appliedIndex = state.progress?.appliedIndex ?? 0n;
|
|
1364
|
+
const highestRelevantWalletIndex = state.progress?.highestRelevantWalletIndex ?? 0n;
|
|
1365
|
+
const sourceGap = (state.progress?.highestIndex ?? 0n) - (state.progress?.highestRelevantIndex ?? 0n);
|
|
1366
|
+
const applyGap = highestRelevantWalletIndex - appliedIndex;
|
|
1367
|
+
return [require_watch.ProgressUpdate({
|
|
1368
|
+
sourceGap,
|
|
1369
|
+
applyGap
|
|
1370
|
+
})];
|
|
1371
|
+
};
|
|
1372
|
+
const protocolVersionChange = (previous, current) => {
|
|
1373
|
+
return previous.protocolVersion != current.protocolVersion ? [require_watch.VersionChange({ change: require_watch.Version({ version: require_const.ProtocolVersion(current.protocolVersion) }) })] : [];
|
|
1374
|
+
};
|
|
1375
|
+
const V1Tag = Symbol("V1");
|
|
1376
|
+
var RunningV1Variant = class {
|
|
1377
|
+
__polyTag__ = V1Tag;
|
|
1378
|
+
#scope;
|
|
1379
|
+
#context;
|
|
1380
|
+
#v1Context;
|
|
1381
|
+
state;
|
|
1382
|
+
constructor(scope, context, v1Context) {
|
|
1383
|
+
this.#scope = scope;
|
|
1384
|
+
this.#context = context;
|
|
1385
|
+
this.#v1Context = v1Context;
|
|
1386
|
+
this.state = require_watch.fromEffect(context.stateRef.get).pipe(require_watch.flatMap((initialState) => context.stateRef.changes.pipe(require_watch.mapAccum(initialState, (previous, current) => {
|
|
1387
|
+
return [current, [previous, current]];
|
|
1388
|
+
}))), require_watch.mapConcat(([previous, current]) => {
|
|
1389
|
+
return [
|
|
1390
|
+
require_watch.State({ state: current }),
|
|
1391
|
+
...progress(current),
|
|
1392
|
+
...protocolVersionChange(previous, current)
|
|
1393
|
+
];
|
|
1394
|
+
}));
|
|
1395
|
+
}
|
|
1396
|
+
startSyncInBackground(startAux) {
|
|
1397
|
+
return this.startSync(startAux).pipe(require_watch.runScoped(require_watch.drain), require_const.forkScoped, require_const.provideService(require_const.Scope, this.#scope));
|
|
1398
|
+
}
|
|
1399
|
+
startSync(startAux) {
|
|
1400
|
+
return require_const.pipe(require_watch.get(this.#context.stateRef), require_watch.fromEffect, require_watch.flatMap((state) => this.#v1Context.syncService.updates(state, startAux)), require_watch.mapEffect((update) => require_watch.modifyEffect(this.#context.stateRef, (state) => require_const.try_({
|
|
1401
|
+
try: () => {
|
|
1402
|
+
const [newState, changesResult] = this.#v1Context.syncCapability.applyUpdate(state, update);
|
|
1403
|
+
return [changesResult, newState];
|
|
1404
|
+
},
|
|
1405
|
+
catch: (err) => new OtherWalletError({
|
|
1406
|
+
message: "Error while applying sync update",
|
|
1407
|
+
cause: err
|
|
1408
|
+
})
|
|
1409
|
+
})).pipe(require_const.flatMap(({ changes, protocolVersion }) => changes.length === 0 ? require_const._void : require_const.pipe(require_const.forEach(changes, (change) => require_const.pipe(this.#v1Context.transactionHistoryService.getTransactionDetails(change.source), require_const.flatMap((metadata) => this.#v1Context.transactionHistoryService.put(change, metadata, protocolVersion)), require_const.catchAllCause((cause) => require_watch.error("Error processing tx history metadata", cause))), {
|
|
1410
|
+
discard: true,
|
|
1411
|
+
concurrency: "unbounded"
|
|
1412
|
+
}), require_const.forkScoped)), require_const.provideService(require_const.Scope, this.#scope))), require_watch.tapError((error$1) => require_watch.error(error$1)), require_watch.retry(require_const.pipe(require_watch.exponential(require_const.seconds(1), 2), require_watch.map$1((delay) => {
|
|
1413
|
+
const maxDelay = require_const.minutes(2);
|
|
1414
|
+
const jitter = require_const.millis(Math.floor(Math.random() * 1e3));
|
|
1415
|
+
const delayWithJitter = require_const.toMillis(delay) + require_const.toMillis(jitter);
|
|
1416
|
+
return require_const.millis(Math.min(delayWithJitter, require_const.toMillis(maxDelay)));
|
|
1417
|
+
}))));
|
|
1418
|
+
}
|
|
1419
|
+
balanceTransaction(secretKeys, tx) {
|
|
1420
|
+
return require_watch.modifyEffect(this.#context.stateRef, (state) => {
|
|
1421
|
+
return require_const.pipe(this.#v1Context.transactingCapability.balanceTransaction(secretKeys, state, tx), require_watch.toEffect);
|
|
1422
|
+
});
|
|
1423
|
+
}
|
|
1424
|
+
transferTransaction(secretKeys, outputs) {
|
|
1425
|
+
return require_watch.modifyEffect(this.#context.stateRef, (state) => {
|
|
1426
|
+
return require_const.pipe(this.#v1Context.transactingCapability.makeTransfer(secretKeys, state, outputs), require_watch.toEffect);
|
|
1427
|
+
});
|
|
1428
|
+
}
|
|
1429
|
+
initSwap(secretKeys, desiredInputs, desiredOutputs) {
|
|
1430
|
+
return require_watch.modifyEffect(this.#context.stateRef, (state) => {
|
|
1431
|
+
return require_const.pipe(this.#v1Context.transactingCapability.initSwap(secretKeys, state, desiredInputs, desiredOutputs), require_watch.toEffect);
|
|
1432
|
+
});
|
|
1433
|
+
}
|
|
1434
|
+
revertTransaction(transaction) {
|
|
1435
|
+
return require_watch.updateEffect(this.#context.stateRef, (state) => {
|
|
1436
|
+
return require_const.pipe(this.#v1Context.transactingCapability.revertTransaction(state, transaction), require_watch.toEffect);
|
|
1437
|
+
});
|
|
1438
|
+
}
|
|
1439
|
+
serializeState(state) {
|
|
1440
|
+
return this.#v1Context.serializationCapability.serialize(state);
|
|
1441
|
+
}
|
|
1442
|
+
};
|
|
1443
|
+
//#endregion
|
|
1444
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-shielded/dist/v1/CoreWallet.js
|
|
1445
|
+
const PublicKeys = { fromSecretKeys: (secretKeys) => {
|
|
1446
|
+
return {
|
|
1447
|
+
coinPublicKey: secretKeys.coinPublicKey,
|
|
1448
|
+
encryptionPublicKey: secretKeys.encryptionPublicKey
|
|
1449
|
+
};
|
|
1450
|
+
} };
|
|
1451
|
+
const CoinHashesMap = {
|
|
1452
|
+
empty: {},
|
|
1453
|
+
pickAllCoins(state) {
|
|
1454
|
+
return [...state.coins, ...state.pendingOutputs.values().map(([coin]) => coin)];
|
|
1455
|
+
},
|
|
1456
|
+
assertValid(map, state) {
|
|
1457
|
+
const coins = CoinHashesMap.pickAllCoins(state);
|
|
1458
|
+
const coinNonces = new Set(require_const.map$7(coins, (coin) => coin.nonce));
|
|
1459
|
+
const definedNonces = new Set(Object.keys(map));
|
|
1460
|
+
const missingNonces = coinNonces.difference(definedNonces);
|
|
1461
|
+
return missingNonces.size === 0 ? require_const.void_$2 : require_const.left(missingNonces);
|
|
1462
|
+
},
|
|
1463
|
+
updateWithCoins(secretKeys, existing, coins) {
|
|
1464
|
+
return require_const.fromIterableWith(coins, (coin) => [coin.nonce, existing[coin.nonce] ?? {
|
|
1465
|
+
commitment: _midnight_ntwrk_ledger_v8.coinCommitment(coin, secretKeys.coinPublicKey),
|
|
1466
|
+
nullifier: _midnight_ntwrk_ledger_v8.coinNullifier(coin, secretKeys.coinSecretKey)
|
|
1467
|
+
}]);
|
|
1468
|
+
},
|
|
1469
|
+
updateWithNewCoins(secretKeys, existing, coins) {
|
|
1470
|
+
const newMap = CoinHashesMap.updateWithCoins(secretKeys, CoinHashesMap.empty, coins);
|
|
1471
|
+
return require_const.union$2(existing, newMap, (a) => a);
|
|
1472
|
+
},
|
|
1473
|
+
init(secretKeys, coins) {
|
|
1474
|
+
return CoinHashesMap.updateWithCoins(secretKeys, {}, coins);
|
|
1475
|
+
}
|
|
1476
|
+
};
|
|
1477
|
+
const CoreWallet = {
|
|
1478
|
+
init(localState, secretKeys, networkId) {
|
|
1479
|
+
return {
|
|
1480
|
+
state: localState,
|
|
1481
|
+
publicKeys: PublicKeys.fromSecretKeys(secretKeys),
|
|
1482
|
+
networkId,
|
|
1483
|
+
coinHashes: CoinHashesMap.init(secretKeys, CoinHashesMap.pickAllCoins(localState)),
|
|
1484
|
+
progress: require_const.createSyncProgress(),
|
|
1485
|
+
protocolVersion: require_const.MinSupportedVersion
|
|
1486
|
+
};
|
|
1487
|
+
},
|
|
1488
|
+
empty(publicKeys, networkId) {
|
|
1489
|
+
return {
|
|
1490
|
+
state: new _midnight_ntwrk_ledger_v8.ZswapLocalState(),
|
|
1491
|
+
publicKeys,
|
|
1492
|
+
networkId,
|
|
1493
|
+
coinHashes: CoinHashesMap.empty,
|
|
1494
|
+
progress: require_const.createSyncProgress(),
|
|
1495
|
+
protocolVersion: require_const.MinSupportedVersion
|
|
1496
|
+
};
|
|
1497
|
+
},
|
|
1498
|
+
restore(localState, secretKeys, syncProgress, protocolVersion, networkId) {
|
|
1499
|
+
return {
|
|
1500
|
+
state: localState,
|
|
1501
|
+
publicKeys: PublicKeys.fromSecretKeys(secretKeys),
|
|
1502
|
+
networkId,
|
|
1503
|
+
coinHashes: CoinHashesMap.init(secretKeys, CoinHashesMap.pickAllCoins(localState)),
|
|
1504
|
+
progress: require_const.createSyncProgress(syncProgress),
|
|
1505
|
+
protocolVersion: require_const.ProtocolVersion(protocolVersion)
|
|
1506
|
+
};
|
|
1507
|
+
},
|
|
1508
|
+
restoreWithCoinHashes(publicKeys, localState, coinHashes, syncProgress, protocolVersion, networkId) {
|
|
1509
|
+
return CoinHashesMap.assertValid(coinHashes, localState).pipe(require_const.mapBoth$3({
|
|
1510
|
+
onLeft: (missingNonces) => new InvalidCoinHashesError({
|
|
1511
|
+
message: "Missing coin hashes for coins present in the state",
|
|
1512
|
+
missingNonces
|
|
1513
|
+
}),
|
|
1514
|
+
onRight: () => ({
|
|
1515
|
+
state: localState,
|
|
1516
|
+
publicKeys,
|
|
1517
|
+
networkId,
|
|
1518
|
+
coinHashes,
|
|
1519
|
+
progress: require_const.createSyncProgress(syncProgress),
|
|
1520
|
+
protocolVersion: require_const.ProtocolVersion(protocolVersion)
|
|
1521
|
+
})
|
|
1522
|
+
}));
|
|
1523
|
+
},
|
|
1524
|
+
initEmpty(keys, networkId) {
|
|
1525
|
+
return this.empty(PublicKeys.fromSecretKeys(keys), networkId);
|
|
1526
|
+
},
|
|
1527
|
+
applyCollapsedUpdate(wallet, collapsed) {
|
|
1528
|
+
const newState = wallet.state.applyCollapsedUpdate(collapsed);
|
|
1529
|
+
return {
|
|
1530
|
+
...wallet,
|
|
1531
|
+
state: newState
|
|
1532
|
+
};
|
|
1533
|
+
},
|
|
1534
|
+
apply(wallet, secretKeys, offer) {
|
|
1535
|
+
const newState = wallet.state.apply(secretKeys, offer);
|
|
1536
|
+
const newCoinHashes = CoinHashesMap.updateWithCoins(secretKeys, wallet.coinHashes, CoinHashesMap.pickAllCoins(newState));
|
|
1537
|
+
return {
|
|
1538
|
+
...wallet,
|
|
1539
|
+
state: newState,
|
|
1540
|
+
coinHashes: newCoinHashes
|
|
1541
|
+
};
|
|
1542
|
+
},
|
|
1543
|
+
replayEventsWithChanges(wallet, secretKeys, events) {
|
|
1544
|
+
const stateWithChanges = wallet.state.replayEventsWithChanges(secretKeys, events);
|
|
1545
|
+
const newState = stateWithChanges.state;
|
|
1546
|
+
const newCoinHashes = CoinHashesMap.updateWithCoins(secretKeys, wallet.coinHashes, CoinHashesMap.pickAllCoins(newState));
|
|
1547
|
+
return [{
|
|
1548
|
+
...wallet,
|
|
1549
|
+
state: newState,
|
|
1550
|
+
coinHashes: newCoinHashes
|
|
1551
|
+
}, stateWithChanges.changes];
|
|
1552
|
+
},
|
|
1553
|
+
updateProgress(wallet, { appliedIndex, highestRelevantWalletIndex, highestIndex, highestRelevantIndex, isConnected }) {
|
|
1554
|
+
const updatedProgress = require_const.createSyncProgress({
|
|
1555
|
+
appliedIndex: appliedIndex ?? wallet.progress.appliedIndex,
|
|
1556
|
+
highestRelevantWalletIndex: highestRelevantWalletIndex ?? wallet.progress.highestRelevantWalletIndex,
|
|
1557
|
+
highestIndex: highestIndex ?? wallet.progress.highestIndex,
|
|
1558
|
+
highestRelevantIndex: highestRelevantIndex ?? wallet.progress.highestRelevantIndex,
|
|
1559
|
+
isConnected: isConnected ?? wallet.progress.isConnected
|
|
1560
|
+
});
|
|
1561
|
+
return {
|
|
1562
|
+
...wallet,
|
|
1563
|
+
progress: updatedProgress
|
|
1564
|
+
};
|
|
1565
|
+
},
|
|
1566
|
+
addTransaction(wallet, _tx) {
|
|
1567
|
+
return wallet;
|
|
1568
|
+
},
|
|
1569
|
+
revertTransaction(wallet, tx) {
|
|
1570
|
+
const newState = wallet.state.revertTransaction(tx);
|
|
1571
|
+
return {
|
|
1572
|
+
...wallet,
|
|
1573
|
+
state: newState
|
|
1574
|
+
};
|
|
1575
|
+
},
|
|
1576
|
+
updateTxHistory(wallet, _newTxs) {
|
|
1577
|
+
return wallet;
|
|
1578
|
+
},
|
|
1579
|
+
spendCoins(wallet, secretKeys, coins, segment) {
|
|
1580
|
+
const [offers, newLocalState] = require_const.pipe(coins, require_const.reduce$3([[], wallet.state], ([accOffers, localState], coinToSpend) => {
|
|
1581
|
+
const [nextState, newInput] = localState.spend(secretKeys, coinToSpend, segment);
|
|
1582
|
+
const inputOffer = _midnight_ntwrk_ledger_v8.ZswapOffer.fromInput(newInput, coinToSpend.type, coinToSpend.value);
|
|
1583
|
+
return [accOffers.concat([inputOffer]), nextState];
|
|
1584
|
+
}));
|
|
1585
|
+
return [offers, {
|
|
1586
|
+
...wallet,
|
|
1587
|
+
state: newLocalState
|
|
1588
|
+
}];
|
|
1589
|
+
},
|
|
1590
|
+
watchCoins(wallet, secretKeys, coins) {
|
|
1591
|
+
const newLocalState = coins.reduce((localState, coin) => localState.watchFor(wallet.publicKeys.coinPublicKey, coin), wallet.state);
|
|
1592
|
+
const newCoinHashes = CoinHashesMap.updateWithNewCoins(secretKeys, wallet.coinHashes, coins);
|
|
1593
|
+
return {
|
|
1594
|
+
...wallet,
|
|
1595
|
+
state: newLocalState,
|
|
1596
|
+
coinHashes: newCoinHashes
|
|
1597
|
+
};
|
|
1598
|
+
}
|
|
1599
|
+
};
|
|
1600
|
+
//#endregion
|
|
1601
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-shielded/dist/v1/Serialization.js
|
|
1602
|
+
const StateSchema = require_const.declare((input) => input instanceof _midnight_ntwrk_ledger_v8.ZswapLocalState).annotations({ identifier: "ledger.ZswapLocalState" });
|
|
1603
|
+
const Uint8ArraySchema$1 = require_const.declare((input) => input instanceof Uint8Array).annotations({ identifier: "Uint8Array" });
|
|
1604
|
+
const StateFromUInt8Array = () => require_const.asSchema(require_const.transformOrFail(Uint8ArraySchema$1, StateSchema, {
|
|
1605
|
+
encode: (state) => {
|
|
1606
|
+
return require_const.try_({
|
|
1607
|
+
try: () => {
|
|
1608
|
+
return state.serialize();
|
|
1609
|
+
},
|
|
1610
|
+
catch: (err) => {
|
|
1611
|
+
return new require_const.Unexpected(err, "Could not serialize local state");
|
|
1612
|
+
}
|
|
1613
|
+
});
|
|
1614
|
+
},
|
|
1615
|
+
decode: (bytes) => require_const.try_({
|
|
1616
|
+
try: () => _midnight_ntwrk_ledger_v8.ZswapLocalState.deserialize(bytes),
|
|
1617
|
+
catch: (err) => {
|
|
1618
|
+
return new require_const.Unexpected(err, "Could not deserialize local state");
|
|
1619
|
+
}
|
|
1620
|
+
})
|
|
1621
|
+
}));
|
|
1622
|
+
const HexedState = () => require_const.pipe(require_const.Uint8ArrayFromHex, require_const.compose(StateFromUInt8Array()));
|
|
1623
|
+
const makeDefaultV1SerializationCapability = () => {
|
|
1624
|
+
const SnapshotSchema = require_const.Struct({
|
|
1625
|
+
publicKeys: require_const.Struct({
|
|
1626
|
+
coinPublicKey: require_const.String$,
|
|
1627
|
+
encryptionPublicKey: require_const.String$
|
|
1628
|
+
}),
|
|
1629
|
+
state: HexedState(),
|
|
1630
|
+
protocolVersion: require_const.BigInt$,
|
|
1631
|
+
offset: require_const.optional(require_const.BigInt$),
|
|
1632
|
+
networkId: require_const.String$,
|
|
1633
|
+
coinHashes: require_const.Record({
|
|
1634
|
+
key: require_const.String$,
|
|
1635
|
+
value: require_const.Struct({
|
|
1636
|
+
nullifier: require_const.String$,
|
|
1637
|
+
commitment: require_const.String$
|
|
1638
|
+
})
|
|
1639
|
+
})
|
|
1640
|
+
});
|
|
1641
|
+
return {
|
|
1642
|
+
serialize: (wallet) => {
|
|
1643
|
+
const buildSnapshot = (w) => ({
|
|
1644
|
+
publicKeys: w.publicKeys,
|
|
1645
|
+
state: w.state,
|
|
1646
|
+
protocolVersion: w.protocolVersion,
|
|
1647
|
+
networkId: w.networkId,
|
|
1648
|
+
offset: w.progress?.appliedIndex,
|
|
1649
|
+
coinHashes: w.coinHashes
|
|
1650
|
+
});
|
|
1651
|
+
return require_const.pipe(wallet, buildSnapshot, require_const.encodeSync(SnapshotSchema), JSON.stringify);
|
|
1652
|
+
},
|
|
1653
|
+
deserialize: (aux, serialized) => {
|
|
1654
|
+
return require_const.pipe(serialized, require_const.decodeUnknownEither(require_const.parseJson(SnapshotSchema)), require_const.mapLeft((err) => WalletError.other(err)), require_const.flatMap$4((snapshot) => CoreWallet.restoreWithCoinHashes(snapshot.publicKeys, snapshot.state, snapshot.coinHashes, {
|
|
1655
|
+
appliedIndex: snapshot.offset ?? 0n,
|
|
1656
|
+
highestRelevantWalletIndex: 0n,
|
|
1657
|
+
highestIndex: 0n,
|
|
1658
|
+
highestRelevantIndex: 0n,
|
|
1659
|
+
isConnected: false
|
|
1660
|
+
}, snapshot.protocolVersion, snapshot.networkId)));
|
|
1661
|
+
}
|
|
1662
|
+
};
|
|
1663
|
+
};
|
|
1664
|
+
//#endregion
|
|
1665
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-shielded/dist/v1/Sync.js
|
|
1666
|
+
const Uint8ArraySchema = require_const.declare((input) => input instanceof Uint8Array).annotations({ identifier: "Uint8Array" });
|
|
1667
|
+
const WalletSyncUpdate = { create: (updates, secretKeys) => {
|
|
1668
|
+
return {
|
|
1669
|
+
updates,
|
|
1670
|
+
secretKeys
|
|
1671
|
+
};
|
|
1672
|
+
} };
|
|
1673
|
+
const LedgerEventSchema = require_const.declare((input) => input instanceof _midnight_ntwrk_ledger_v8.Event).annotations({ identifier: "ledger.Event" });
|
|
1674
|
+
const LedgerEventFromUint8Array = require_const.transformOrFail(Uint8ArraySchema, LedgerEventSchema, {
|
|
1675
|
+
encode: (event) => require_const.try_({
|
|
1676
|
+
try: () => event.serialize(),
|
|
1677
|
+
catch: (error) => new require_const.Unexpected(error, "Could not serialize ledger event")
|
|
1678
|
+
}),
|
|
1679
|
+
decode: (bytes) => require_const.try_({
|
|
1680
|
+
try: () => _midnight_ntwrk_ledger_v8.Event.deserialize(bytes),
|
|
1681
|
+
catch: (error) => new require_const.Unexpected(error, "Could not deserialize ledger event")
|
|
1682
|
+
})
|
|
1683
|
+
});
|
|
1684
|
+
const HexedLedgerEvent = require_const.pipe(require_const.Uint8ArrayFromHex, require_const.compose(LedgerEventFromUint8Array));
|
|
1685
|
+
const EventsSyncUpdatePayload = require_const.Struct({
|
|
1686
|
+
id: require_const.Number$,
|
|
1687
|
+
raw: require_const.String$,
|
|
1688
|
+
protocolVersion: require_const.Number$,
|
|
1689
|
+
maxId: require_const.Number$
|
|
1690
|
+
});
|
|
1691
|
+
const EventsSyncUpdate = require_const.TaggedStruct("EventsSyncUpdate", {
|
|
1692
|
+
id: require_const.Number$,
|
|
1693
|
+
protocolVersion: require_const.Number$,
|
|
1694
|
+
maxId: require_const.Number$,
|
|
1695
|
+
event: LedgerEventSchema
|
|
1696
|
+
});
|
|
1697
|
+
const EventsSyncUpdateFromPayload = require_const.transformOrFail(EventsSyncUpdatePayload, EventsSyncUpdate, {
|
|
1698
|
+
decode: (input) => require_const.pipe(require_const.decodeUnknownEither(HexedLedgerEvent)(input.raw), require_const.map$9((event) => ({
|
|
1699
|
+
_tag: "EventsSyncUpdate",
|
|
1700
|
+
id: input.id,
|
|
1701
|
+
protocolVersion: input.protocolVersion,
|
|
1702
|
+
maxId: input.maxId,
|
|
1703
|
+
event
|
|
1704
|
+
})), require_const.mapLeft((error) => new require_const.Unexpected(error, "Failed to decode ledger event payload")), require_watch.toEffect),
|
|
1705
|
+
encode: (output) => require_const.pipe(require_const.encodeEither(HexedLedgerEvent)(output.event), require_const.map$9((raw) => ({
|
|
1706
|
+
id: output.id,
|
|
1707
|
+
raw,
|
|
1708
|
+
protocolVersion: output.protocolVersion,
|
|
1709
|
+
maxId: output.maxId
|
|
1710
|
+
})), require_const.mapLeft((error) => new require_const.Unexpected(error, "Failed to encode ledger event payload")), require_watch.toEffect)
|
|
1711
|
+
});
|
|
1712
|
+
const makeEventsSyncService = (config) => {
|
|
1713
|
+
return { updates: (state, secretKeys) => {
|
|
1714
|
+
const { indexerClientConnection } = config;
|
|
1715
|
+
const webSocketUrlResult = require_watch.createWebSocketUrl(indexerClientConnection.indexerHttpUrl, indexerClientConnection.indexerWsUrl);
|
|
1716
|
+
if (require_const.isLeft(webSocketUrlResult)) return require_watch.fail(new SyncWalletError(/* @__PURE__ */ new Error(`Could not derive WebSocket URL from indexer HTTP URL: ${webSocketUrlResult.left.message}`)));
|
|
1717
|
+
const indexerWsUrlResult = require_watch.make(webSocketUrlResult.right);
|
|
1718
|
+
if (require_const.isLeft(indexerWsUrlResult)) return require_watch.fail(new SyncWalletError(/* @__PURE__ */ new Error(`Invalid indexer WS URL: ${indexerWsUrlResult.left.message}`)));
|
|
1719
|
+
const indexerWsUrl = indexerWsUrlResult.right;
|
|
1720
|
+
const resumeFrom = (state.progress?.appliedIndex ?? 0n) - 1n;
|
|
1721
|
+
const batchSize = config.batchUpdates?.size ?? 10;
|
|
1722
|
+
const batchTimeout = require_const.millis(config.batchUpdates?.timeout ?? 1);
|
|
1723
|
+
const batchSpacing = config.batchUpdates?.spacing ?? 4;
|
|
1724
|
+
const bufferSize = config.indexerClientConnection.bufferSize ?? 1e4;
|
|
1725
|
+
const resumeThreshold = config.indexerClientConnection.resumeThreshold ?? 100;
|
|
1726
|
+
const eventsStream = require_const.pipe(require_watch.ZswapEvents.runWithBackpressure({
|
|
1727
|
+
bufferSize,
|
|
1728
|
+
resumeThreshold,
|
|
1729
|
+
from: resumeFrom,
|
|
1730
|
+
variables: (cursor) => ({ id: cursor < 0n ? null : Number(cursor) }),
|
|
1731
|
+
key: (r) => BigInt(r.zswapLedgerEvents.id)
|
|
1732
|
+
}), require_watch.provideLayer(require_watch.layer({
|
|
1733
|
+
url: indexerWsUrl,
|
|
1734
|
+
keepAlive: config.indexerClientConnection.keepAlive
|
|
1735
|
+
})), require_watch.mapError((error) => new SyncWalletError(error)), require_watch.mapEffect((subscription) => require_const.pipe(subscription.zswapLedgerEvents, require_const.decodeUnknownEither(EventsSyncUpdateFromPayload), require_const.mapLeft((err) => new SyncWalletError(err)), require_watch.toEffect)), require_watch.groupedWithin(batchSize, batchTimeout), require_watch.map(require_const.toArray), require_watch.map((data) => WalletSyncUpdate.create(data, secretKeys)));
|
|
1736
|
+
return batchSpacing > 0 ? require_watch.schedule(eventsStream, require_watch.spaced(require_const.millis(batchSpacing))) : eventsStream;
|
|
1737
|
+
} };
|
|
1738
|
+
};
|
|
1739
|
+
const makeEventsSyncCapability = () => {
|
|
1740
|
+
return { applyUpdate: (state, wrappedUpdate) => {
|
|
1741
|
+
if (wrappedUpdate.updates.length === 0) return [state, {
|
|
1742
|
+
changes: [],
|
|
1743
|
+
protocolVersion: Number(state.protocolVersion)
|
|
1744
|
+
}];
|
|
1745
|
+
const appliedIndex = state.progress?.appliedIndex ?? 0n;
|
|
1746
|
+
const freshUpdates = wrappedUpdate.updates.filter((u) => BigInt(u.id) > appliedIndex);
|
|
1747
|
+
const lastUpdate = wrappedUpdate.updates.at(-1);
|
|
1748
|
+
const highestRelevantWalletIndex = BigInt(lastUpdate.maxId);
|
|
1749
|
+
const [newState, newChanges] = freshUpdates.length === 0 ? [state, []] : CoreWallet.replayEventsWithChanges(state, wrappedUpdate.secretKeys, freshUpdates.map((u) => u.event));
|
|
1750
|
+
return [CoreWallet.updateProgress(newState, {
|
|
1751
|
+
highestRelevantWalletIndex,
|
|
1752
|
+
appliedIndex: freshUpdates.length === 0 ? appliedIndex : BigInt(freshUpdates.at(-1).id),
|
|
1753
|
+
isConnected: true
|
|
1754
|
+
}), {
|
|
1755
|
+
changes: newChanges,
|
|
1756
|
+
protocolVersion: lastUpdate.protocolVersion
|
|
1757
|
+
}];
|
|
1758
|
+
} };
|
|
1759
|
+
};
|
|
1760
|
+
//#endregion
|
|
1761
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-shielded/dist/v1/TransactionImbalances.js
|
|
1762
|
+
const ShieldedCostModel = {
|
|
1763
|
+
inputFeeOverhead: 0n,
|
|
1764
|
+
outputFeeOverhead: 0n
|
|
1765
|
+
};
|
|
1766
|
+
const TransactionImbalances = new class {
|
|
1767
|
+
empty = () => {
|
|
1768
|
+
return {
|
|
1769
|
+
guaranteed: require_watch.Imbalances.empty(),
|
|
1770
|
+
fallible: /* @__PURE__ */ new Map()
|
|
1771
|
+
};
|
|
1772
|
+
};
|
|
1773
|
+
areBalanced = (imbalances) => {
|
|
1774
|
+
const areGuaranteedAllZeroes = imbalances.guaranteed.entries().every(([, value]) => value === 0n);
|
|
1775
|
+
const areFallibleAllZeroes = Array.from(imbalances.fallible.values()).every((segmentImbalances) => segmentImbalances.entries().every(([, value]) => value === 0n));
|
|
1776
|
+
return areGuaranteedAllZeroes && areFallibleAllZeroes;
|
|
1777
|
+
};
|
|
1778
|
+
}();
|
|
1779
|
+
//#endregion
|
|
1780
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-shielded/dist/v1/TransactionOps.js
|
|
1781
|
+
const TransactionOps = new class {
|
|
1782
|
+
default = {
|
|
1783
|
+
getImbalances(tx) {
|
|
1784
|
+
return TransactionOps.shared.getImbalances(tx);
|
|
1785
|
+
},
|
|
1786
|
+
id(tx) {
|
|
1787
|
+
return tx.identifiers().at(0);
|
|
1788
|
+
}
|
|
1789
|
+
};
|
|
1790
|
+
proofErased = {
|
|
1791
|
+
getImbalances(tx) {
|
|
1792
|
+
return TransactionOps.shared.getImbalances(tx);
|
|
1793
|
+
},
|
|
1794
|
+
id(tx) {
|
|
1795
|
+
return tx.identifiers().at(0);
|
|
1796
|
+
}
|
|
1797
|
+
};
|
|
1798
|
+
unproven = {
|
|
1799
|
+
getImbalances(tx) {
|
|
1800
|
+
return TransactionOps.shared.getImbalances(tx);
|
|
1801
|
+
},
|
|
1802
|
+
id(tx) {
|
|
1803
|
+
return tx.identifiers().at(0);
|
|
1804
|
+
}
|
|
1805
|
+
};
|
|
1806
|
+
shared = {
|
|
1807
|
+
getImbalances(tx) {
|
|
1808
|
+
return {
|
|
1809
|
+
guaranteed: TransactionOps.shared.getGuaranteedImbalances(tx),
|
|
1810
|
+
fallible: TransactionOps.shared.getFallibleImbalances(tx)
|
|
1811
|
+
};
|
|
1812
|
+
},
|
|
1813
|
+
getGuaranteedImbalances: (tx) => {
|
|
1814
|
+
const rawGuaranteedImbalances = tx.imbalances(0).entries().filter(([token]) => token.tag === "shielded").map(([token, value]) => {
|
|
1815
|
+
return [token.raw, value];
|
|
1816
|
+
});
|
|
1817
|
+
return require_watch.Imbalances.fromEntries(rawGuaranteedImbalances);
|
|
1818
|
+
},
|
|
1819
|
+
getFallibleImbalances: (tx) => {
|
|
1820
|
+
const fallibleImbalances = Array.from(tx.fallibleOffer?.keys() ?? []).flatMap((segment) => {
|
|
1821
|
+
const rawImbalances = tx.imbalances(segment).entries().filter(([token]) => token.tag === "shielded").map(([token, value]) => {
|
|
1822
|
+
return [token.raw, value];
|
|
1823
|
+
});
|
|
1824
|
+
return [[segment, require_watch.Imbalances.fromEntries(rawImbalances)]];
|
|
1825
|
+
});
|
|
1826
|
+
return new Map(fallibleImbalances);
|
|
1827
|
+
}
|
|
1828
|
+
};
|
|
1829
|
+
}();
|
|
1830
|
+
//#endregion
|
|
1831
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-shielded/dist/v1/Transacting.js
|
|
1832
|
+
const makeDefaultTransactingCapability = (config, getContext) => {
|
|
1833
|
+
return new TransactingCapabilityImplementation(config.networkId, () => getContext().coinSelection, () => getContext().coinsAndBalancesCapability, () => getContext().keysCapability, TransactionOps.default);
|
|
1834
|
+
};
|
|
1835
|
+
var TransactingCapabilityImplementation = class {
|
|
1836
|
+
networkId;
|
|
1837
|
+
getCoinSelection;
|
|
1838
|
+
txOps;
|
|
1839
|
+
getCoins;
|
|
1840
|
+
getKeys;
|
|
1841
|
+
constructor(networkId, getCoinSelection, getCoins, getKeys, txOps) {
|
|
1842
|
+
this.getCoins = getCoins;
|
|
1843
|
+
this.networkId = networkId;
|
|
1844
|
+
this.getCoinSelection = getCoinSelection;
|
|
1845
|
+
this.getKeys = getKeys;
|
|
1846
|
+
this.txOps = txOps;
|
|
1847
|
+
}
|
|
1848
|
+
balanceTransaction(secretKeys, state, tx) {
|
|
1849
|
+
return require_const.gen$1(this, function* () {
|
|
1850
|
+
const coinSelection = this.getCoinSelection();
|
|
1851
|
+
const initialImbalances = this.txOps.getImbalances(tx);
|
|
1852
|
+
if (TransactionImbalances.areBalanced(initialImbalances)) return [void 0, state];
|
|
1853
|
+
const { newState: afterFallible, fallibleOffers } = yield* this.balanceFallibleSection(secretKeys, state, initialImbalances, coinSelection);
|
|
1854
|
+
const { newState: afterGuaranteed, offer: guaranteed } = yield* this.#balanceGuaranteedSection(secretKeys, afterFallible, initialImbalances, coinSelection, require_watch.Imbalances.empty());
|
|
1855
|
+
return [Array.from(fallibleOffers.entries()).reduce((tx, [segment, offer]) => tx.addZswapOffer({
|
|
1856
|
+
tag: "specific",
|
|
1857
|
+
value: segment
|
|
1858
|
+
}, offer), _midnight_ntwrk_ledger_v8.Transaction.fromParts(this.networkId, guaranteed)), afterGuaranteed];
|
|
1859
|
+
});
|
|
1860
|
+
}
|
|
1861
|
+
makeTransfer(secretKeys, state, transfers) {
|
|
1862
|
+
return require_const.gen$1(this, function* () {
|
|
1863
|
+
const positiveTransfers = yield* require_const.pipe(transfers, require_const.filter$2((t) => t.amount > 0n), require_const.match$2({
|
|
1864
|
+
onEmpty: () => require_const.left(new OtherWalletError({ message: "The amount needs to be positive" })),
|
|
1865
|
+
onNonEmpty: (nonEmpty) => require_const.right(nonEmpty)
|
|
1866
|
+
}));
|
|
1867
|
+
const networkId = this.networkId;
|
|
1868
|
+
const { initialOffersAndCoins, selfCoins } = yield* this.#processDesiredOutputs(state, positiveTransfers);
|
|
1869
|
+
const offerToBalance = require_const.pipe(initialOffersAndCoins, require_const.map$6((o) => o.outputOffer), require_watch.fold((a, b) => a.merge(b)));
|
|
1870
|
+
const unprovenTxToBalance = _midnight_ntwrk_ledger_v8.Transaction.fromParts(networkId, offerToBalance);
|
|
1871
|
+
const imbalances = TransactionOps.unproven.getImbalances(unprovenTxToBalance);
|
|
1872
|
+
const { offer, newState } = yield* this.#balanceGuaranteedSection(secretKeys, state, imbalances, this.getCoinSelection(), require_watch.Imbalances.empty());
|
|
1873
|
+
const finalState = CoreWallet.watchCoins(newState, secretKeys, selfCoins);
|
|
1874
|
+
return [unprovenTxToBalance.merge(_midnight_ntwrk_ledger_v8.Transaction.fromParts(networkId, offer)), finalState];
|
|
1875
|
+
});
|
|
1876
|
+
}
|
|
1877
|
+
initSwap(secretKeys, state, desiredInputs, desiredOutputs) {
|
|
1878
|
+
return require_const.gen$1(this, function* () {
|
|
1879
|
+
if (!desiredOutputs.every((output) => output.amount > 0n)) return yield* require_const.left(new OtherWalletError({ message: "The amount needs to be positive" }));
|
|
1880
|
+
if (!Object.entries(desiredInputs).every(([, amount]) => amount > 0n)) return yield* require_const.left(new OtherWalletError({ message: "The input amounts need to be positive" }));
|
|
1881
|
+
const outputsParseResult = yield* this.#processDesiredOutputsPossiblyEmpty(state, desiredOutputs);
|
|
1882
|
+
const inputsParseResult = require_watch.Imbalances.fromEntries(require_const.toEntries(desiredInputs));
|
|
1883
|
+
const networkId = this.networkId;
|
|
1884
|
+
const { offer, newState } = yield* this.#balanceGuaranteedSection(secretKeys, state, TransactionImbalances.empty(), this.getCoinSelection(), inputsParseResult);
|
|
1885
|
+
const finalState = CoreWallet.watchCoins(newState, secretKeys, outputsParseResult.selfCoins);
|
|
1886
|
+
const balancingTx = _midnight_ntwrk_ledger_v8.Transaction.fromParts(networkId, offer);
|
|
1887
|
+
return [outputsParseResult.unprovenTxToBalance ? outputsParseResult.unprovenTxToBalance.merge(balancingTx) : balancingTx, finalState];
|
|
1888
|
+
});
|
|
1889
|
+
}
|
|
1890
|
+
revertTransaction(state, transaction) {
|
|
1891
|
+
return require_const.try_$1({
|
|
1892
|
+
try: () => {
|
|
1893
|
+
return CoreWallet.revertTransaction(state, transaction);
|
|
1894
|
+
},
|
|
1895
|
+
catch: (err) => {
|
|
1896
|
+
return new OtherWalletError({
|
|
1897
|
+
message: `Error while reverting transaction ${transaction.identifiers().at(0)}`,
|
|
1898
|
+
cause: err
|
|
1899
|
+
});
|
|
1900
|
+
}
|
|
1901
|
+
});
|
|
1902
|
+
}
|
|
1903
|
+
#prepareOffer(secretKeys, state, recipe, segment) {
|
|
1904
|
+
const [inputOffers, stateAfterSpends] = CoreWallet.spendCoins(state, secretKeys, recipe.inputs, segment);
|
|
1905
|
+
const stateAfterWatches = CoreWallet.watchCoins(stateAfterSpends, secretKeys, recipe.outputs);
|
|
1906
|
+
const outputOffers = recipe.outputs.map((coin) => {
|
|
1907
|
+
const output = _midnight_ntwrk_ledger_v8.ZswapOutput.new(coin, segment, this.getKeys().getCoinPublicKey(state).toHexString(), this.getKeys().getEncryptionPublicKey(state).toHexString());
|
|
1908
|
+
return _midnight_ntwrk_ledger_v8.ZswapOffer.fromOutput(output, coin.type, coin.value);
|
|
1909
|
+
});
|
|
1910
|
+
return require_const.pipe(require_const.appendAll$1(inputOffers, outputOffers), require_const.match$2({
|
|
1911
|
+
onEmpty: () => require_const.none(),
|
|
1912
|
+
onNonEmpty: (nonEmpty) => require_const.pipe(nonEmpty, require_watch.fold((a, b) => a.merge(b)), require_const.some)
|
|
1913
|
+
}), require_const.map$8((offer) => ({
|
|
1914
|
+
offer,
|
|
1915
|
+
newState: stateAfterWatches
|
|
1916
|
+
})));
|
|
1917
|
+
}
|
|
1918
|
+
balanceFallibleSection(secretKeys, state, imbalances, coinSelection) {
|
|
1919
|
+
return Array.from(imbalances.fallible.entries()).reduce((acc, [segment, segmentImbalances]) => require_const.flatMap$4(acc, ({ fallibleOffers, newState }) => require_const.pipe(require_const.try_$1({
|
|
1920
|
+
try: () => {
|
|
1921
|
+
const fallibleBalanceRecipe = require_watch.getBalanceRecipe({
|
|
1922
|
+
coins: this.getCoins().getAvailableCoins(newState).map((c) => c.coin),
|
|
1923
|
+
initialImbalances: segmentImbalances,
|
|
1924
|
+
transactionCostModel: ShieldedCostModel,
|
|
1925
|
+
feeTokenType: "",
|
|
1926
|
+
coinSelection,
|
|
1927
|
+
createOutput: (coin) => _midnight_ntwrk_ledger_v8.createShieldedCoinInfo(coin.type, coin.value),
|
|
1928
|
+
isCoinEqual: (a, b) => a.type === b.type && a.value === b.value
|
|
1929
|
+
});
|
|
1930
|
+
return this.#prepareOffer(secretKeys, newState, fallibleBalanceRecipe, segment);
|
|
1931
|
+
},
|
|
1932
|
+
catch: (err) => {
|
|
1933
|
+
if (err instanceof require_watch.InsufficientFundsError) return new InsufficientFundsError({
|
|
1934
|
+
message: `Insufficient funds for fallible segment ${segment}`,
|
|
1935
|
+
tokenType: err.tokenType,
|
|
1936
|
+
amount: segmentImbalances.get(err.tokenType) ?? 0n
|
|
1937
|
+
});
|
|
1938
|
+
return new OtherWalletError({
|
|
1939
|
+
message: `Balancing fallible segment ${segment} failed`,
|
|
1940
|
+
cause: err
|
|
1941
|
+
});
|
|
1942
|
+
}
|
|
1943
|
+
}), require_const.map$9(require_const.match$3({
|
|
1944
|
+
onNone: () => ({
|
|
1945
|
+
fallibleOffers,
|
|
1946
|
+
newState
|
|
1947
|
+
}),
|
|
1948
|
+
onSome: (res) => ({
|
|
1949
|
+
fallibleOffers: new Map([...fallibleOffers, [segment, res.offer]]),
|
|
1950
|
+
newState: res.newState
|
|
1951
|
+
})
|
|
1952
|
+
})))), require_const.right({
|
|
1953
|
+
fallibleOffers: /* @__PURE__ */ new Map(),
|
|
1954
|
+
newState: state
|
|
1955
|
+
}));
|
|
1956
|
+
}
|
|
1957
|
+
#balanceGuaranteedSection(secretKeys, state, imbalances, coinSelection, targetImbalances) {
|
|
1958
|
+
return require_const.gen$1(this, function* () {
|
|
1959
|
+
const balanceRecipe = yield* require_const.try_$1({
|
|
1960
|
+
try: () => require_watch.getBalanceRecipe({
|
|
1961
|
+
coins: this.getCoins().getAvailableCoins(state).map((c) => c.coin),
|
|
1962
|
+
initialImbalances: imbalances.guaranteed,
|
|
1963
|
+
transactionCostModel: ShieldedCostModel,
|
|
1964
|
+
feeTokenType: "",
|
|
1965
|
+
coinSelection,
|
|
1966
|
+
createOutput: (coin) => _midnight_ntwrk_ledger_v8.createShieldedCoinInfo(coin.type, coin.value),
|
|
1967
|
+
isCoinEqual: (a, b) => a.nonce === b.nonce,
|
|
1968
|
+
targetImbalances
|
|
1969
|
+
}),
|
|
1970
|
+
catch: (err) => {
|
|
1971
|
+
if (err instanceof require_watch.InsufficientFundsError) return new InsufficientFundsError({
|
|
1972
|
+
message: "Insufficient funds",
|
|
1973
|
+
tokenType: err.tokenType,
|
|
1974
|
+
amount: imbalances.guaranteed.get(err.tokenType) ?? 0n
|
|
1975
|
+
});
|
|
1976
|
+
else return new OtherWalletError({
|
|
1977
|
+
message: "Balancing guaranteed section failed",
|
|
1978
|
+
cause: err
|
|
1979
|
+
});
|
|
1980
|
+
}
|
|
1981
|
+
});
|
|
1982
|
+
return require_const.pipe(this.#prepareOffer(secretKeys, state, balanceRecipe, 0), require_const.match$3({
|
|
1983
|
+
onNone: () => ({
|
|
1984
|
+
offer: void 0,
|
|
1985
|
+
newState: state
|
|
1986
|
+
}),
|
|
1987
|
+
onSome: (result) => result
|
|
1988
|
+
}));
|
|
1989
|
+
});
|
|
1990
|
+
}
|
|
1991
|
+
#processDesiredOutputs(state, transfers) {
|
|
1992
|
+
return require_const.try_$1({
|
|
1993
|
+
try: () => {
|
|
1994
|
+
const initialOffersAndCoins = require_const.pipe(transfers, require_const.map$6((transfer) => {
|
|
1995
|
+
const { receiverAddress, type, amount } = transfer;
|
|
1996
|
+
const coin = _midnight_ntwrk_ledger_v8.createShieldedCoinInfo(type, amount);
|
|
1997
|
+
const output = _midnight_ntwrk_ledger_v8.ZswapOutput.new(coin, 0, receiverAddress.coinPublicKey.toHexString(), receiverAddress.encryptionPublicKey.toHexString());
|
|
1998
|
+
return {
|
|
1999
|
+
coin,
|
|
2000
|
+
outputOffer: _midnight_ntwrk_ledger_v8.ZswapOffer.fromOutput(output, type, amount),
|
|
2001
|
+
isForSelf: receiverAddress.coinPublicKey.equals(this.getKeys().getCoinPublicKey(state))
|
|
2002
|
+
};
|
|
2003
|
+
}));
|
|
2004
|
+
return {
|
|
2005
|
+
initialOffersAndCoins,
|
|
2006
|
+
selfCoins: require_const.flatMap$3(initialOffersAndCoins, ({ coin, isForSelf }) => {
|
|
2007
|
+
if (isForSelf) return [coin];
|
|
2008
|
+
else return [];
|
|
2009
|
+
})
|
|
2010
|
+
};
|
|
2011
|
+
},
|
|
2012
|
+
catch: (err) => {
|
|
2013
|
+
return new OtherWalletError({
|
|
2014
|
+
message: "Failed to process desired outputs",
|
|
2015
|
+
cause: err
|
|
2016
|
+
});
|
|
2017
|
+
}
|
|
2018
|
+
});
|
|
2019
|
+
}
|
|
2020
|
+
#processDesiredOutputsPossiblyEmpty(state, desiredOutputs) {
|
|
2021
|
+
return require_const.pipe(desiredOutputs, require_const.match$2({
|
|
2022
|
+
onEmpty: () => {
|
|
2023
|
+
return require_const.right({
|
|
2024
|
+
imbalances: TransactionImbalances.empty(),
|
|
2025
|
+
selfCoins: [],
|
|
2026
|
+
unprovenTxToBalance: null
|
|
2027
|
+
});
|
|
2028
|
+
},
|
|
2029
|
+
onNonEmpty: (desiredOutputs) => {
|
|
2030
|
+
return require_const.pipe(this.#processDesiredOutputs(state, desiredOutputs), require_const.map$9(({ initialOffersAndCoins, selfCoins }) => {
|
|
2031
|
+
const networkId = this.networkId;
|
|
2032
|
+
const offerToBalance = require_const.pipe(initialOffersAndCoins, require_const.map$6((o) => o.outputOffer), require_watch.fold((a, b) => a.merge(b)));
|
|
2033
|
+
const unprovenTxToBalance = _midnight_ntwrk_ledger_v8.Transaction.fromParts(networkId, offerToBalance);
|
|
2034
|
+
return {
|
|
2035
|
+
imbalances: TransactionOps.unproven.getImbalances(unprovenTxToBalance),
|
|
2036
|
+
selfCoins,
|
|
2037
|
+
unprovenTxToBalance
|
|
2038
|
+
};
|
|
2039
|
+
}));
|
|
2040
|
+
}
|
|
2041
|
+
}));
|
|
2042
|
+
}
|
|
2043
|
+
};
|
|
2044
|
+
//#endregion
|
|
2045
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-shielded/dist/v1/CoinsAndBalances.js
|
|
2046
|
+
const calculateBalances = (coins) => coins.reduce((acc, { coin }) => ({
|
|
2047
|
+
...acc,
|
|
2048
|
+
[coin.type]: acc[coin.type] === void 0 ? coin.value : acc[coin.type] + coin.value
|
|
2049
|
+
}), {});
|
|
2050
|
+
const makeDefaultCoinsAndBalancesCapability = () => {
|
|
2051
|
+
const getAvailableBalances = (state) => {
|
|
2052
|
+
return calculateBalances(getAvailableCoins(state));
|
|
2053
|
+
};
|
|
2054
|
+
const getPendingBalances = (state) => {
|
|
2055
|
+
return calculateBalances(getPendingCoins(state));
|
|
2056
|
+
};
|
|
2057
|
+
const getTotalBalances = (state) => {
|
|
2058
|
+
return require_const.pipe([getAvailableBalances(state), getPendingBalances(state)], require_watch.mergeWithAccumulator(0n, (a, b) => a + b));
|
|
2059
|
+
};
|
|
2060
|
+
const getAvailableCoins = (state) => {
|
|
2061
|
+
const pendingSpends = new Set([...state.state.pendingSpends.values()].map(([coin]) => coin.nonce));
|
|
2062
|
+
return require_const.pipe([...state.state.coins], require_const.filter$2((coin) => !pendingSpends.has(coin.nonce)), require_const.map$6((coin) => {
|
|
2063
|
+
return {
|
|
2064
|
+
coin,
|
|
2065
|
+
commitment: state.coinHashes[coin.nonce].commitment,
|
|
2066
|
+
nullifier: state.coinHashes[coin.nonce].nullifier
|
|
2067
|
+
};
|
|
2068
|
+
}));
|
|
2069
|
+
};
|
|
2070
|
+
const getPendingCoins = (state) => require_const.pipe([...state.state.pendingOutputs.values()], require_const.map$6(([coin, ttl]) => ({
|
|
2071
|
+
coin,
|
|
2072
|
+
ttl,
|
|
2073
|
+
commitment: state.coinHashes[coin.nonce].commitment,
|
|
2074
|
+
nullifier: state.coinHashes[coin.nonce].nullifier
|
|
2075
|
+
})));
|
|
2076
|
+
const getTotalCoins = (state) => [...getAvailableCoins(state), ...getPendingCoins(state)];
|
|
2077
|
+
return {
|
|
2078
|
+
getAvailableBalances,
|
|
2079
|
+
getPendingBalances,
|
|
2080
|
+
getTotalBalances,
|
|
2081
|
+
getAvailableCoins,
|
|
2082
|
+
getPendingCoins,
|
|
2083
|
+
getTotalCoins
|
|
2084
|
+
};
|
|
2085
|
+
};
|
|
2086
|
+
//#endregion
|
|
2087
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-shielded/dist/v1/Keys.js
|
|
2088
|
+
require__polyfill_buffer_patch.init__polyfill_buffer_patch();
|
|
2089
|
+
const makeDefaultKeysCapability = () => {
|
|
2090
|
+
return {
|
|
2091
|
+
getCoinPublicKey: (state) => {
|
|
2092
|
+
return new require_dist.ShieldedCoinPublicKey(require__polyfill_buffer_patch.import_buffer.Buffer.from(state.publicKeys.coinPublicKey, "hex"));
|
|
2093
|
+
},
|
|
2094
|
+
getEncryptionPublicKey: (state) => {
|
|
2095
|
+
return new require_dist.ShieldedEncryptionPublicKey(require__polyfill_buffer_patch.import_buffer.Buffer.from(state.publicKeys.encryptionPublicKey, "hex"));
|
|
2096
|
+
},
|
|
2097
|
+
getAddress: (state) => {
|
|
2098
|
+
return new require_dist.ShieldedAddress(new require_dist.ShieldedCoinPublicKey(require__polyfill_buffer_patch.import_buffer.Buffer.from(state.publicKeys.coinPublicKey, "hex")), new require_dist.ShieldedEncryptionPublicKey(require__polyfill_buffer_patch.import_buffer.Buffer.from(state.publicKeys.encryptionPublicKey, "hex")));
|
|
2099
|
+
}
|
|
2100
|
+
};
|
|
2101
|
+
};
|
|
2102
|
+
//#endregion
|
|
2103
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-shielded/dist/v1/TransactionHistory.js
|
|
2104
|
+
const QualifiedShieldedCoinInfoSchema = require_const.Struct({
|
|
2105
|
+
type: require_const.String$,
|
|
2106
|
+
nonce: require_const.String$,
|
|
2107
|
+
value: require_const.BigInt$,
|
|
2108
|
+
mtIndex: require_const.BigInt$
|
|
2109
|
+
});
|
|
2110
|
+
const ShieldedSectionSchema = require_const.Struct({
|
|
2111
|
+
receivedCoins: require_const.Array$(QualifiedShieldedCoinInfoSchema),
|
|
2112
|
+
spentCoins: require_const.Array$(QualifiedShieldedCoinInfoSchema)
|
|
2113
|
+
});
|
|
2114
|
+
require_const.Struct({
|
|
2115
|
+
hash: require_const.TransactionHashSchema,
|
|
2116
|
+
protocolVersion: require_const.Number$,
|
|
2117
|
+
status: require_const.TransactionHistoryStatusSchema,
|
|
2118
|
+
shielded: ShieldedSectionSchema
|
|
2119
|
+
});
|
|
2120
|
+
const coinEquals = require_const.equivalence(QualifiedShieldedCoinInfoSchema);
|
|
2121
|
+
const mergeShieldedSections = (existing, incoming) => ({
|
|
2122
|
+
receivedCoins: require_const.unionWith$1(existing.receivedCoins, incoming.receivedCoins, coinEquals),
|
|
2123
|
+
spentCoins: require_const.unionWith$1(existing.spentCoins, incoming.spentCoins, coinEquals)
|
|
2124
|
+
});
|
|
2125
|
+
const convertUpdateToStorageEntry = (changes, metadata, protocolVersion) => ({
|
|
2126
|
+
hash: changes.source,
|
|
2127
|
+
protocolVersion,
|
|
2128
|
+
status: metadata.status,
|
|
2129
|
+
shielded: {
|
|
2130
|
+
receivedCoins: changes.receivedCoins.map(({ mt_index, ...rest }) => ({
|
|
2131
|
+
...rest,
|
|
2132
|
+
mtIndex: mt_index
|
|
2133
|
+
})),
|
|
2134
|
+
spentCoins: changes.spentCoins.map(({ mt_index, ...rest }) => ({
|
|
2135
|
+
...rest,
|
|
2136
|
+
mtIndex: mt_index
|
|
2137
|
+
}))
|
|
2138
|
+
}
|
|
2139
|
+
});
|
|
2140
|
+
const upsertShieldedEntry = (txHistoryStorage, entry) => require_const.tryPromise({
|
|
2141
|
+
try: () => txHistoryStorage.upsert(entry),
|
|
2142
|
+
catch: (e) => new TransactionHistoryError({
|
|
2143
|
+
message: `Failed to upsert history entry for ${entry.hash}`,
|
|
2144
|
+
cause: e
|
|
2145
|
+
})
|
|
2146
|
+
});
|
|
2147
|
+
const makeDefaultTransactionHistoryService = (config, _getContext) => {
|
|
2148
|
+
const txHistoryStorage = config.txHistoryStorage;
|
|
2149
|
+
const queryClientLayer = require_watch.layer$1({ url: config.indexerClientConnection.indexerHttpUrl });
|
|
2150
|
+
return {
|
|
2151
|
+
put: (changes, metadata, protocolVersion) => {
|
|
2152
|
+
return upsertShieldedEntry(txHistoryStorage, convertUpdateToStorageEntry(changes, metadata, protocolVersion));
|
|
2153
|
+
},
|
|
2154
|
+
getTransactionDetails: (hash) => require_const.gen(function* () {
|
|
2155
|
+
const tx = (yield* (yield* require_watch.TransactionHistoryDetail)({ transactionHash: hash })).transactions[0];
|
|
2156
|
+
const rawStatus = tx.__typename === "RegularTransaction" ? tx.transactionResult.status : void 0;
|
|
2157
|
+
const status = rawStatus === "FAILURE" || rawStatus === "PARTIAL_SUCCESS" ? rawStatus : "SUCCESS";
|
|
2158
|
+
return {
|
|
2159
|
+
hash: tx.hash,
|
|
2160
|
+
timestamp: tx.block.timestamp,
|
|
2161
|
+
status
|
|
2162
|
+
};
|
|
2163
|
+
}).pipe(require_const.provide(queryClientLayer), require_const.scoped$1, require_const.retry(require_watch.exponential(require_const.seconds(1)).pipe(require_watch.compose(require_watch.recurs(3)))), require_const.mapError$1((cause) => new TransactionHistoryError({
|
|
2164
|
+
message: `Failed to fetch transaction metadata for ${hash}`,
|
|
2165
|
+
cause
|
|
2166
|
+
})))
|
|
2167
|
+
};
|
|
2168
|
+
};
|
|
2169
|
+
//#endregion
|
|
2170
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-shielded/dist/v1/V1Builder.js
|
|
2171
|
+
var V1Builder = class V1Builder {
|
|
2172
|
+
#buildState;
|
|
2173
|
+
constructor(buildState = {}) {
|
|
2174
|
+
this.#buildState = buildState;
|
|
2175
|
+
}
|
|
2176
|
+
withDefaults() {
|
|
2177
|
+
return this.withDefaultTransactionType().withSyncDefaults().withSerializationDefaults().withTransactingDefaults().withCoinsAndBalancesDefaults().withTransactionHistoryDefaults().withKeysDefaults().withCoinSelectionDefaults();
|
|
2178
|
+
}
|
|
2179
|
+
withTransactionType() {
|
|
2180
|
+
return new V1Builder({
|
|
2181
|
+
...this.#buildState,
|
|
2182
|
+
transactingCapability: void 0,
|
|
2183
|
+
transactionHistoryService: void 0
|
|
2184
|
+
});
|
|
2185
|
+
}
|
|
2186
|
+
withDefaultTransactionType() {
|
|
2187
|
+
return this.withTransactionType();
|
|
2188
|
+
}
|
|
2189
|
+
withSyncDefaults() {
|
|
2190
|
+
return this.withSync(makeEventsSyncService, makeEventsSyncCapability);
|
|
2191
|
+
}
|
|
2192
|
+
withSync(syncService, syncCapability) {
|
|
2193
|
+
return new V1Builder({
|
|
2194
|
+
...this.#buildState,
|
|
2195
|
+
syncService,
|
|
2196
|
+
syncCapability
|
|
2197
|
+
});
|
|
2198
|
+
}
|
|
2199
|
+
withSerializationDefaults() {
|
|
2200
|
+
return this.withSerialization(makeDefaultV1SerializationCapability);
|
|
2201
|
+
}
|
|
2202
|
+
withSerialization(serializationCapability) {
|
|
2203
|
+
return new V1Builder({
|
|
2204
|
+
...this.#buildState,
|
|
2205
|
+
serializationCapability
|
|
2206
|
+
});
|
|
2207
|
+
}
|
|
2208
|
+
withTransactingDefaults() {
|
|
2209
|
+
return this.withTransacting(makeDefaultTransactingCapability);
|
|
2210
|
+
}
|
|
2211
|
+
withTransacting(transactingCapability) {
|
|
2212
|
+
return new V1Builder({
|
|
2213
|
+
...this.#buildState,
|
|
2214
|
+
transactingCapability
|
|
2215
|
+
});
|
|
2216
|
+
}
|
|
2217
|
+
withCoinSelection(coinSelection) {
|
|
2218
|
+
return new V1Builder({
|
|
2219
|
+
...this.#buildState,
|
|
2220
|
+
coinSelection
|
|
2221
|
+
});
|
|
2222
|
+
}
|
|
2223
|
+
withCoinSelectionDefaults() {
|
|
2224
|
+
return this.withCoinSelection(() => require_watch.chooseCoin);
|
|
2225
|
+
}
|
|
2226
|
+
withCoinsAndBalancesDefaults() {
|
|
2227
|
+
return this.withCoinsAndBalances(makeDefaultCoinsAndBalancesCapability);
|
|
2228
|
+
}
|
|
2229
|
+
withCoinsAndBalances(coinsAndBalancesCapability) {
|
|
2230
|
+
return new V1Builder({
|
|
2231
|
+
...this.#buildState,
|
|
2232
|
+
coinsAndBalancesCapability
|
|
2233
|
+
});
|
|
2234
|
+
}
|
|
2235
|
+
withTransactionHistoryDefaults() {
|
|
2236
|
+
return this.withTransactionHistory(makeDefaultTransactionHistoryService);
|
|
2237
|
+
}
|
|
2238
|
+
withTransactionHistory(transactionHistoryService) {
|
|
2239
|
+
return new V1Builder({
|
|
2240
|
+
...this.#buildState,
|
|
2241
|
+
transactionHistoryService
|
|
2242
|
+
});
|
|
2243
|
+
}
|
|
2244
|
+
withKeysDefaults() {
|
|
2245
|
+
return this.withKeys(makeDefaultKeysCapability);
|
|
2246
|
+
}
|
|
2247
|
+
withKeys(keysCapability) {
|
|
2248
|
+
return new V1Builder({
|
|
2249
|
+
...this.#buildState,
|
|
2250
|
+
keysCapability
|
|
2251
|
+
});
|
|
2252
|
+
}
|
|
2253
|
+
build(configuration) {
|
|
2254
|
+
const v1Context = this.#buildContextFromBuildState(configuration);
|
|
2255
|
+
const { networkId } = configuration;
|
|
2256
|
+
return {
|
|
2257
|
+
__polyTag__: V1Tag,
|
|
2258
|
+
coinsAndBalances: v1Context.coinsAndBalancesCapability,
|
|
2259
|
+
keys: v1Context.keysCapability,
|
|
2260
|
+
serialization: v1Context.serializationCapability,
|
|
2261
|
+
transactionHistory: v1Context.transactionHistoryService,
|
|
2262
|
+
start(context) {
|
|
2263
|
+
return require_const.gen(function* () {
|
|
2264
|
+
return new RunningV1Variant(yield* require_const.Scope, context, v1Context);
|
|
2265
|
+
});
|
|
2266
|
+
},
|
|
2267
|
+
migrateState(_previousState) {
|
|
2268
|
+
const seed = require_const.fromString("0000000000000000000000000000000000000000000000000000000000000001");
|
|
2269
|
+
return require_const.succeed(CoreWallet.empty(PublicKeys.fromSecretKeys(_midnight_ntwrk_ledger_v8.ZswapSecretKeys.fromSeed(seed)), networkId));
|
|
2270
|
+
},
|
|
2271
|
+
deserializeState: (serialized) => {
|
|
2272
|
+
return v1Context.serializationCapability.deserialize(null, serialized);
|
|
2273
|
+
}
|
|
2274
|
+
};
|
|
2275
|
+
}
|
|
2276
|
+
#buildContextFromBuildState(configuration) {
|
|
2277
|
+
if (!isBuildStateFull(this.#buildState)) throw new Error("Not all components are configured in V1 Builder");
|
|
2278
|
+
const { syncCapability, syncService, transactingCapability, serializationCapability, coinSelection, coinsAndBalancesCapability, keysCapability, transactionHistoryService } = this.#buildState;
|
|
2279
|
+
const getContext = () => context;
|
|
2280
|
+
const context = {
|
|
2281
|
+
serializationCapability: serializationCapability(configuration, getContext),
|
|
2282
|
+
syncCapability: syncCapability(configuration, getContext),
|
|
2283
|
+
syncService: syncService(configuration, getContext),
|
|
2284
|
+
transactingCapability: transactingCapability(configuration, getContext),
|
|
2285
|
+
coinsAndBalancesCapability: coinsAndBalancesCapability(configuration, getContext),
|
|
2286
|
+
keysCapability: keysCapability(configuration, getContext),
|
|
2287
|
+
coinSelection: coinSelection(configuration, getContext),
|
|
2288
|
+
transactionHistoryService: transactionHistoryService(configuration, getContext)
|
|
2289
|
+
};
|
|
2290
|
+
return context;
|
|
2291
|
+
}
|
|
2292
|
+
};
|
|
2293
|
+
const isBuildStateFull = (buildState) => {
|
|
2294
|
+
return [
|
|
2295
|
+
"syncService",
|
|
2296
|
+
"syncCapability",
|
|
2297
|
+
"transactingCapability",
|
|
2298
|
+
"coinSelection",
|
|
2299
|
+
"serializationCapability",
|
|
2300
|
+
"coinsAndBalancesCapability",
|
|
2301
|
+
"keysCapability",
|
|
2302
|
+
"transactionHistoryService"
|
|
2303
|
+
].every((key) => typeof buildState[key] == "function");
|
|
2304
|
+
};
|
|
2305
|
+
//#endregion
|
|
2306
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-shielded/dist/ShieldedWallet.js
|
|
2307
|
+
var ShieldedWalletState = class ShieldedWalletState {
|
|
2308
|
+
static mapState = (variant) => (state) => {
|
|
2309
|
+
const { serialization, coinsAndBalances, keys } = variant;
|
|
2310
|
+
const { transactionHistory } = variant;
|
|
2311
|
+
return new ShieldedWalletState(state, {
|
|
2312
|
+
serialization,
|
|
2313
|
+
coinsAndBalances,
|
|
2314
|
+
keys
|
|
2315
|
+
}, { transactionHistory });
|
|
2316
|
+
};
|
|
2317
|
+
protocolVersion;
|
|
2318
|
+
state;
|
|
2319
|
+
capabilities;
|
|
2320
|
+
services;
|
|
2321
|
+
get balances() {
|
|
2322
|
+
return this.capabilities.coinsAndBalances.getAvailableBalances(this.state);
|
|
2323
|
+
}
|
|
2324
|
+
get totalCoins() {
|
|
2325
|
+
return this.capabilities.coinsAndBalances.getTotalCoins(this.state);
|
|
2326
|
+
}
|
|
2327
|
+
get availableCoins() {
|
|
2328
|
+
return this.capabilities.coinsAndBalances.getAvailableCoins(this.state);
|
|
2329
|
+
}
|
|
2330
|
+
get pendingCoins() {
|
|
2331
|
+
return this.capabilities.coinsAndBalances.getPendingCoins(this.state);
|
|
2332
|
+
}
|
|
2333
|
+
get coinPublicKey() {
|
|
2334
|
+
return this.capabilities.keys.getCoinPublicKey(this.state);
|
|
2335
|
+
}
|
|
2336
|
+
get encryptionPublicKey() {
|
|
2337
|
+
return this.capabilities.keys.getEncryptionPublicKey(this.state);
|
|
2338
|
+
}
|
|
2339
|
+
get address() {
|
|
2340
|
+
return this.capabilities.keys.getAddress(this.state);
|
|
2341
|
+
}
|
|
2342
|
+
get progress() {
|
|
2343
|
+
return this.state.progress;
|
|
2344
|
+
}
|
|
2345
|
+
constructor(state, capabilities, services) {
|
|
2346
|
+
this.protocolVersion = state.version;
|
|
2347
|
+
this.state = state.state;
|
|
2348
|
+
this.capabilities = capabilities;
|
|
2349
|
+
this.services = services;
|
|
2350
|
+
}
|
|
2351
|
+
serialize() {
|
|
2352
|
+
return this.capabilities.serialization.serialize(this.state);
|
|
2353
|
+
}
|
|
2354
|
+
};
|
|
2355
|
+
function ShieldedWallet(configuration) {
|
|
2356
|
+
return CustomShieldedWallet(configuration, new V1Builder().withDefaults());
|
|
2357
|
+
}
|
|
2358
|
+
function CustomShieldedWallet(configuration, builder) {
|
|
2359
|
+
const buildArgs = [configuration];
|
|
2360
|
+
const BaseWallet = require_watch.WalletBuilder.init().withVariant(require_const.MinSupportedVersion, builder).build(...buildArgs);
|
|
2361
|
+
return class CustomShieldedWalletImplementation extends BaseWallet {
|
|
2362
|
+
static startWithSecretKeys(secretKeys) {
|
|
2363
|
+
return CustomShieldedWalletImplementation.startFirst(CustomShieldedWalletImplementation, CoreWallet.initEmpty(secretKeys, CustomShieldedWalletImplementation.configuration.networkId));
|
|
2364
|
+
}
|
|
2365
|
+
static startWithSeed(seed) {
|
|
2366
|
+
const secretKeys = _midnight_ntwrk_ledger_v8.ZswapSecretKeys.fromSeed(seed);
|
|
2367
|
+
return CustomShieldedWalletImplementation.startWithSecretKeys(secretKeys);
|
|
2368
|
+
}
|
|
2369
|
+
static restore(serializedState) {
|
|
2370
|
+
const deserialized = CustomShieldedWalletImplementation.allVariantsRecord()[V1Tag].variant.deserializeState(serializedState).pipe(require_const.getOrThrow$1);
|
|
2371
|
+
return CustomShieldedWalletImplementation.startFirst(CustomShieldedWalletImplementation, deserialized);
|
|
2372
|
+
}
|
|
2373
|
+
state;
|
|
2374
|
+
constructor(runtime, scope) {
|
|
2375
|
+
super(runtime, scope);
|
|
2376
|
+
this.state = this.rawState.pipe(rxjs.map(ShieldedWalletState.mapState(CustomShieldedWalletImplementation.allVariantsRecord()[V1Tag].variant)), rxjs.shareReplay({
|
|
2377
|
+
refCount: true,
|
|
2378
|
+
bufferSize: 1
|
|
2379
|
+
}));
|
|
2380
|
+
}
|
|
2381
|
+
start(secretKeys) {
|
|
2382
|
+
return this.runtime.dispatch({ [V1Tag]: (v1) => v1.startSyncInBackground(secretKeys) }).pipe(require_const.runPromise);
|
|
2383
|
+
}
|
|
2384
|
+
balanceTransaction(secretKeys, tx) {
|
|
2385
|
+
return this.runtime.dispatch({ [V1Tag]: (v1) => v1.balanceTransaction(secretKeys, tx) }).pipe(require_const.runPromise);
|
|
2386
|
+
}
|
|
2387
|
+
transferTransaction(secretKeys, outputs) {
|
|
2388
|
+
return this.runtime.dispatch({ [V1Tag]: (v1) => v1.transferTransaction(secretKeys, outputs) }).pipe(require_const.runPromise);
|
|
2389
|
+
}
|
|
2390
|
+
initSwap(secretKeys, desiredInputs, desiredOutputs) {
|
|
2391
|
+
return this.runtime.dispatch({ [V1Tag]: (v1) => v1.initSwap(secretKeys, desiredInputs, desiredOutputs) }).pipe(require_const.runPromise);
|
|
2392
|
+
}
|
|
2393
|
+
revertTransaction(transaction) {
|
|
2394
|
+
return this.runtime.dispatch({ [V1Tag]: (v1) => v1.revertTransaction(transaction) }).pipe(require_const.runPromise);
|
|
2395
|
+
}
|
|
2396
|
+
waitForSyncedState(allowedGap = 0n) {
|
|
2397
|
+
return rxjs.firstValueFrom(this.state.pipe(rxjs.filter((state) => state.state.progress.isCompleteWithin(allowedGap))));
|
|
2398
|
+
}
|
|
2399
|
+
/**
|
|
2400
|
+
* Serializes the most recent state It's preferable to use [[ShieldedWalletState.serialize]] instead, to know
|
|
2401
|
+
* exactly, which state is serialized
|
|
2402
|
+
*/
|
|
2403
|
+
serializeState() {
|
|
2404
|
+
return rxjs.firstValueFrom(this.state).then((state) => state.serialize());
|
|
2405
|
+
}
|
|
2406
|
+
getAddress() {
|
|
2407
|
+
return rxjs.firstValueFrom(this.state).then((state) => state.address);
|
|
2408
|
+
}
|
|
2409
|
+
};
|
|
2410
|
+
}
|
|
2411
|
+
//#endregion
|
|
2412
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-facade/dist/transaction.js
|
|
2413
|
+
const finalizedTransactionTrait = {
|
|
2414
|
+
areAllTxIdsIncluded(tx, txIds) {
|
|
2415
|
+
const txIdsSet = require_const.fromIterable$1(tx.identifiers());
|
|
2416
|
+
const expectedIdSet = require_const.fromIterable$1(txIds);
|
|
2417
|
+
return require_const.isSubset(txIdsSet, expectedIdSet);
|
|
2418
|
+
},
|
|
2419
|
+
deserialize(serialized) {
|
|
2420
|
+
return _midnight_ntwrk_ledger_v8.Transaction.deserialize("signature", "proof", "binding", serialized);
|
|
2421
|
+
},
|
|
2422
|
+
firstId(tx) {
|
|
2423
|
+
return tx.identifiers()[0];
|
|
2424
|
+
},
|
|
2425
|
+
hasTTLExpired(tx, creationTime, now) {
|
|
2426
|
+
const defaultShieldedGracePeriod = _midnight_ntwrk_ledger_v8.LedgerParameters.initialParameters().dust.dustGracePeriodSeconds;
|
|
2427
|
+
const intentTTLs = require_const.pipe(tx.intents?.values().toArray() ?? [], require_const.map$6((i) => i.ttl), require_const.filterMap$1(require_const.make));
|
|
2428
|
+
const hasDustPayments = require_const.pipe(tx.intents?.values().toArray() ?? [], require_const.flatMap$3((i) => i.dustActions?.spends ?? []), require_const.isNonEmptyArray);
|
|
2429
|
+
const hasShieldedOffers = tx.guaranteedOffer != null || (tx.fallibleOffer?.size ?? 0) == 0;
|
|
2430
|
+
const maybeShieldedTTL = hasDustPayments || hasShieldedOffers ? require_const.pipe(creationTime, require_const.addDuration(require_const.seconds(Number(defaultShieldedGracePeriod))), require_const.of$2) : require_const.empty$3();
|
|
2431
|
+
return require_const.pipe(intentTTLs, require_const.appendAll$1(maybeShieldedTTL), (arr) => require_const.isNonEmptyReadonlyArray(arr) ? require_const.some(require_const.min(arr, require_const.mapInput$1(require_const.Date, require_const.toDate))) : require_const.none(), require_const.match$3({
|
|
2432
|
+
onNone: () => false,
|
|
2433
|
+
onSome: (finalTTL) => require_const.distance(finalTTL, now) > 0
|
|
2434
|
+
}));
|
|
2435
|
+
},
|
|
2436
|
+
ids(tx) {
|
|
2437
|
+
return tx.identifiers();
|
|
2438
|
+
},
|
|
2439
|
+
isOneIncludedInOther(tx, otherTx) {
|
|
2440
|
+
const txIds = require_const.fromIterable$1(tx.identifiers());
|
|
2441
|
+
const otherTxIds = require_const.fromIterable$1(otherTx.identifiers());
|
|
2442
|
+
const smallerSize = require_const.min$1(require_const.number)(require_const.size(txIds), require_const.size(otherTxIds));
|
|
2443
|
+
const intersection$1 = require_const.intersection(txIds, otherTxIds);
|
|
2444
|
+
return require_const.size(intersection$1) == smallerSize;
|
|
2445
|
+
},
|
|
2446
|
+
isTx(tx) {
|
|
2447
|
+
return tx instanceof _midnight_ntwrk_ledger_v8.Transaction;
|
|
2448
|
+
},
|
|
2449
|
+
serialize(tx) {
|
|
2450
|
+
return tx.serialize();
|
|
2451
|
+
}
|
|
2452
|
+
};
|
|
2453
|
+
//#endregion
|
|
2454
|
+
//#region ../../node_modules/@midnightntwrk/wallet-sdk-facade/dist/index.js
|
|
2455
|
+
/**
|
|
2456
|
+
* Full entry schema for transaction history — common fields + all wallet sections. Pass this to
|
|
2457
|
+
* `InMemoryTransactionHistoryStorage` to enable serialize/restore.
|
|
2458
|
+
*/
|
|
2459
|
+
const WalletEntrySchema = require_const.Struct({
|
|
2460
|
+
...require_const.TransactionHistoryCommonSchema.fields,
|
|
2461
|
+
shielded: require_const.optional(ShieldedSectionSchema),
|
|
2462
|
+
unshielded: require_const.optional(require_watch.UnshieldedSectionSchema),
|
|
2463
|
+
dust: require_const.optional(DustSectionSchema)
|
|
2464
|
+
});
|
|
2465
|
+
const mergeWalletEntries = (existing, incoming) => ({
|
|
2466
|
+
...existing,
|
|
2467
|
+
...incoming,
|
|
2468
|
+
...existing.shielded !== void 0 && incoming.shielded !== void 0 ? { shielded: mergeShieldedSections(existing.shielded, incoming.shielded) } : {},
|
|
2469
|
+
...existing.unshielded !== void 0 && incoming.unshielded !== void 0 ? { unshielded: {
|
|
2470
|
+
...existing.unshielded,
|
|
2471
|
+
...incoming.unshielded
|
|
2472
|
+
} } : {},
|
|
2473
|
+
...existing.dust !== void 0 && incoming.dust !== void 0 ? { dust: mergeDustSections(existing.dust, incoming.dust) } : {}
|
|
2474
|
+
});
|
|
2475
|
+
const isWalletEntry = require_const.is(WalletEntrySchema);
|
|
2476
|
+
const TokenKindsToBalance = new class {
|
|
2477
|
+
allTokenKinds = [
|
|
2478
|
+
"shielded",
|
|
2479
|
+
"unshielded",
|
|
2480
|
+
"dust"
|
|
2481
|
+
];
|
|
2482
|
+
toFlags = (tokenKinds) => {
|
|
2483
|
+
return require_const.pipe(tokenKinds, (kinds) => kinds === "all" ? this.allTokenKinds : kinds, (kinds) => ({
|
|
2484
|
+
shouldBalanceUnshielded: kinds.includes("unshielded"),
|
|
2485
|
+
shouldBalanceShielded: kinds.includes("shielded"),
|
|
2486
|
+
shouldBalanceDust: kinds.includes("dust")
|
|
2487
|
+
}));
|
|
2488
|
+
};
|
|
2489
|
+
}();
|
|
2490
|
+
const BalancingRecipe = {
|
|
2491
|
+
isRecipe: (value) => {
|
|
2492
|
+
return typeof value === "object" && value !== null && "type" in value && typeof value.type === "string" && [
|
|
2493
|
+
"FINALIZED_TRANSACTION",
|
|
2494
|
+
"UNBOUND_TRANSACTION",
|
|
2495
|
+
"UNPROVEN_TRANSACTION"
|
|
2496
|
+
].includes(value.type);
|
|
2497
|
+
},
|
|
2498
|
+
getTransactions: (recipe) => {
|
|
2499
|
+
switch (recipe.type) {
|
|
2500
|
+
case "FINALIZED_TRANSACTION": return [recipe.originalTransaction, recipe.balancingTransaction];
|
|
2501
|
+
case "UNBOUND_TRANSACTION": {
|
|
2502
|
+
const balancingPart = recipe.balancingTransaction ? [recipe.balancingTransaction] : [];
|
|
2503
|
+
return [recipe.baseTransaction, ...balancingPart];
|
|
2504
|
+
}
|
|
2505
|
+
case "UNPROVEN_TRANSACTION": return [recipe.transaction];
|
|
2506
|
+
}
|
|
2507
|
+
}
|
|
2508
|
+
};
|
|
2509
|
+
var FacadeState = class {
|
|
2510
|
+
shielded;
|
|
2511
|
+
unshielded;
|
|
2512
|
+
dust;
|
|
2513
|
+
pending;
|
|
2514
|
+
get isSynced() {
|
|
2515
|
+
return this.shielded.state.progress.isStrictlyComplete() && this.dust.state.progress.isStrictlyComplete() && this.unshielded.progress.isStrictlyComplete();
|
|
2516
|
+
}
|
|
2517
|
+
constructor(shielded, unshielded, dust, pending) {
|
|
2518
|
+
this.shielded = shielded;
|
|
2519
|
+
this.unshielded = unshielded;
|
|
2520
|
+
this.dust = dust;
|
|
2521
|
+
this.pending = pending;
|
|
2522
|
+
}
|
|
2523
|
+
};
|
|
2524
|
+
const DEFAULT_TTL_MS = 3600 * 1e3;
|
|
2525
|
+
var WalletFacade = class WalletFacade {
|
|
2526
|
+
static makeDefaultSubmissionService(config) {
|
|
2527
|
+
return require_watch.makeDefaultSubmissionService(config);
|
|
2528
|
+
}
|
|
2529
|
+
static makeDefaultPendingTransactionsService(config) {
|
|
2530
|
+
return require_watch.PendingTransactionsServiceImpl.init({
|
|
2531
|
+
configuration: config,
|
|
2532
|
+
txTrait: finalizedTransactionTrait
|
|
2533
|
+
});
|
|
2534
|
+
}
|
|
2535
|
+
static makeDefaultProvingService(config) {
|
|
2536
|
+
if (config.provingServerUrl) return require_watch.makeDefaultProvingService({ provingServerUrl: config.provingServerUrl });
|
|
2537
|
+
else throw new Error("Missing required configuration: 'provingServerUrl' must be set in config, or provide a custom provingService in init parameters.");
|
|
2538
|
+
}
|
|
2539
|
+
/**
|
|
2540
|
+
* Fetches the current Terms and Conditions from the network indexer.
|
|
2541
|
+
*
|
|
2542
|
+
* This is a static, pre-initialization utility — no wallet instance is required. Wallet builders should call this
|
|
2543
|
+
* before or independently of wallet initialization to display the current T&C to end users and obtain the hash for
|
|
2544
|
+
* content verification.
|
|
2545
|
+
*
|
|
2546
|
+
* The returned `hash` is the hex-encoded SHA-256 hash of the document at `url`. Wallet builders are responsible for
|
|
2547
|
+
* fetching and rendering the document content via `url` in whatever manner suits their application.
|
|
2548
|
+
*
|
|
2549
|
+
* @param configuration - An object with an `indexerClientConnection.indexerHttpUrl`. Any wallet configuration that
|
|
2550
|
+
* satisfies {@link FetchTermsAndConditionsConfiguration} can be passed directly.
|
|
2551
|
+
* @returns A promise resolving to the current {@link TermsAndConditions}, or rejecting if no Terms and Conditions have
|
|
2552
|
+
* been set on the network yet.
|
|
2553
|
+
*/
|
|
2554
|
+
static async fetchTermsAndConditions(configuration) {
|
|
2555
|
+
const tc = (await require_watch.runPromise(require_watch.FetchTermsAndConditions, {}, { url: configuration.indexerClientConnection.indexerHttpUrl })).block?.systemParameters?.termsAndConditions;
|
|
2556
|
+
if (!tc) throw new Error("Terms and Conditions are not currently set on the network.");
|
|
2557
|
+
return tc;
|
|
2558
|
+
}
|
|
2559
|
+
/**
|
|
2560
|
+
* Default initialization for {@link WalletFacade}. It is a static method, which takes an object holding configuration
|
|
2561
|
+
* and initialization of necessary components. Specifically - it requires following fields:
|
|
2562
|
+
*
|
|
2563
|
+
* - `configuration` - holding a configuration, which needs to extend {@link DefaultConfiguration} - this way allows to
|
|
2564
|
+
* convey use-case-specific settings in the same way, as the SDK works by default
|
|
2565
|
+
* - `shielded` - a function taking the configuration and returning shielded wallet (or a promise with such)
|
|
2566
|
+
* implementing {@link ShieldedWalletAPI}
|
|
2567
|
+
* - `unshielded` - a function taking the configuration and returning unshielded wallet (or a promise with such)
|
|
2568
|
+
* implementing {@link UnshieldedWalletAPI}
|
|
2569
|
+
* - `dust` - a function taking the configuration and returning Dust wallet (or a promise with such) implementing
|
|
2570
|
+
* {@link DustWalletAPI} There are some optional services/abstractions to provide, too. If not provided - default
|
|
2571
|
+
* implementations will be used, each of them is initialized by a function taking the configuration and returning
|
|
2572
|
+
* proper implementation (wrapped in a {@link Promise} or not).
|
|
2573
|
+
* - `submissionService` - needs to implement {@link SubmissionService} for a {@link ledger.FinalizedTransaction} to
|
|
2574
|
+
* submit transactions to the network, default uses Node RPC connection
|
|
2575
|
+
* - `pendingTransactionsService` - needs to implement {@link PendingTransactionsService} for a
|
|
2576
|
+
* {@link ledger.FinalizedTransaction} to keep track of pending transactions, default uses in-memory implementation
|
|
2577
|
+
* - `provingService` - needs to implement {@link ProvingService} to prove it, default uses proving server
|
|
2578
|
+
* - `clock` - needs to implement {@link Clock.Clock} for getting current time, default uses system clock
|
|
2579
|
+
*/
|
|
2580
|
+
static async init(initParams) {
|
|
2581
|
+
const submissionService = await Promise.resolve(initParams.submissionService ? initParams.submissionService(initParams.configuration) : WalletFacade.makeDefaultSubmissionService(initParams.configuration));
|
|
2582
|
+
const pendingTransactionsService = await Promise.resolve(initParams.pendingTransactionsService ? initParams.pendingTransactionsService(initParams.configuration) : WalletFacade.makeDefaultPendingTransactionsService(initParams.configuration));
|
|
2583
|
+
const provingService = await Promise.resolve(initParams.provingService ? initParams.provingService(initParams.configuration) : WalletFacade.makeDefaultProvingService(initParams.configuration));
|
|
2584
|
+
const shielded = await Promise.resolve(initParams.shielded(initParams.configuration));
|
|
2585
|
+
const unshielded = await Promise.resolve(initParams.unshielded(initParams.configuration));
|
|
2586
|
+
const dust = await Promise.resolve(initParams.dust(initParams.configuration));
|
|
2587
|
+
const clock = await Promise.resolve(initParams.clock ? initParams.clock(initParams.configuration) : require_watch.systemClock);
|
|
2588
|
+
return new WalletFacade(shielded, unshielded, dust, submissionService, pendingTransactionsService, provingService, initParams.configuration.txHistoryStorage, clock);
|
|
2589
|
+
}
|
|
2590
|
+
shielded;
|
|
2591
|
+
unshielded;
|
|
2592
|
+
dust;
|
|
2593
|
+
submissionService;
|
|
2594
|
+
pendingTransactionsService;
|
|
2595
|
+
provingService;
|
|
2596
|
+
#txHistoryStorage;
|
|
2597
|
+
clock;
|
|
2598
|
+
#pendingSubscription;
|
|
2599
|
+
/**
|
|
2600
|
+
* Constructor is private on purpose - much of initialization of the facade is potentially asynchronous, and adding
|
|
2601
|
+
* new parameters is a breaking change to the users Use {@link WalletFacade.init} instead
|
|
2602
|
+
*
|
|
2603
|
+
* @private
|
|
2604
|
+
*/
|
|
2605
|
+
constructor(shieldedWallet, unshieldedWallet, dustWallet, submissionService, pendingTransactionsService, provingService, txHistoryStorage, clock = require_watch.systemClock) {
|
|
2606
|
+
this.shielded = shieldedWallet;
|
|
2607
|
+
this.unshielded = unshieldedWallet;
|
|
2608
|
+
this.dust = dustWallet;
|
|
2609
|
+
this.submissionService = submissionService;
|
|
2610
|
+
this.pendingTransactionsService = pendingTransactionsService;
|
|
2611
|
+
this.provingService = provingService;
|
|
2612
|
+
this.#txHistoryStorage = txHistoryStorage;
|
|
2613
|
+
this.clock = clock;
|
|
2614
|
+
this.#pendingSubscription = this.pendingTransactionsService.state().pipe((0, rxjs.concatMap)((pending) => require_watch.allFailed(pending)), (0, rxjs.concatMap)((item) => this.revert(item.tx))).subscribe();
|
|
2615
|
+
}
|
|
2616
|
+
defaultTtl() {
|
|
2617
|
+
return new Date(this.clock.now().getTime() + DEFAULT_TTL_MS);
|
|
2618
|
+
}
|
|
2619
|
+
mergeUnprovenTransactions(a, b) {
|
|
2620
|
+
if (a && b) return a.merge(b);
|
|
2621
|
+
return a ?? b;
|
|
2622
|
+
}
|
|
2623
|
+
async createDustActionTransaction(action, nightUtxos, nightVerifyingKey, signDustRegistration) {
|
|
2624
|
+
const ttl = this.defaultTtl();
|
|
2625
|
+
const now = this.clock.now();
|
|
2626
|
+
const isRegistration = action.type === "registration";
|
|
2627
|
+
const dustReceiverAddress = isRegistration ? action.dustReceiverAddress : void 0;
|
|
2628
|
+
const split = await this.dust.splitNightUtxosForDustRegistration(now, nightUtxos.map(({ utxo, meta }) => ({
|
|
2629
|
+
...utxo,
|
|
2630
|
+
ctime: meta.ctime,
|
|
2631
|
+
registeredForDustGeneration: meta.registeredForDustGeneration
|
|
2632
|
+
})), isRegistration);
|
|
2633
|
+
const toUnshieldedUtxoWithMeta = (u) => ({
|
|
2634
|
+
utxo: {
|
|
2635
|
+
value: u.utxo.value,
|
|
2636
|
+
type: u.utxo.type,
|
|
2637
|
+
owner: u.utxo.owner,
|
|
2638
|
+
intentHash: u.utxo.intentHash,
|
|
2639
|
+
outputNo: u.utxo.outputNo
|
|
2640
|
+
},
|
|
2641
|
+
meta: {
|
|
2642
|
+
ctime: u.utxo.ctime,
|
|
2643
|
+
registeredForDustGeneration: u.utxo.registeredForDustGeneration
|
|
2644
|
+
}
|
|
2645
|
+
});
|
|
2646
|
+
const guaranteedForUnshielded = split.guaranteedUtxos.map(toUnshieldedUtxoWithMeta);
|
|
2647
|
+
const fallibleForUnshielded = split.fallibleUtxos.map(toUnshieldedUtxoWithMeta);
|
|
2648
|
+
const txWithOffers = await this.unshielded.rotateUtxos(guaranteedForUnshielded, fallibleForUnshielded, nightVerifyingKey, ttl);
|
|
2649
|
+
let txWithDustActions;
|
|
2650
|
+
try {
|
|
2651
|
+
txWithDustActions = await this.dust.attachDustRegistration(txWithOffers, now, nightVerifyingKey, dustReceiverAddress, split.feePayment);
|
|
2652
|
+
} catch (error) {
|
|
2653
|
+
await this.unshielded.revertTransaction(txWithOffers);
|
|
2654
|
+
throw error;
|
|
2655
|
+
}
|
|
2656
|
+
const hasUnregisteredGuaranteed = split.guaranteedUtxos.some((u) => !u.utxo.registeredForDustGeneration);
|
|
2657
|
+
if (isRegistration && hasUnregisteredGuaranteed) {
|
|
2658
|
+
const fee = await this.dust.calculateFee([txWithDustActions]);
|
|
2659
|
+
if (split.feePayment < fee) {
|
|
2660
|
+
await this.unshielded.revertTransaction(txWithOffers);
|
|
2661
|
+
throw Error(`Insufficient generated dust to cover registration fee (have ${split.feePayment}, need ${fee}). Use WalletFacade.waitForGeneratedDust(utxos, ${fee}) before retrying.`);
|
|
2662
|
+
}
|
|
2663
|
+
}
|
|
2664
|
+
try {
|
|
2665
|
+
const signedRecipe = await this.signRecipe({
|
|
2666
|
+
type: "UNPROVEN_TRANSACTION",
|
|
2667
|
+
transaction: txWithDustActions
|
|
2668
|
+
}, signDustRegistration);
|
|
2669
|
+
if (signedRecipe.type !== "UNPROVEN_TRANSACTION") throw Error("signRecipe returned unexpected recipe type for dust action transaction.");
|
|
2670
|
+
return signedRecipe.transaction;
|
|
2671
|
+
} catch (error) {
|
|
2672
|
+
await this.unshielded.revertTransaction(txWithOffers);
|
|
2673
|
+
throw error;
|
|
2674
|
+
}
|
|
2675
|
+
}
|
|
2676
|
+
state() {
|
|
2677
|
+
return (0, rxjs.combineLatest)([
|
|
2678
|
+
this.shielded.state,
|
|
2679
|
+
this.unshielded.state,
|
|
2680
|
+
this.dust.state,
|
|
2681
|
+
this.pendingTransactionsService.state()
|
|
2682
|
+
]).pipe((0, rxjs.map)(([shieldedState, unshieldedState, dustState, pending]) => new FacadeState(shieldedState, unshieldedState, dustState, pending)));
|
|
2683
|
+
}
|
|
2684
|
+
async waitForSyncedState() {
|
|
2685
|
+
const [shieldedState, unshieldedState, dustState, pending] = await Promise.all([
|
|
2686
|
+
this.shielded.waitForSyncedState(),
|
|
2687
|
+
this.unshielded.waitForSyncedState(),
|
|
2688
|
+
this.dust.waitForSyncedState(),
|
|
2689
|
+
(0, rxjs.firstValueFrom)(this.pendingTransactionsService.state())
|
|
2690
|
+
]);
|
|
2691
|
+
return new FacadeState(shieldedState, unshieldedState, dustState, pending);
|
|
2692
|
+
}
|
|
2693
|
+
async submitTransaction(tx) {
|
|
2694
|
+
try {
|
|
2695
|
+
await this.pendingTransactionsService.addPendingTransaction(tx);
|
|
2696
|
+
await this.submissionService.submitTransaction(tx, "Finalized");
|
|
2697
|
+
return tx.identifiers().at(-1);
|
|
2698
|
+
} catch (error) {
|
|
2699
|
+
await this.revert(tx);
|
|
2700
|
+
throw error;
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2703
|
+
async balanceFinalizedTransaction(tx, secretKeys, options) {
|
|
2704
|
+
const { shieldedSecretKeys, dustSecretKey } = secretKeys;
|
|
2705
|
+
const { ttl, tokenKindsToBalance = "all" } = options;
|
|
2706
|
+
const { shouldBalanceDust, shouldBalanceShielded, shouldBalanceUnshielded } = TokenKindsToBalance.toFlags(tokenKindsToBalance);
|
|
2707
|
+
const unshieldedBalancingTx = shouldBalanceUnshielded ? await this.unshielded.balanceFinalizedTransaction(tx) : void 0;
|
|
2708
|
+
const shieldedBalancingTx = shouldBalanceShielded ? await this.shielded.balanceTransaction(shieldedSecretKeys, tx) : void 0;
|
|
2709
|
+
const mergedBalancingTx = this.mergeUnprovenTransactions(shieldedBalancingTx, unshieldedBalancingTx);
|
|
2710
|
+
const feeBalancingTx = shouldBalanceDust ? await this.dust.balanceTransactions(dustSecretKey, mergedBalancingTx ? [tx, mergedBalancingTx] : [tx], ttl) : void 0;
|
|
2711
|
+
const balancingTx = this.mergeUnprovenTransactions(mergedBalancingTx, feeBalancingTx);
|
|
2712
|
+
if (!balancingTx) throw new Error("No balancing transaction was created. Please check your transaction.");
|
|
2713
|
+
return {
|
|
2714
|
+
type: "FINALIZED_TRANSACTION",
|
|
2715
|
+
originalTransaction: tx,
|
|
2716
|
+
balancingTransaction: balancingTx
|
|
2717
|
+
};
|
|
2718
|
+
}
|
|
2719
|
+
async balanceUnboundTransaction(tx, secretKeys, options) {
|
|
2720
|
+
const { shieldedSecretKeys, dustSecretKey } = secretKeys;
|
|
2721
|
+
const { ttl, tokenKindsToBalance = "all" } = options;
|
|
2722
|
+
const { shouldBalanceDust, shouldBalanceShielded, shouldBalanceUnshielded } = TokenKindsToBalance.toFlags(tokenKindsToBalance);
|
|
2723
|
+
const shieldedBalancingTx = shouldBalanceShielded ? await this.shielded.balanceTransaction(shieldedSecretKeys, tx) : void 0;
|
|
2724
|
+
const balancedUnshieldedTx = shouldBalanceUnshielded ? await this.unshielded.balanceUnboundTransaction(tx) : void 0;
|
|
2725
|
+
const baseTx = balancedUnshieldedTx ?? tx;
|
|
2726
|
+
const feeBalancingTransaction = shouldBalanceDust ? await this.dust.balanceTransactions(dustSecretKey, shieldedBalancingTx ? [baseTx, shieldedBalancingTx] : [baseTx], ttl) : void 0;
|
|
2727
|
+
const balancingTransaction = this.mergeUnprovenTransactions(shieldedBalancingTx, feeBalancingTransaction);
|
|
2728
|
+
if (!balancingTransaction && !balancedUnshieldedTx) throw new Error("No balancing transaction was created. Please check your transaction.");
|
|
2729
|
+
return {
|
|
2730
|
+
type: "UNBOUND_TRANSACTION",
|
|
2731
|
+
baseTransaction: baseTx,
|
|
2732
|
+
balancingTransaction: balancingTransaction ?? void 0
|
|
2733
|
+
};
|
|
2734
|
+
}
|
|
2735
|
+
async balanceUnprovenTransaction(tx, secretKeys, options) {
|
|
2736
|
+
const { shieldedSecretKeys, dustSecretKey } = secretKeys;
|
|
2737
|
+
const { ttl, tokenKindsToBalance = "all" } = options;
|
|
2738
|
+
const { shouldBalanceDust, shouldBalanceShielded, shouldBalanceUnshielded } = TokenKindsToBalance.toFlags(tokenKindsToBalance);
|
|
2739
|
+
const shieldedBalancingTx = shouldBalanceShielded ? await this.shielded.balanceTransaction(shieldedSecretKeys, tx) : void 0;
|
|
2740
|
+
const baseTx = (shouldBalanceUnshielded ? await this.unshielded.balanceUnprovenTransaction(tx) : void 0) ?? tx;
|
|
2741
|
+
const mergedTx = this.mergeUnprovenTransactions(baseTx, shieldedBalancingTx);
|
|
2742
|
+
const feeBalancingTx = shouldBalanceDust ? await this.dust.balanceTransactions(dustSecretKey, [mergedTx], ttl) : void 0;
|
|
2743
|
+
return {
|
|
2744
|
+
type: "UNPROVEN_TRANSACTION",
|
|
2745
|
+
transaction: this.mergeUnprovenTransactions(mergedTx, feeBalancingTx)
|
|
2746
|
+
};
|
|
2747
|
+
}
|
|
2748
|
+
async finalizeRecipe(recipe) {
|
|
2749
|
+
return Promise.resolve(recipe).then(async (recipe) => {
|
|
2750
|
+
switch (recipe.type) {
|
|
2751
|
+
case "FINALIZED_TRANSACTION": {
|
|
2752
|
+
const finalizedBalancing = await this.finalizeTransaction(recipe.balancingTransaction);
|
|
2753
|
+
return recipe.originalTransaction.merge(finalizedBalancing);
|
|
2754
|
+
}
|
|
2755
|
+
case "UNBOUND_TRANSACTION": {
|
|
2756
|
+
const finalizedBalancingTx = recipe.balancingTransaction ? await this.finalizeTransaction(recipe.balancingTransaction) : void 0;
|
|
2757
|
+
const finalizedTransaction = recipe.baseTransaction.bind();
|
|
2758
|
+
return finalizedBalancingTx ? finalizedTransaction.merge(finalizedBalancingTx) : finalizedTransaction;
|
|
2759
|
+
}
|
|
2760
|
+
case "UNPROVEN_TRANSACTION": return await this.finalizeTransaction(recipe.transaction);
|
|
2761
|
+
}
|
|
2762
|
+
}).then(async (finalizedTx) => {
|
|
2763
|
+
await this.pendingTransactionsService.addPendingTransaction(finalizedTx);
|
|
2764
|
+
return finalizedTx;
|
|
2765
|
+
});
|
|
2766
|
+
}
|
|
2767
|
+
async signRecipe(recipe, signSegment) {
|
|
2768
|
+
switch (recipe.type) {
|
|
2769
|
+
case "FINALIZED_TRANSACTION": {
|
|
2770
|
+
const signedBalancingTx = await this.signUnprovenTransaction(recipe.balancingTransaction, signSegment);
|
|
2771
|
+
const withDustSig = await this.#signDustRegistrationIfPresent(signedBalancingTx, signSegment);
|
|
2772
|
+
return {
|
|
2773
|
+
type: "FINALIZED_TRANSACTION",
|
|
2774
|
+
originalTransaction: recipe.originalTransaction,
|
|
2775
|
+
balancingTransaction: withDustSig
|
|
2776
|
+
};
|
|
2777
|
+
}
|
|
2778
|
+
case "UNBOUND_TRANSACTION": {
|
|
2779
|
+
const signedBalancingTx = recipe.balancingTransaction ? await this.signUnprovenTransaction(recipe.balancingTransaction, signSegment).then((tx) => this.#signDustRegistrationIfPresent(tx, signSegment)) : void 0;
|
|
2780
|
+
return {
|
|
2781
|
+
type: "UNBOUND_TRANSACTION",
|
|
2782
|
+
baseTransaction: await this.signUnboundTransaction(recipe.baseTransaction, signSegment),
|
|
2783
|
+
balancingTransaction: signedBalancingTx
|
|
2784
|
+
};
|
|
2785
|
+
}
|
|
2786
|
+
case "UNPROVEN_TRANSACTION": {
|
|
2787
|
+
const signedTx = await this.signUnprovenTransaction(recipe.transaction, signSegment);
|
|
2788
|
+
return {
|
|
2789
|
+
type: "UNPROVEN_TRANSACTION",
|
|
2790
|
+
transaction: await this.#signDustRegistrationIfPresent(signedTx, signSegment)
|
|
2791
|
+
};
|
|
2792
|
+
}
|
|
2793
|
+
}
|
|
2794
|
+
}
|
|
2795
|
+
async #signDustRegistrationIfPresent(tx, signSegment) {
|
|
2796
|
+
const intent = tx.intents?.get(1);
|
|
2797
|
+
const registrations = intent?.dustActions?.registrations ?? [];
|
|
2798
|
+
if (!intent || registrations.length === 0) return tx;
|
|
2799
|
+
const signature = signSegment(intent.signatureData(1));
|
|
2800
|
+
return await this.dust.addDustRegistrationSignature(tx, signature);
|
|
2801
|
+
}
|
|
2802
|
+
async signUnprovenTransaction(tx, signSegment) {
|
|
2803
|
+
return await this.unshielded.signUnprovenTransaction(tx, signSegment);
|
|
2804
|
+
}
|
|
2805
|
+
async signUnboundTransaction(tx, signSegment) {
|
|
2806
|
+
return await this.unshielded.signUnboundTransaction(tx, signSegment);
|
|
2807
|
+
}
|
|
2808
|
+
async finalizeTransaction(tx) {
|
|
2809
|
+
try {
|
|
2810
|
+
const finalizedTx = (await this.provingService.prove(tx)).bind();
|
|
2811
|
+
await this.pendingTransactionsService.addPendingTransaction(finalizedTx);
|
|
2812
|
+
return finalizedTx;
|
|
2813
|
+
} catch (error) {
|
|
2814
|
+
await Promise.allSettled([
|
|
2815
|
+
this.shielded.revertTransaction(tx),
|
|
2816
|
+
this.unshielded.revertTransaction(tx),
|
|
2817
|
+
this.dust.revertTransaction(tx)
|
|
2818
|
+
]);
|
|
2819
|
+
throw error;
|
|
2820
|
+
}
|
|
2821
|
+
}
|
|
2822
|
+
/** Estimates the fee for the given transaction only. This lacks the fees of the balancing transaction. */
|
|
2823
|
+
async calculateTransactionFee(tx) {
|
|
2824
|
+
return await this.dust.calculateFee([tx]);
|
|
2825
|
+
}
|
|
2826
|
+
/** Calculates the total fee for the given transaction plus the fee of the balancing transaction. */
|
|
2827
|
+
async estimateTransactionFee(tx, secretKey, options) {
|
|
2828
|
+
const ttl = options?.ttl ?? this.defaultTtl();
|
|
2829
|
+
return await this.dust.estimateFee(secretKey, [tx], ttl, options?.currentTime);
|
|
2830
|
+
}
|
|
2831
|
+
async transferTransaction(outputs, secretKeys, options) {
|
|
2832
|
+
const { shieldedSecretKeys, dustSecretKey } = secretKeys;
|
|
2833
|
+
const { ttl, payFees = true } = options;
|
|
2834
|
+
const unshieldedOutputs = outputs.filter((output) => output.type === "unshielded").flatMap((output) => output.outputs);
|
|
2835
|
+
const shieldedOutputs = outputs.filter((output) => output.type === "shielded").flatMap((output) => output.outputs);
|
|
2836
|
+
if (unshieldedOutputs.length === 0 && shieldedOutputs.length === 0) throw Error("At least one shielded or unshielded output is required.");
|
|
2837
|
+
const shieldedTx = shieldedOutputs.length > 0 ? await this.shielded.transferTransaction(shieldedSecretKeys, shieldedOutputs) : void 0;
|
|
2838
|
+
const unshieldedTx = unshieldedOutputs.length > 0 ? await this.unshielded.transferTransaction(unshieldedOutputs, ttl) : void 0;
|
|
2839
|
+
const mergedTxs = this.mergeUnprovenTransactions(shieldedTx, unshieldedTx);
|
|
2840
|
+
const feeBalancingTx = payFees ? await this.dust.balanceTransactions(dustSecretKey, [mergedTxs], ttl) : void 0;
|
|
2841
|
+
return {
|
|
2842
|
+
type: "UNPROVEN_TRANSACTION",
|
|
2843
|
+
transaction: this.mergeUnprovenTransactions(mergedTxs, feeBalancingTx)
|
|
2844
|
+
};
|
|
2845
|
+
}
|
|
2846
|
+
/**
|
|
2847
|
+
* Provides estimate of the fee of issuing registration transaction with provided UTxOs
|
|
2848
|
+
*
|
|
2849
|
+
* @param nightUtxos - Night UTxOs to use for the registration
|
|
2850
|
+
* @returns And object informing about fee at the moment, as well as estimation of dust generation of the UTxO(s),
|
|
2851
|
+
* that would be used for paying the fee. These include data that allows to compute when the fee could be paid
|
|
2852
|
+
*/
|
|
2853
|
+
async estimateRegistration(nightUtxos) {
|
|
2854
|
+
const now = this.clock.now();
|
|
2855
|
+
const dustState = await this.dust.waitForSyncedState();
|
|
2856
|
+
const dustGenerationEstimations = require_const.pipe(nightUtxos, require_const.map$6(({ utxo, meta }) => ({
|
|
2857
|
+
...utxo,
|
|
2858
|
+
ctime: meta.ctime,
|
|
2859
|
+
registeredForDustGeneration: meta.registeredForDustGeneration
|
|
2860
|
+
})), (utxosWithMeta) => dustState.estimateDustGeneration(utxosWithMeta, now), (estimatedUtxos) => dustState.capabilities.coinsAndBalances.splitNightUtxos(estimatedUtxos), (split) => split.guaranteed);
|
|
2861
|
+
const fakeSigningKey = _midnight_ntwrk_ledger_v8.sampleSigningKey();
|
|
2862
|
+
const fakeVerifyingKey = _midnight_ntwrk_ledger_v8.signatureVerifyingKey(fakeSigningKey);
|
|
2863
|
+
const ttl = this.defaultTtl();
|
|
2864
|
+
const fakeUnsignedTx = await this.dust.createDustGenerationTransaction(void 0, ttl, nightUtxos.map(({ utxo, meta }) => ({
|
|
2865
|
+
...utxo,
|
|
2866
|
+
ctime: meta.ctime,
|
|
2867
|
+
registeredForDustGeneration: meta.registeredForDustGeneration
|
|
2868
|
+
})), fakeVerifyingKey, dustState.address);
|
|
2869
|
+
const intent = fakeUnsignedTx.intents?.get(1);
|
|
2870
|
+
if (!intent) throw Error("Dust generation transaction is missing intent segment 1.");
|
|
2871
|
+
const signatureData = intent.signatureData(1);
|
|
2872
|
+
const signature = _midnight_ntwrk_ledger_v8.signData(fakeSigningKey, signatureData);
|
|
2873
|
+
const finalizedFakeTx = (await this.dust.addDustGenerationSignature(fakeUnsignedTx, signature)).mockProve().bind();
|
|
2874
|
+
return {
|
|
2875
|
+
fee: await this.calculateTransactionFee(finalizedFakeTx),
|
|
2876
|
+
dustGenerationEstimations
|
|
2877
|
+
};
|
|
2878
|
+
}
|
|
2879
|
+
async initSwap(desiredInputs, desiredOutputs, secretKeys, options) {
|
|
2880
|
+
const { shieldedSecretKeys, dustSecretKey } = secretKeys;
|
|
2881
|
+
const { ttl, payFees = false } = options;
|
|
2882
|
+
const { shielded: shieldedInputs, unshielded: unshieldedInputs } = desiredInputs;
|
|
2883
|
+
const shieldedOutputs = desiredOutputs.filter((output) => output.type === "shielded").flatMap((output) => output.outputs);
|
|
2884
|
+
const unshieldedOutputs = desiredOutputs.filter((output) => output.type === "unshielded").flatMap((output) => output.outputs);
|
|
2885
|
+
const hasShieldedPart = shieldedInputs && Object.keys(shieldedInputs).length > 0 || shieldedOutputs.length > 0;
|
|
2886
|
+
const hasUnshieldedPart = unshieldedInputs && Object.keys(unshieldedInputs).length > 0 || unshieldedOutputs.length > 0;
|
|
2887
|
+
if (!hasShieldedPart && !hasUnshieldedPart) throw Error("At least one shielded or unshielded swap is required.");
|
|
2888
|
+
const shieldedTx = hasShieldedPart && shieldedInputs !== void 0 ? await this.shielded.initSwap(shieldedSecretKeys, shieldedInputs, shieldedOutputs) : void 0;
|
|
2889
|
+
const unshieldedTx = hasUnshieldedPart && unshieldedInputs !== void 0 ? await this.unshielded.initSwap(unshieldedInputs, unshieldedOutputs, ttl) : void 0;
|
|
2890
|
+
const combinedTx = this.mergeUnprovenTransactions(shieldedTx, unshieldedTx);
|
|
2891
|
+
if (!combinedTx) throw Error("Unexpected transaction state.");
|
|
2892
|
+
const feeBalancingTx = payFees ? await this.dust.balanceTransactions(dustSecretKey, [combinedTx], ttl) : void 0;
|
|
2893
|
+
return {
|
|
2894
|
+
type: "UNPROVEN_TRANSACTION",
|
|
2895
|
+
transaction: this.mergeUnprovenTransactions(combinedTx, feeBalancingTx)
|
|
2896
|
+
};
|
|
2897
|
+
}
|
|
2898
|
+
async registerNightUtxosForDustGeneration(nightUtxos, nightVerifyingKey, signDustRegistration, dustReceiverAddress) {
|
|
2899
|
+
if (nightUtxos.length === 0) throw Error("At least one Night UTXO is required.");
|
|
2900
|
+
const receiverAddress = dustReceiverAddress ?? await this.dust.getAddress();
|
|
2901
|
+
return {
|
|
2902
|
+
type: "UNPROVEN_TRANSACTION",
|
|
2903
|
+
transaction: await this.createDustActionTransaction({
|
|
2904
|
+
type: "registration",
|
|
2905
|
+
dustReceiverAddress: receiverAddress
|
|
2906
|
+
}, nightUtxos, nightVerifyingKey, signDustRegistration)
|
|
2907
|
+
};
|
|
2908
|
+
}
|
|
2909
|
+
/**
|
|
2910
|
+
* Waits until the dust projected to be generated by the given Night UTxOs reaches `requiredAmount`, re-checking every
|
|
2911
|
+
* second. Pair with {@link estimateRegistration} to pick `requiredAmount`, then call before
|
|
2912
|
+
* {@link registerNightUtxosForDustGeneration} so the registration covers its own fee.
|
|
2913
|
+
*
|
|
2914
|
+
* @param nightUtxos - Night UTxOs to project generation for; the same set passed to the registration.
|
|
2915
|
+
* @param requiredAmount - Dust threshold to wait for. Resolves immediately if `<= 0n`.
|
|
2916
|
+
* @param opts.timeoutMs - Deadline, in ms, for the threshold to be reached. Rejects otherwise. Default `300_000`.
|
|
2917
|
+
* @throws If `nightUtxos` is empty, or if `requiredAmount` is not reached within `opts.timeoutMs`.
|
|
2918
|
+
*/
|
|
2919
|
+
async waitForGeneratedDust(nightUtxos, requiredAmount, opts) {
|
|
2920
|
+
await this.dust.waitForGeneratedDust(nightUtxos.map(({ utxo, meta }) => ({
|
|
2921
|
+
...utxo,
|
|
2922
|
+
ctime: meta.ctime,
|
|
2923
|
+
registeredForDustGeneration: meta.registeredForDustGeneration
|
|
2924
|
+
})), requiredAmount, this.clock, opts);
|
|
2925
|
+
}
|
|
2926
|
+
async deregisterFromDustGeneration(nightUtxos, nightVerifyingKey, signDustRegistration) {
|
|
2927
|
+
return {
|
|
2928
|
+
type: "UNPROVEN_TRANSACTION",
|
|
2929
|
+
transaction: await this.createDustActionTransaction({ type: "deregistration" }, nightUtxos, nightVerifyingKey, signDustRegistration)
|
|
2930
|
+
};
|
|
2931
|
+
}
|
|
2932
|
+
async revert(txOrRecipe) {
|
|
2933
|
+
const transactionsToRevert = BalancingRecipe.isRecipe(txOrRecipe) ? BalancingRecipe.getTransactions(txOrRecipe) : [txOrRecipe];
|
|
2934
|
+
await Promise.all(transactionsToRevert.map((tx) => this.revertTransaction(tx)));
|
|
2935
|
+
}
|
|
2936
|
+
async revertTransaction(tx) {
|
|
2937
|
+
await Promise.all([
|
|
2938
|
+
this.shielded.revertTransaction(tx),
|
|
2939
|
+
this.unshielded.revertTransaction(tx),
|
|
2940
|
+
this.dust.revertTransaction(tx)
|
|
2941
|
+
]).then(() => this.pendingTransactionsService.clear(tx));
|
|
2942
|
+
}
|
|
2943
|
+
async start(shieldedSecretKeys, dustSecretKey) {
|
|
2944
|
+
await Promise.all([
|
|
2945
|
+
this.shielded.start(shieldedSecretKeys),
|
|
2946
|
+
this.unshielded.start(),
|
|
2947
|
+
this.dust.start(dustSecretKey),
|
|
2948
|
+
this.pendingTransactionsService.start()
|
|
2949
|
+
]);
|
|
2950
|
+
}
|
|
2951
|
+
async stop() {
|
|
2952
|
+
await Promise.all([
|
|
2953
|
+
this.shielded.stop(),
|
|
2954
|
+
this.unshielded.stop(),
|
|
2955
|
+
this.dust.stop(),
|
|
2956
|
+
this.submissionService.close(),
|
|
2957
|
+
this.pendingTransactionsService.stop(),
|
|
2958
|
+
Promise.resolve(this.#pendingSubscription?.unsubscribe())
|
|
2959
|
+
]);
|
|
2960
|
+
}
|
|
2961
|
+
async queryTxHistoryByHash(hash) {
|
|
2962
|
+
const raw = await this.#txHistoryStorage.get(hash);
|
|
2963
|
+
return raw && isWalletEntry(raw) ? raw : void 0;
|
|
2964
|
+
}
|
|
2965
|
+
async getAllFromTxHistory() {
|
|
2966
|
+
return [...await this.#txHistoryStorage.getAll()];
|
|
2967
|
+
}
|
|
2968
|
+
};
|
|
2969
|
+
//#endregion
|
|
2970
|
+
//#region ../../packages/module/midnight-sync/src/store/compute-sync-ratio.ts
|
|
2971
|
+
const computeConnectedSyncRatio = (applied, highest, isConnected) => isConnected && applied === 0n && highest === 0n ? (0, _laceio_cardano_util.Percent)(1) : computeSyncRatio(applied, highest);
|
|
2972
|
+
const computeSyncRatio = (applied, highest) => {
|
|
2973
|
+
if (highest === 0n) {
|
|
2974
|
+
if (applied === 0n) return (0, _laceio_cardano_util.Percent)(0);
|
|
2975
|
+
const ratio = 1 - 1 / (1 + Number(applied) / 1e3);
|
|
2976
|
+
return (0, _laceio_cardano_util.Percent)(Math.min(.99, ratio));
|
|
2977
|
+
}
|
|
2978
|
+
return (0, _laceio_cardano_util.Percent)(Math.min(1, Number(applied) / Number(highest)));
|
|
2979
|
+
};
|
|
2980
|
+
//#endregion
|
|
2981
|
+
//#region ../../packages/module/midnight-sync/src/store/dependencies.ts
|
|
2982
|
+
/**
|
|
2983
|
+
* Wraps keyManager.keys$ with recovery for AuthenticationCancelledError.
|
|
2984
|
+
* If the user cancels the auth prompt, waits for keys to become available
|
|
2985
|
+
* from another source (e.g., an unlock triggered by a different flow)
|
|
2986
|
+
* and retries.
|
|
2987
|
+
*/
|
|
2988
|
+
const keysWithAuthCancelledRecovery$ = (keyManager) => keyManager.keys$.pipe((0, rxjs.take)(1), (0, rxjs.catchError)((error) => {
|
|
2989
|
+
if (!(error instanceof require_types.AuthenticationCancelledError)) return (0, rxjs.throwError)(() => error);
|
|
2990
|
+
return keyManager.areKeysAvailable$.pipe((0, rxjs.filter)((available) => available), (0, rxjs.take)(1), (0, rxjs.switchMap)(() => keyManager.keys$.pipe((0, rxjs.take)(1))));
|
|
2991
|
+
}));
|
|
2992
|
+
const STATE_SERIALISATION_THROTTLE_TIME = require_time_vo.Milliseconds(5e3);
|
|
2993
|
+
const DEFAULT_BATCH_UPDATES = {
|
|
2994
|
+
size: 12,
|
|
2995
|
+
spacing: 4
|
|
2996
|
+
};
|
|
2997
|
+
/**
|
|
2998
|
+
* Restore accepts the legacy `unshieldedTxHistory` key so profiles written
|
|
2999
|
+
* before the persisted key was renamed load without a resync; the next persist
|
|
3000
|
+
* rewrites the doc under `txHistory`, migrating it lazily.
|
|
3001
|
+
*/
|
|
3002
|
+
const readPersistedTxHistory = (serializedState) => serializedState.txHistory ?? serializedState.unshieldedTxHistory;
|
|
3003
|
+
/**
|
|
3004
|
+
* djb2 over the serialized states. The previous-persist comparator must not
|
|
3005
|
+
* RETAIN the inputs: keeping the raw serialized strings would pin ~10MB per
|
|
3006
|
+
* synced wallet in service worker memory between persist cycles.
|
|
3007
|
+
*/
|
|
3008
|
+
const fingerprintOf = (parts) => {
|
|
3009
|
+
let hash = 5381;
|
|
3010
|
+
for (const part of parts) for (let index = 0; index < part.length; index += 1) {
|
|
3011
|
+
hash = hash * 33 ^ part.charCodeAt(index);
|
|
3012
|
+
hash |= 0;
|
|
3013
|
+
}
|
|
3014
|
+
return `${hash}:${parts.map((part) => part.length).join(":")}`;
|
|
3015
|
+
};
|
|
3016
|
+
const getAccountWalletInstance = async ({ account, config, getTemenosLedgerIndexerUrl, store, keyManager }, logger, { createAttestedProver, createLocalProofServerAccess, batchUpdates = DEFAULT_BATCH_UPDATES }) => {
|
|
3017
|
+
const walletState = await (0, rxjs.firstValueFrom)(store.get(String(account.accountId)).pipe((0, rxjs.defaultIfEmpty)(void 0)));
|
|
3018
|
+
const indexerClientConnection = {
|
|
3019
|
+
indexerHttpUrl: config.indexerAddress,
|
|
3020
|
+
indexerWsUrl: require_utils.convertHttpUrlToWebsocket(config.indexerAddress),
|
|
3021
|
+
keepAlive: 15e3
|
|
3022
|
+
};
|
|
3023
|
+
const { networkId } = account.blockchainSpecific;
|
|
3024
|
+
const proofServerUrl = require_const.getProofServerEndpoint(config.proofServer);
|
|
3025
|
+
if (!proofServerUrl && config.proofServer.kind !== "in-process") throw new Error(`Cannot start Midnight wallet: proof server mode "${config.proofServer.kind}" has no HTTP endpoint`);
|
|
3026
|
+
require_const.assertProofServerRouting(config.proofServer, !!createAttestedProver, !!createLocalProofServerAccess);
|
|
3027
|
+
const createAccess = (onProgress) => config.proofServer.kind === "in-process" && createLocalProofServerAccess ? createLocalProofServerAccess(onProgress) : config.proofServer.kind === "tee-delegated" && createAttestedProver ? require_watch.createAttestedProofServerAccess(createAttestedProver({
|
|
3028
|
+
networkId,
|
|
3029
|
+
proofServerApiUrl: config.proofServer.url,
|
|
3030
|
+
getLedgerIndexerUrl: async () => {
|
|
3031
|
+
if (!getTemenosLedgerIndexerUrl) throw new Error("Temenos attestation requires a ledger indexer resolver");
|
|
3032
|
+
return getTemenosLedgerIndexerUrl();
|
|
3033
|
+
}
|
|
3034
|
+
}), onProgress) : require_watch.createProofServerAccess(require_watch.createHttpProofServerTransport(proofServerUrl));
|
|
3035
|
+
const proofServer = require_watch.createScopedProofServerAccess(createAccess);
|
|
3036
|
+
const { finalizeRecipe } = proofServer;
|
|
3037
|
+
const configuration = {
|
|
3038
|
+
costParameters: {
|
|
3039
|
+
additionalFeeOverhead: 300000000000000n,
|
|
3040
|
+
feeBlocksMargin: 5
|
|
3041
|
+
},
|
|
3042
|
+
networkId,
|
|
3043
|
+
batchUpdates,
|
|
3044
|
+
indexerClientConnection,
|
|
3045
|
+
relayURL: new URL(require_utils.convertHttpUrlToWebsocket(config.nodeAddress)),
|
|
3046
|
+
txHistoryStorage: new require_const.InMemoryTransactionHistoryStorage(WalletEntrySchema, mergeWalletEntries)
|
|
3047
|
+
};
|
|
3048
|
+
if (walletState) {
|
|
3049
|
+
const { dust, shielded, unshielded } = walletState.serializedState;
|
|
3050
|
+
let restoredTxHistoryStorage;
|
|
3051
|
+
try {
|
|
3052
|
+
restoredTxHistoryStorage = require_const.InMemoryTransactionHistoryStorage.restore(SerialisedWalletState.toJSON(readPersistedTxHistory(walletState.serializedState)), WalletEntrySchema, mergeWalletEntries);
|
|
3053
|
+
} catch (error) {
|
|
3054
|
+
logger.warn(`Discarding unreadable persisted Midnight wallet state for account ${account.accountId}; rebuilding from seed`, error instanceof Error ? error.message : String(error));
|
|
3055
|
+
await (0, rxjs.firstValueFrom)(store.removeWhere((state) => state.accountId === account.accountId).pipe((0, rxjs.defaultIfEmpty)(void 0), (0, rxjs.catchError)((wipeError) => {
|
|
3056
|
+
logger.error(`Failed to discard unreadable Midnight wallet state for account ${account.accountId}`, wipeError);
|
|
3057
|
+
return (0, rxjs.of)(void 0);
|
|
3058
|
+
})));
|
|
3059
|
+
}
|
|
3060
|
+
if (restoredTxHistoryStorage) {
|
|
3061
|
+
configuration.txHistoryStorage = restoredTxHistoryStorage;
|
|
3062
|
+
return {
|
|
3063
|
+
walletFacade: await WalletFacade.init({
|
|
3064
|
+
configuration,
|
|
3065
|
+
provingService: () => proofServer.provingService,
|
|
3066
|
+
submissionService: createProgressSubmissionService,
|
|
3067
|
+
shielded: (config) => ShieldedWallet(config).restore(SerialisedWalletState.toJSON(shielded)),
|
|
3068
|
+
unshielded: (config) => require_watch.UnshieldedWallet(config).restore(SerialisedWalletState.toJSON(unshielded)),
|
|
3069
|
+
dust: (config) => DustWallet(config).restore(SerialisedWalletState.toJSON(dust))
|
|
3070
|
+
}),
|
|
3071
|
+
txHistoryStorage: restoredTxHistoryStorage,
|
|
3072
|
+
proofCircuitProvider: proofServer.circuits,
|
|
3073
|
+
finalizeRecipe
|
|
3074
|
+
};
|
|
3075
|
+
}
|
|
3076
|
+
}
|
|
3077
|
+
const { walletKeys: { dustKeyBuffer, zswapKeyBuffer }, unshieldedKeystore } = await (0, rxjs.firstValueFrom)(keysWithAuthCancelledRecovery$(keyManager));
|
|
3078
|
+
const dustParameters = _midnight_ntwrk_ledger_v8.LedgerParameters.initialParameters().dust;
|
|
3079
|
+
const txHistoryStorage = new require_const.InMemoryTransactionHistoryStorage(WalletEntrySchema, mergeWalletEntries);
|
|
3080
|
+
configuration.txHistoryStorage = txHistoryStorage;
|
|
3081
|
+
return {
|
|
3082
|
+
walletFacade: await WalletFacade.init({
|
|
3083
|
+
configuration,
|
|
3084
|
+
provingService: () => proofServer.provingService,
|
|
3085
|
+
submissionService: createProgressSubmissionService,
|
|
3086
|
+
shielded: (config) => ShieldedWallet(config).startWithSeed(zswapKeyBuffer),
|
|
3087
|
+
unshielded: (config) => require_watch.UnshieldedWallet(config).startWithPublicKey(require_watch.PublicKey.fromKeyStore(unshieldedKeystore)),
|
|
3088
|
+
dust: (config) => DustWallet(config).startWithSeed(dustKeyBuffer, dustParameters)
|
|
3089
|
+
}),
|
|
3090
|
+
txHistoryStorage,
|
|
3091
|
+
proofCircuitProvider: proofServer.circuits,
|
|
3092
|
+
finalizeRecipe
|
|
3093
|
+
};
|
|
3094
|
+
};
|
|
3095
|
+
/**
|
|
3096
|
+
* Creates an observable MidnightWallet from wallet instances.
|
|
3097
|
+
*
|
|
3098
|
+
* The nightVerifyingKey is obtained from the wallet state, which works
|
|
3099
|
+
* for both restored and new wallets.
|
|
3100
|
+
*/
|
|
3101
|
+
const createAccountObservableMidnightWallet = ({ account, keyManager, walletFacade, haltPersistence, proofCircuitProvider, finalizeRecipe }) => {
|
|
3102
|
+
const { networkId } = account.blockchainSpecific;
|
|
3103
|
+
const state$ = walletFacade.state().pipe((0, rxjs.shareReplay)({
|
|
3104
|
+
bufferSize: 1,
|
|
3105
|
+
refCount: true
|
|
3106
|
+
}));
|
|
3107
|
+
const releasing = withReservationRelease(walletFacade);
|
|
3108
|
+
return state$.pipe((0, rxjs.take)(1), (0, rxjs.map)((initialState) => {
|
|
3109
|
+
const nightVerifyingKey = initialState.unshielded.capabilities.keys.getPublicKey(initialState.unshielded.state);
|
|
3110
|
+
return {
|
|
3111
|
+
accountId: account.accountId,
|
|
3112
|
+
areKeysAvailable$: keyManager.areKeysAvailable$,
|
|
3113
|
+
networkId,
|
|
3114
|
+
nightVerifyingKey,
|
|
3115
|
+
proofCircuitProvider,
|
|
3116
|
+
walletId: account.walletId,
|
|
3117
|
+
address$: state$.pipe((0, rxjs.map)(({ dust, shielded, unshielded }) => ({
|
|
3118
|
+
dust: MidnightDustAddress(require_dist.DustAddress.codec.encode(networkId, dust.capabilities.keys.getAddress(dust.state)).asString()),
|
|
3119
|
+
shielded: MidnightShieldedAddress(require_dist.ShieldedAddress.codec.encode(networkId, shielded.address).asString()),
|
|
3120
|
+
unshielded: MidnightUnshieldedAddress(require_dist.UnshieldedAddress.codec.encode(networkId, unshielded.address).asString())
|
|
3121
|
+
})), (0, rxjs.distinctUntilChanged)(_laceio_cardano_util.deepEquals)),
|
|
3122
|
+
coinsByTokenType$: state$.pipe((0, rxjs.map)(({ shielded, unshielded }) => {
|
|
3123
|
+
const shieldedCoins = {};
|
|
3124
|
+
const unshieldedCoins = {};
|
|
3125
|
+
for (const { coin } of shielded.totalCoins) {
|
|
3126
|
+
const previousCoinsList = shieldedCoins[coin.type] || [];
|
|
3127
|
+
shieldedCoins[coin.type] = previousCoinsList.concat({
|
|
3128
|
+
status: "mt_index" in coin ? "available" : "pending",
|
|
3129
|
+
value: require_bignum_vo.BigNumber(coin.value)
|
|
3130
|
+
});
|
|
3131
|
+
}
|
|
3132
|
+
const parseUnshieldedCoins = (status, coins) => {
|
|
3133
|
+
for (const { meta, utxo } of coins) {
|
|
3134
|
+
const tokenType = require_utils.toUnshieldedTokenType(utxo.type, networkId);
|
|
3135
|
+
unshieldedCoins[tokenType] = (unshieldedCoins[tokenType] || []).concat({
|
|
3136
|
+
status,
|
|
3137
|
+
value: require_bignum_vo.BigNumber(utxo.value),
|
|
3138
|
+
registeredForDustGeneration: meta.registeredForDustGeneration,
|
|
3139
|
+
ownerAddress: utxo.owner
|
|
3140
|
+
});
|
|
3141
|
+
}
|
|
3142
|
+
};
|
|
3143
|
+
parseUnshieldedCoins("pending", unshielded.pendingCoins);
|
|
3144
|
+
parseUnshieldedCoins("available", unshielded.availableCoins);
|
|
3145
|
+
return {
|
|
3146
|
+
shielded: shieldedCoins,
|
|
3147
|
+
unshielded: unshieldedCoins
|
|
3148
|
+
};
|
|
3149
|
+
}), (0, rxjs.distinctUntilChanged)(_laceio_cardano_util.deepEquals)),
|
|
3150
|
+
syncProgress$: state$.pipe((0, rxjs.map)(({ dust, shielded, unshielded }) => ({
|
|
3151
|
+
dust: computeConnectedSyncRatio(dust.state.progress.appliedIndex, dust.state.progress.highestRelevantWalletIndex, dust.state.progress.isConnected),
|
|
3152
|
+
shielded: computeConnectedSyncRatio(shielded.state.progress.appliedIndex, shielded.state.progress.highestRelevantWalletIndex, shielded.state.progress.isConnected),
|
|
3153
|
+
unshielded: computeConnectedSyncRatio(unshielded.state.progress.appliedId, unshielded.state.progress.highestTransactionId, unshielded.state.progress.isConnected),
|
|
3154
|
+
isStrictlyComplete: {
|
|
3155
|
+
dust: dust.state.progress.isStrictlyComplete(),
|
|
3156
|
+
shielded: shielded.state.progress.isStrictlyComplete(),
|
|
3157
|
+
unshielded: unshielded.state.progress.isStrictlyComplete()
|
|
3158
|
+
}
|
|
3159
|
+
})), (0, rxjs.distinctUntilChanged)(_laceio_cardano_util.deepEquals)),
|
|
3160
|
+
transactionHistory$: state$.pipe((0, rxjs.throttleTime)(500, void 0, {
|
|
3161
|
+
leading: true,
|
|
3162
|
+
trailing: true
|
|
3163
|
+
}), (0, rxjs.switchMap)(() => (0, rxjs.from)(walletFacade.getAllFromTxHistory())), (0, rxjs.distinctUntilChanged)(_laceio_cardano_util.deepEquals)),
|
|
3164
|
+
balanceFinalizedTransaction: (tx, { ttl, tokenKindsToBalance }) => keyManager.keys$.pipe((0, rxjs.take)(1), (0, rxjs.switchMap)(({ walletKeys: { dustSecretKey, zswapSecretKeys } }) => (0, rxjs.from)(releasing.balanceFinalizedTransaction(tx, {
|
|
3165
|
+
shieldedSecretKeys: zswapSecretKeys,
|
|
3166
|
+
dustSecretKey
|
|
3167
|
+
}, {
|
|
3168
|
+
ttl,
|
|
3169
|
+
tokenKindsToBalance
|
|
3170
|
+
})))),
|
|
3171
|
+
balanceUnboundTransaction: (tx, { ttl, tokenKindsToBalance }) => keyManager.keys$.pipe((0, rxjs.take)(1), (0, rxjs.switchMap)(({ walletKeys: { dustSecretKey, zswapSecretKeys } }) => (0, rxjs.from)(releasing.balanceUnboundTransaction(tx, {
|
|
3172
|
+
shieldedSecretKeys: zswapSecretKeys,
|
|
3173
|
+
dustSecretKey
|
|
3174
|
+
}, {
|
|
3175
|
+
ttl,
|
|
3176
|
+
tokenKindsToBalance
|
|
3177
|
+
})))),
|
|
3178
|
+
balanceUnprovenTransaction: (tx, { ttl, tokenKindsToBalance }) => keyManager.keys$.pipe((0, rxjs.take)(1), (0, rxjs.switchMap)(({ walletKeys: { dustSecretKey, zswapSecretKeys } }) => (0, rxjs.from)(walletFacade.balanceUnprovenTransaction(tx, {
|
|
3179
|
+
shieldedSecretKeys: zswapSecretKeys,
|
|
3180
|
+
dustSecretKey
|
|
3181
|
+
}, {
|
|
3182
|
+
ttl,
|
|
3183
|
+
tokenKindsToBalance
|
|
3184
|
+
})))),
|
|
3185
|
+
calculateTransactionFee: (tx) => (0, rxjs.from)(walletFacade.calculateTransactionFee(tx)),
|
|
3186
|
+
estimateTransactionFee: (tx, options) => keyManager.keys$.pipe((0, rxjs.take)(1), (0, rxjs.switchMap)(({ walletKeys: { dustSecretKey } }) => (0, rxjs.from)(walletFacade.estimateTransactionFee(tx, dustSecretKey, options)))),
|
|
3187
|
+
deregisterFromDustGeneration: (nightUtxos) => keyManager.keys$.pipe((0, rxjs.take)(1), (0, rxjs.switchMap)(({ unshieldedKeystore }) => (0, rxjs.from)(walletFacade.deregisterFromDustGeneration(nightUtxos, unshieldedKeystore.getPublicKey(), (data) => unshieldedKeystore.signData(data))))),
|
|
3188
|
+
getTransactionHistoryEntryByHash: (hash) => (0, rxjs.from)(walletFacade.queryTxHistoryByHash(hash)),
|
|
3189
|
+
finalizeRecipe: (recipe, onProgress) => (0, rxjs.defer)(async () => finalizeRecipe(walletFacade, recipe, onProgress)),
|
|
3190
|
+
finalizeTransaction: (recipe) => (0, rxjs.from)(walletFacade.finalizeTransaction(recipe)),
|
|
3191
|
+
registerNightUtxosForDustGeneration: (nightUtxos, dustAddress) => keyManager.keys$.pipe((0, rxjs.take)(1), (0, rxjs.switchMap)(({ unshieldedKeystore }) => (0, rxjs.from)(walletFacade.registerNightUtxosForDustGeneration(nightUtxos, unshieldedKeystore.getPublicKey(), (data) => unshieldedKeystore.signData(data), dustAddress)))),
|
|
3192
|
+
revert: (recipe) => (0, rxjs.from)(walletFacade.revert(recipe)),
|
|
3193
|
+
state: () => state$,
|
|
3194
|
+
stop: () => {
|
|
3195
|
+
haltPersistence();
|
|
3196
|
+
return (0, rxjs.from)(walletFacade.stop());
|
|
3197
|
+
},
|
|
3198
|
+
signUnprovenTransaction: (tx) => keyManager.keys$.pipe((0, rxjs.take)(1), (0, rxjs.switchMap)(({ unshieldedKeystore }) => (0, rxjs.from)(walletFacade.signUnprovenTransaction(tx, (data) => unshieldedKeystore.signData(data))))),
|
|
3199
|
+
signRecipe: (recipe) => keyManager.keys$.pipe((0, rxjs.take)(1), (0, rxjs.switchMap)(({ unshieldedKeystore }) => (0, rxjs.from)(walletFacade.signRecipe(recipe, (data) => unshieldedKeystore.signData(data))))),
|
|
3200
|
+
signData: (data) => keyManager.keys$.pipe((0, rxjs.take)(1), (0, rxjs.map)(({ unshieldedKeystore }) => ({
|
|
3201
|
+
signature: unshieldedKeystore.signData(data),
|
|
3202
|
+
verifyingKey: unshieldedKeystore.getPublicKey()
|
|
3203
|
+
}))),
|
|
3204
|
+
submitTransaction: (tx) => (0, rxjs.from)(walletFacade.submitTransaction(tx)),
|
|
3205
|
+
transferTransaction: (outputs, { ttl, payFees }) => keyManager.keys$.pipe((0, rxjs.take)(1), (0, rxjs.switchMap)(({ walletKeys: { dustSecretKey, zswapSecretKeys } }) => (0, rxjs.from)(releasing.transferTransaction(outputs, {
|
|
3206
|
+
shieldedSecretKeys: zswapSecretKeys,
|
|
3207
|
+
dustSecretKey
|
|
3208
|
+
}, {
|
|
3209
|
+
ttl,
|
|
3210
|
+
payFees
|
|
3211
|
+
})))),
|
|
3212
|
+
initSwap: (desiredInputs, desiredOutputs, { ttl, payFees }) => keyManager.keys$.pipe((0, rxjs.take)(1), (0, rxjs.switchMap)(({ walletKeys: { dustSecretKey, zswapSecretKeys } }) => (0, rxjs.from)(releasing.initSwap({
|
|
3213
|
+
desiredInputs,
|
|
3214
|
+
desiredOutputs
|
|
3215
|
+
}, {
|
|
3216
|
+
shieldedSecretKeys: zswapSecretKeys,
|
|
3217
|
+
dustSecretKey
|
|
3218
|
+
}, {
|
|
3219
|
+
ttl,
|
|
3220
|
+
payFees
|
|
3221
|
+
}))))
|
|
3222
|
+
};
|
|
3223
|
+
}));
|
|
3224
|
+
};
|
|
3225
|
+
/**
|
|
3226
|
+
* Creates and manages the lifecycle of Midnight SDK wallet instances.
|
|
3227
|
+
*
|
|
3228
|
+
* Lifecycle:
|
|
3229
|
+
* - Creates all 3 wallets (Unshielded, Shielded, Dust) via getAccountWalletInstance
|
|
3230
|
+
* - Starts UnshieldedWallet immediately (no keys needed)
|
|
3231
|
+
* - Starts ShieldedWallet and DustWallet once account keys become available
|
|
3232
|
+
* (one auth prompt; sync then runs for the wallet's lifetime, surviving
|
|
3233
|
+
* the key manager's idle zeroization — see the start step below)
|
|
3234
|
+
* - DustWallet is never stopped once started
|
|
3235
|
+
* (SDK limitation: stop() closes Effect runtime, breaking calculateFee)
|
|
3236
|
+
* - On unsubscribe: stops all wallets and clears the sync key copy
|
|
3237
|
+
*/
|
|
3238
|
+
const createAndManageWallets = (props, { logger }, options) => {
|
|
3239
|
+
const { keyManager, account, store } = props;
|
|
3240
|
+
return new rxjs.Observable((subscriber) => {
|
|
3241
|
+
let walletFacade = null;
|
|
3242
|
+
let syncSecretKeys = null;
|
|
3243
|
+
let syncDustSecretKey = null;
|
|
3244
|
+
let syncStartSubscription = null;
|
|
3245
|
+
let persistSubscription = null;
|
|
3246
|
+
let isDestroyed = false;
|
|
3247
|
+
let isPersistenceHalted = false;
|
|
3248
|
+
const init = async () => {
|
|
3249
|
+
const { walletFacade: facade, txHistoryStorage, proofCircuitProvider, finalizeRecipe } = await getAccountWalletInstance(props, logger, options);
|
|
3250
|
+
if (isDestroyed) {
|
|
3251
|
+
facade.stop();
|
|
3252
|
+
return;
|
|
3253
|
+
}
|
|
3254
|
+
walletFacade = facade;
|
|
3255
|
+
await walletFacade.unshielded.start();
|
|
3256
|
+
syncStartSubscription = keysWithAuthCancelledRecovery$(keyManager).pipe((0, rxjs.switchMap)((keys) => {
|
|
3257
|
+
if (!walletFacade) return (0, rxjs.from)(Promise.resolve());
|
|
3258
|
+
syncSecretKeys = _midnight_ntwrk_ledger_v8.ZswapSecretKeys.fromSeed(keys.walletKeys.zswapKeyBuffer);
|
|
3259
|
+
syncDustSecretKey = _midnight_ntwrk_ledger_v8.DustSecretKey.fromSeed(keys.walletKeys.dustKeyBuffer);
|
|
3260
|
+
const facade = walletFacade;
|
|
3261
|
+
const syncKeys = syncSecretKeys;
|
|
3262
|
+
const dustSyncKey = syncDustSecretKey;
|
|
3263
|
+
return (0, rxjs.from)((async () => {
|
|
3264
|
+
const failures = [];
|
|
3265
|
+
try {
|
|
3266
|
+
await facade.shielded.start(syncKeys);
|
|
3267
|
+
} catch (error) {
|
|
3268
|
+
logger.error(`Midnight shielded wallet failed to start for account ${account.accountId}:`, error);
|
|
3269
|
+
failures.push(error);
|
|
3270
|
+
}
|
|
3271
|
+
try {
|
|
3272
|
+
await facade.dust.start(dustSyncKey);
|
|
3273
|
+
} catch (error) {
|
|
3274
|
+
logger.error(`Midnight dust wallet failed to start for account ${account.accountId}:`, error);
|
|
3275
|
+
failures.push(error);
|
|
3276
|
+
}
|
|
3277
|
+
if (failures.length > 0) throw failures[0];
|
|
3278
|
+
})());
|
|
3279
|
+
})).subscribe({ error: (error) => {
|
|
3280
|
+
logger.error(`Wallet sync start error for account ${account.accountId}:`, error);
|
|
3281
|
+
subscriber.error(error);
|
|
3282
|
+
} });
|
|
3283
|
+
let lastPersistedFingerprint;
|
|
3284
|
+
const persistOnce = async () => {
|
|
3285
|
+
const [dust, shielded, unshielded, txHistory] = (await (0, rxjs.firstValueFrom)((0, rxjs.zip)((0, rxjs.from)(walletFacade.dust.serializeState()), (0, rxjs.from)(walletFacade.shielded.serializeState()), (0, rxjs.from)(walletFacade.unshielded.serializeState()), (0, rxjs.from)(txHistoryStorage.serialize())))).map(SerialisedWalletState);
|
|
3286
|
+
const fingerprint = fingerprintOf([
|
|
3287
|
+
dust,
|
|
3288
|
+
shielded,
|
|
3289
|
+
unshielded,
|
|
3290
|
+
txHistory
|
|
3291
|
+
]);
|
|
3292
|
+
if (fingerprint === lastPersistedFingerprint) return;
|
|
3293
|
+
if (isPersistenceHalted || isDestroyed) return;
|
|
3294
|
+
await (0, rxjs.firstValueFrom)(store.upsert({
|
|
3295
|
+
serializedState: {
|
|
3296
|
+
dust,
|
|
3297
|
+
shielded,
|
|
3298
|
+
unshielded,
|
|
3299
|
+
txHistory
|
|
3300
|
+
},
|
|
3301
|
+
accountId: account.accountId,
|
|
3302
|
+
walletId: account.walletId,
|
|
3303
|
+
networkId: account.blockchainSpecific.networkId
|
|
3304
|
+
}).pipe((0, rxjs.defaultIfEmpty)(void 0)));
|
|
3305
|
+
lastPersistedFingerprint = fingerprint;
|
|
3306
|
+
};
|
|
3307
|
+
persistSubscription = walletFacade.state().pipe((0, rxjs.throttleTime)(STATE_SERIALISATION_THROTTLE_TIME, void 0, {
|
|
3308
|
+
leading: true,
|
|
3309
|
+
trailing: true
|
|
3310
|
+
}), (0, rxjs.exhaustMap)(() => (0, rxjs.from)(persistOnce()).pipe((0, rxjs.catchError)((error) => {
|
|
3311
|
+
logger.error(`Failed to persist wallet state for account ${account.accountId}:`, error);
|
|
3312
|
+
return (0, rxjs.of)(void 0);
|
|
3313
|
+
})))).subscribe();
|
|
3314
|
+
subscriber.next({
|
|
3315
|
+
walletFacade,
|
|
3316
|
+
haltPersistence: () => {
|
|
3317
|
+
isPersistenceHalted = true;
|
|
3318
|
+
},
|
|
3319
|
+
proofCircuitProvider,
|
|
3320
|
+
finalizeRecipe
|
|
3321
|
+
});
|
|
3322
|
+
};
|
|
3323
|
+
init().catch((error) => {
|
|
3324
|
+
subscriber.error(error);
|
|
3325
|
+
});
|
|
3326
|
+
return () => {
|
|
3327
|
+
isDestroyed = true;
|
|
3328
|
+
syncStartSubscription?.unsubscribe();
|
|
3329
|
+
persistSubscription?.unsubscribe();
|
|
3330
|
+
if (walletFacade) walletFacade.stop().catch(() => void 0).finally(() => {
|
|
3331
|
+
syncSecretKeys?.clear();
|
|
3332
|
+
syncDustSecretKey?.clear();
|
|
3333
|
+
});
|
|
3334
|
+
};
|
|
3335
|
+
});
|
|
3336
|
+
};
|
|
3337
|
+
/**
|
|
3338
|
+
* Starts a Midnight account wallet with full lifecycle management.
|
|
3339
|
+
*
|
|
3340
|
+
* Creates SDK wallets, manages their start/stop lifecycle, and converts
|
|
3341
|
+
* to the MidnightWallet interface used by the rest of the application.
|
|
3342
|
+
*/
|
|
3343
|
+
const createStartMidnightAccountWallet = (dependencies, options) => (props) => createAndManageWallets(props, dependencies, options).pipe((0, rxjs.switchMap)(({ walletFacade, haltPersistence, proofCircuitProvider, finalizeRecipe }) => createAccountObservableMidnightWallet({
|
|
3344
|
+
account: props.account,
|
|
3345
|
+
keyManager: props.keyManager,
|
|
3346
|
+
walletFacade,
|
|
3347
|
+
haltPersistence,
|
|
3348
|
+
proofCircuitProvider,
|
|
3349
|
+
finalizeRecipe
|
|
3350
|
+
})));
|
|
3351
|
+
/**
|
|
3352
|
+
* The engine's side-effect dependencies. The attested prover is the
|
|
3353
|
+
* loadout's: the app proves through the bundled Temenos deployment, which a
|
|
3354
|
+
* headless loadout does not ship.
|
|
3355
|
+
*/
|
|
3356
|
+
const createMidnightSideEffectDependencies = (options = {}) => ({ runtime }, dependencies) => {
|
|
3357
|
+
const midnightWallets$ = require_midnight_wallet.midnightWalletsForRuntime(runtime);
|
|
3358
|
+
return {
|
|
3359
|
+
midnightWallets$,
|
|
3360
|
+
wasmProofActivities$: rxjs.EMPTY,
|
|
3361
|
+
dismissWasmProofActivity: () => void 0,
|
|
3362
|
+
teeAttestationProgress$: require_send_proof_progress.teeAttestationProgress$,
|
|
3363
|
+
getMidnightWalletByAccountId: (accountId) => midnightWallets$.pipe((0, rxjs.take)(1), (0, rxjs.map)((wallets) => wallets[accountId]), (0, rxjs.switchMap)((wallet) => wallet ? (0, rxjs.of)(wallet) : (0, rxjs.throwError)(() => /* @__PURE__ */ new Error(`Could not load midnight wallet for account ${accountId}`)))),
|
|
3364
|
+
stopAllMidnightWallets: () => {
|
|
3365
|
+
const walletsArray = Object.values(midnightWallets$.value);
|
|
3366
|
+
midnightWallets$.next({});
|
|
3367
|
+
if (walletsArray.length === 0) return (0, rxjs.of)(void 0);
|
|
3368
|
+
return (0, rxjs.forkJoin)(walletsArray.map((wallet) => wallet.stop())).pipe((0, rxjs.map)(() => void 0));
|
|
3369
|
+
},
|
|
3370
|
+
stopMidnightWallet: (accountId) => {
|
|
3371
|
+
const wallet = midnightWallets$.value[accountId];
|
|
3372
|
+
if (!wallet) return (0, rxjs.of)(void 0);
|
|
3373
|
+
const { [accountId]: _, ...remaining } = midnightWallets$.value;
|
|
3374
|
+
midnightWallets$.next(remaining);
|
|
3375
|
+
return wallet.stop().pipe((0, rxjs.map)(() => void 0));
|
|
3376
|
+
},
|
|
3377
|
+
startMidnightAccountWallet: createStartMidnightAccountWallet(dependencies, options)
|
|
3378
|
+
};
|
|
3379
|
+
};
|
|
3380
|
+
//#endregion
|
|
3381
|
+
//#region ../../packages/module/midnight-sync/src/store/utils/activities.ts
|
|
3382
|
+
const toBigInt = (v) => typeof v === "bigint" ? v : BigInt(v);
|
|
3383
|
+
const buildTokenBalanceChangesFromUtxos = (createdUtxos, spentUtxos, networkId) => {
|
|
3384
|
+
const changesByToken = /* @__PURE__ */ new Map();
|
|
3385
|
+
for (const u of createdUtxos) {
|
|
3386
|
+
const tokenId = require_token_id_vo.TokenId(require_utils.toUnshieldedTokenType(u.tokenType, networkId));
|
|
3387
|
+
const existing = changesByToken.get(tokenId);
|
|
3388
|
+
const value = toBigInt(u.value);
|
|
3389
|
+
changesByToken.set(tokenId, {
|
|
3390
|
+
tokenId,
|
|
3391
|
+
amount: existing ? existing.amount + value : value
|
|
3392
|
+
});
|
|
3393
|
+
}
|
|
3394
|
+
for (const u of spentUtxos) {
|
|
3395
|
+
const tokenId = require_token_id_vo.TokenId(require_utils.toUnshieldedTokenType(u.tokenType, networkId));
|
|
3396
|
+
const existing = changesByToken.get(tokenId);
|
|
3397
|
+
const value = toBigInt(u.value);
|
|
3398
|
+
changesByToken.set(tokenId, {
|
|
3399
|
+
tokenId,
|
|
3400
|
+
amount: existing ? existing.amount - value : -value
|
|
3401
|
+
});
|
|
3402
|
+
}
|
|
3403
|
+
return [...changesByToken.values()].filter(({ amount }) => amount !== 0n).map(({ tokenId, amount }) => ({
|
|
3404
|
+
tokenId,
|
|
3405
|
+
amount: require_bignum_vo.BigNumber(amount)
|
|
3406
|
+
}));
|
|
3407
|
+
};
|
|
3408
|
+
const getAddressFromUtxos = (createdUtxos, spentUtxos) => {
|
|
3409
|
+
return (createdUtxos[0] ?? spentUtxos[0])?.owner ?? "";
|
|
3410
|
+
};
|
|
3411
|
+
/**
|
|
3412
|
+
* Whether the wallet took part in an unshielded movement in this transaction —
|
|
3413
|
+
* the gate for surfacing it as an activity. True for unshielded and mixed sends,
|
|
3414
|
+
* and for dust designation (which rotates night UTxOs into the unshielded
|
|
3415
|
+
* section). False for shielded-only entries: their values are encrypted and
|
|
3416
|
+
* unreadable, and the fee-dust they spend never lands in the unshielded section,
|
|
3417
|
+
* so surfacing them would only produce an empty/unknown row.
|
|
3418
|
+
*/
|
|
3419
|
+
const entryHasUnshieldedActivity = (entry) => (entry.unshielded?.createdUtxos.length ?? 0) > 0 || (entry.unshielded?.spentUtxos.length ?? 0) > 0;
|
|
3420
|
+
const mapStatusToActivityType = (status, tokenBalanceChanges) => {
|
|
3421
|
+
switch (status) {
|
|
3422
|
+
case "SUCCESS":
|
|
3423
|
+
case "PARTIAL_SUCCESS": return !tokenBalanceChanges?.length || tokenBalanceChanges.some(({ amount }) => BigInt(amount) > 0n) ? require_activity_type.ActivityType.Receive : require_activity_type.ActivityType.Send;
|
|
3424
|
+
case "FAILURE": return require_activity_type.ActivityType.Failed;
|
|
3425
|
+
}
|
|
3426
|
+
};
|
|
3427
|
+
/**
|
|
3428
|
+
* Resolves the activity type and displayed token amounts for a transaction's
|
|
3429
|
+
* unshielded section. A transaction that moved unshielded value but nets to zero
|
|
3430
|
+
* is a self-transfer — a plain self-send, or a dust designation, which rotates
|
|
3431
|
+
* NIGHT back to the owner — so it is surfaced as {@link ActivityType.Self}.
|
|
3432
|
+
* No amount is shown: no value left the wallet, and the intended amount is not
|
|
3433
|
+
* recoverable (a self output is indistinguishable from change). Failures keep
|
|
3434
|
+
* their Failed type regardless.
|
|
3435
|
+
*/
|
|
3436
|
+
const deriveUnshieldedActivity = ({ status, createdUtxos, spentUtxos, networkId }) => {
|
|
3437
|
+
const netChanges = buildTokenBalanceChangesFromUtxos(createdUtxos, spentUtxos, networkId);
|
|
3438
|
+
if (status !== "FAILURE" && netChanges.length === 0 && (createdUtxos.length > 0 || spentUtxos.length > 0)) return {
|
|
3439
|
+
type: require_activity_type.ActivityType.Self,
|
|
3440
|
+
tokenBalanceChanges: []
|
|
3441
|
+
};
|
|
3442
|
+
return {
|
|
3443
|
+
type: mapStatusToActivityType(status, netChanges),
|
|
3444
|
+
tokenBalanceChanges: netChanges
|
|
3445
|
+
};
|
|
3446
|
+
};
|
|
3447
|
+
const formatFee = (fees) => fees === null || fees === void 0 ? "0" : String(fees);
|
|
3448
|
+
//#endregion
|
|
3449
|
+
//#region ../../packages/module/midnight-sync/src/store/side-effects/activities.ts
|
|
3450
|
+
const mapTxHistoryEntryToActivity = ({ accountId, txHistoryEntry, networkId }) => {
|
|
3451
|
+
const { hash, timestamp, status } = txHistoryEntry;
|
|
3452
|
+
const { type, tokenBalanceChanges } = deriveUnshieldedActivity({
|
|
3453
|
+
status,
|
|
3454
|
+
createdUtxos: txHistoryEntry.unshielded?.createdUtxos ?? [],
|
|
3455
|
+
spentUtxos: txHistoryEntry.unshielded?.spentUtxos ?? [],
|
|
3456
|
+
networkId
|
|
3457
|
+
});
|
|
3458
|
+
return {
|
|
3459
|
+
accountId,
|
|
3460
|
+
activityId: hash,
|
|
3461
|
+
type,
|
|
3462
|
+
timestamp: require_time_vo.Timestamp(timestamp?.getTime() ?? 0),
|
|
3463
|
+
tokenBalanceChanges
|
|
3464
|
+
};
|
|
3465
|
+
};
|
|
3466
|
+
const mapTxHistoryEntryToActivityDetail = ({ accountId, txHistoryEntry, networkId }) => {
|
|
3467
|
+
const createdUtxos = txHistoryEntry.unshielded?.createdUtxos ?? [];
|
|
3468
|
+
const spentUtxos = txHistoryEntry.unshielded?.spentUtxos ?? [];
|
|
3469
|
+
const activity = mapTxHistoryEntryToActivity({
|
|
3470
|
+
accountId,
|
|
3471
|
+
txHistoryEntry,
|
|
3472
|
+
networkId
|
|
3473
|
+
});
|
|
3474
|
+
const address = getAddressFromUtxos(createdUtxos, spentUtxos);
|
|
3475
|
+
return {
|
|
3476
|
+
...activity,
|
|
3477
|
+
address,
|
|
3478
|
+
fee: formatFee(txHistoryEntry.fees)
|
|
3479
|
+
};
|
|
3480
|
+
};
|
|
3481
|
+
/**
|
|
3482
|
+
* Whether confirmed rows with no unshielded section are shown. They carry no
|
|
3483
|
+
* readable value or date, so they render as amount-less "unknown" / 1970 rows;
|
|
3484
|
+
* hiding them is the default and the flag restores the earlier behaviour while
|
|
3485
|
+
* the product decision is open.
|
|
3486
|
+
*/
|
|
3487
|
+
const showShieldedOnlyRows$ = (stateObservables) => stateObservables.features.selectLoadedFeatures$.pipe((0, rxjs.map)((loaded) => loaded.featureFlags.some((flag) => flag.key === require_watch.FEATURE_FLAG_MIDNIGHT_SHIELDED_ACTIVITY_ROWS)), (0, rxjs.distinctUntilChanged)());
|
|
3488
|
+
const updateActivities = (_, stateObservables, { actions, midnightWallets$ }) => midnightWallets$.pipe((0, rxjs.scan)((accumulator, wallets) => ({
|
|
3489
|
+
current: wallets,
|
|
3490
|
+
added: Object.values(wallets).filter((w) => !(w.accountId in accumulator.current))
|
|
3491
|
+
}), {
|
|
3492
|
+
current: {},
|
|
3493
|
+
added: []
|
|
3494
|
+
}), (0, rxjs.mergeMap)(({ added }) => added), (0, rxjs.mergeMap)((wallet) => (0, rxjs.combineLatest)([wallet.transactionHistory$, showShieldedOnlyRows$(stateObservables)]).pipe((0, rxjs.map)(([transactionHistory, showShieldedOnlyRows]) => ({
|
|
3495
|
+
activities: transactionHistory.filter((entry) => showShieldedOnlyRows || entryHasUnshieldedActivity(entry)).map((txHistoryEntry) => mapTxHistoryEntryToActivity({
|
|
3496
|
+
accountId: wallet.accountId,
|
|
3497
|
+
txHistoryEntry,
|
|
3498
|
+
networkId: wallet.networkId
|
|
3499
|
+
})),
|
|
3500
|
+
suppressedActivityIds: showShieldedOnlyRows ? [] : transactionHistory.filter((entry) => !entryHasUnshieldedActivity(entry)).map((entry) => entry.hash)
|
|
3501
|
+
})), (0, rxjs.mergeMap)(({ activities, suppressedActivityIds }) => [
|
|
3502
|
+
actions.activities.upsertActivities({
|
|
3503
|
+
accountId: wallet.accountId,
|
|
3504
|
+
activities
|
|
3505
|
+
}),
|
|
3506
|
+
...suppressedActivityIds.length > 0 ? [actions.activities.removeActivities({
|
|
3507
|
+
accountId: wallet.accountId,
|
|
3508
|
+
activityIds: suppressedActivityIds
|
|
3509
|
+
})] : [],
|
|
3510
|
+
actions.activities.setHasLoadedOldestEntry({
|
|
3511
|
+
accountId: wallet.accountId,
|
|
3512
|
+
hasLoadedOldestEntry: true
|
|
3513
|
+
}),
|
|
3514
|
+
actions.activities.setDesiredLoadedActivitiesCount({
|
|
3515
|
+
accountId: wallet.accountId,
|
|
3516
|
+
desiredLoadedActivitiesCount: activities.length
|
|
3517
|
+
})
|
|
3518
|
+
]), (0, rxjs.takeUntil)(midnightWallets$.pipe((0, rxjs.filter)((wallets) => !(wallet.accountId in wallets)))))));
|
|
3519
|
+
const loadActivityDetails = ({ activities: { loadActivityDetails$ } }, _, { actions, getMidnightWalletByAccountId, logger }) => loadActivityDetails$.pipe((0, rxjs.filter)(({ payload: { blockchainName } }) => blockchainName === "Midnight"), (0, rxjs.map)((action) => action.payload.activity), (0, rxjs.switchMap)(({ activityId, accountId }) => getMidnightWalletByAccountId(accountId).pipe((0, rxjs.switchMap)((wallet) => wallet.getTransactionHistoryEntryByHash(activityId).pipe((0, rxjs.map)((txHistoryEntry) => {
|
|
3520
|
+
if (!txHistoryEntry) return actions.activities.setActivityDetails({ activityDetails: void 0 });
|
|
3521
|
+
return actions.activities.setActivityDetails({ activityDetails: mapTxHistoryEntryToActivityDetail({
|
|
3522
|
+
accountId: wallet.accountId,
|
|
3523
|
+
txHistoryEntry,
|
|
3524
|
+
networkId: wallet.networkId
|
|
3525
|
+
}) });
|
|
3526
|
+
}), (0, rxjs.catchError)((error) => {
|
|
3527
|
+
logger.error("Failed to load Midnight activity details", error);
|
|
3528
|
+
return rxjs.EMPTY;
|
|
3529
|
+
}))), (0, rxjs.catchError)(() => rxjs.EMPTY))));
|
|
3530
|
+
//#endregion
|
|
3531
|
+
//#region ../../packages/module/midnight-sync/src/store/side-effects/proof-activities.ts
|
|
3532
|
+
const watchProofActivities = (_actions, _state, { actions, wasmProofActivities$ }) => wasmProofActivities$.pipe((0, rxjs.map)((activities) => actions.midnightContext.proofActivitiesUpdated(activities)));
|
|
3533
|
+
const dismissProofActivity = ({ midnightContext: { proofActivityDismissRequested$ } }, _state, { dismissWasmProofActivity }) => proofActivityDismissRequested$.pipe((0, rxjs.tap)(({ payload }) => {
|
|
3534
|
+
dismissWasmProofActivity(payload);
|
|
3535
|
+
}), (0, rxjs.ignoreElements)());
|
|
3536
|
+
//#endregion
|
|
3537
|
+
//#region ../../packages/module/midnight-sync/src/store/side-effects/proof-server-kill-switch.ts
|
|
3538
|
+
/** Persist the fallback when a selected provider is disabled or no longer
|
|
3539
|
+
* belongs to the source-controlled catalogue. Notify once per affected batch. */
|
|
3540
|
+
const migrateUnavailableProofServerSelection = (_, { midnightContext: { selectUnavailableProofServerNetworks$, selectNetworksConfig$, selectNetworksConfigFeatureFlagsOverrides$ } }, { actions }) => selectUnavailableProofServerNetworks$.pipe((0, rxjs.distinctUntilChanged)(lodash_isEqual.default), (0, rxjs.filter)((networkIds) => networkIds.length > 0), (0, rxjs.withLatestFrom)(selectNetworksConfig$, selectNetworksConfigFeatureFlagsOverrides$), (0, rxjs.mergeMap)(([networkIds, networksConfig, featureFlagsOverrides]) => (0, rxjs.from)([...networkIds.map((networkId) => actions.midnightContext.setUserNetworkConfigOverride({
|
|
3541
|
+
networkId,
|
|
3542
|
+
config: networksConfig[networkId],
|
|
3543
|
+
featureFlagsOverrides: featureFlagsOverrides[networkId] ?? {}
|
|
3544
|
+
})), actions.ui.showToast({
|
|
3545
|
+
text: "midnight.proof-server.unavailable",
|
|
3546
|
+
color: "neutral",
|
|
3547
|
+
duration: 8,
|
|
3548
|
+
leftIcon: {
|
|
3549
|
+
name: "AlertTriangle",
|
|
3550
|
+
size: 20
|
|
3551
|
+
}
|
|
3552
|
+
})])));
|
|
3553
|
+
//#endregion
|
|
3554
|
+
//#region ../../packages/module/midnight-sync/src/store/side-effects/resync.ts
|
|
3555
|
+
const withMidnightAccounts = (makeSideEffect) => (actionObservables, stateObservables, dependencies) => makeSideEffect(midnightAccounts$(stateObservables))(actionObservables, stateObservables, dependencies);
|
|
3556
|
+
const requestResyncWallet = withMidnightAccounts((midnightAccount$) => ({ midnightSync: { requestResync$ } }, _, { actions }) => (0, rxjs.merge)(requestResync$.pipe((0, rxjs.withLatestFrom)(midnightAccount$), (0, rxjs.switchMap)(([_, accounts]) => {
|
|
3557
|
+
return (0, rxjs.from)([...accounts.map(({ accountId }) => actions.sync.addSyncOperation({
|
|
3558
|
+
accountId,
|
|
3559
|
+
operation: {
|
|
3560
|
+
operationId: `${accountId}-midnight-sync`,
|
|
3561
|
+
status: "Pending",
|
|
3562
|
+
description: "sync.operation.midnight-resync",
|
|
3563
|
+
startedAt: require_time_vo.Timestamp(Date.now())
|
|
3564
|
+
}
|
|
3565
|
+
})), actions.midnightSync.resync()]);
|
|
3566
|
+
}))));
|
|
3567
|
+
const createClearWalletStateOnResync = (store) => withMidnightAccounts((midnightAccounts$) => ({ midnightSync: { resync$ } }, _, { actions, stopAllMidnightWallets, logger }) => resync$.pipe((0, rxjs.withLatestFrom)(midnightAccounts$), (0, rxjs.switchMap)(([_, midnightAccounts]) => stopAllMidnightWallets().pipe((0, rxjs.catchError)((error) => {
|
|
3568
|
+
logger.error("Midnight resync: stop failed", error);
|
|
3569
|
+
return (0, rxjs.of)(void 0);
|
|
3570
|
+
}), (0, rxjs.switchMap)(() => store.clear().pipe((0, rxjs.defaultIfEmpty)(void 0), (0, rxjs.catchError)((error) => {
|
|
3571
|
+
logger.error("Midnight resync: state wipe failed", error);
|
|
3572
|
+
return (0, rxjs.of)(void 0);
|
|
3573
|
+
}))), (0, rxjs.switchMap)(() => [...midnightAccounts.flatMap(({ accountId }) => [
|
|
3574
|
+
actions.addresses.resetAddresses({ accountId }),
|
|
3575
|
+
actions.tokens.resetAccountTokens({ accountId }),
|
|
3576
|
+
actions.activities.resetActivities({ accountId }),
|
|
3577
|
+
actions.midnightContext.resetAccountDust({ accountId })
|
|
3578
|
+
]), actions.midnightSync.restartWalletWatch()])))));
|
|
3579
|
+
/**
|
|
3580
|
+
* Side-effect that triggers a Midnight wallet resync whenever the config change
|
|
3581
|
+
* is made with a feature flag override and the wallet is unlocked.
|
|
3582
|
+
*/
|
|
3583
|
+
const resyncWalletOnConfigChangeFromFeatureFlags = withMidnightAccounts((midnightAccounts$) => (_, { appLock: { isUnlocked$ }, midnightContext: { selectCurrentNetwork$, selectNetworksConfigFeatureFlagsOverrides$ } }, { actions }) => {
|
|
3584
|
+
return selectNetworksConfigFeatureFlagsOverrides$.pipe((0, rxjs.withLatestFrom)(isUnlocked$), (0, rxjs.filter)(([_, isUnlocked]) => isUnlocked), (0, rxjs.switchMap)(() => selectCurrentNetwork$.pipe((0, rxjs.take)(1))), (0, rxjs.map)(({ config }) => config), (0, rxjs.distinctUntilChanged)(_laceio_cardano_util.deepEquals)).pipe((0, rxjs.withLatestFrom)(midnightAccounts$), (0, rxjs.switchMap)(([_, midnightAccounts]) => (0, rxjs.from)([...midnightAccounts.map(({ accountId }) => actions.sync.addSyncOperation({
|
|
3585
|
+
accountId,
|
|
3586
|
+
operation: {
|
|
3587
|
+
operationId: `${accountId}-midnight-sync`,
|
|
3588
|
+
status: "Pending",
|
|
3589
|
+
description: "sync.operation.midnight-resync",
|
|
3590
|
+
startedAt: require_time_vo.Timestamp(Date.now())
|
|
3591
|
+
}
|
|
3592
|
+
})), actions.midnightSync.resync()])));
|
|
3593
|
+
});
|
|
3594
|
+
const createDeleteWalletSideEffect = (storage) => ({ wallets: { removeWallet$ } }, { wallets: { selectAll$ } }, { stopMidnightWallet, actions, logger }) => removeWallet$.pipe((0, rxjs.withLatestFrom)(selectAll$.pipe((0, rxjs.map)((wallets) => wallets.filter(require_utils.hasMidnightAccount)))), (0, rxjs.switchMap)(([{ payload }, midnightWallets]) => {
|
|
3595
|
+
const walletId = typeof payload === "string" ? payload : payload.walletId;
|
|
3596
|
+
const targetWallet = midnightWallets.find((w) => w.walletId === walletId);
|
|
3597
|
+
if (!targetWallet) return rxjs.EMPTY;
|
|
3598
|
+
const allMidnightAccounts = targetWallet.accounts.filter(require_utils.isInMemoryMidnightAccount);
|
|
3599
|
+
return (allMidnightAccounts.length > 0 ? (0, rxjs.forkJoin)(allMidnightAccounts.map(({ accountId }) => stopMidnightWallet(accountId))) : (0, rxjs.of)([])).pipe((0, rxjs.switchMap)(() => storage.removeWhere((wallet) => wallet.walletId === walletId).pipe((0, rxjs.defaultIfEmpty)(void 0), (0, rxjs.catchError)((error) => {
|
|
3600
|
+
logger.error("Midnight delete wallet: state wipe failed", error);
|
|
3601
|
+
return (0, rxjs.of)(void 0);
|
|
3602
|
+
}))), (0, rxjs.mergeMap)(() => allMidnightAccounts.flatMap(({ accountId }) => [
|
|
3603
|
+
actions.addresses.resetAddresses({ accountId }),
|
|
3604
|
+
actions.tokens.resetAccountTokens({ accountId }),
|
|
3605
|
+
actions.activities.resetActivities({ accountId })
|
|
3606
|
+
])));
|
|
3607
|
+
}));
|
|
3608
|
+
/**
|
|
3609
|
+
* Stops one Midnight account's wallet, wipes that account's persisted SDK
|
|
3610
|
+
* state, then emits the actions that clear every redux cache the wiped state
|
|
3611
|
+
* fed. Scoped to a single account, unlike `createClearWalletStateOnResync`,
|
|
3612
|
+
* which wipes the whole chain.
|
|
3613
|
+
*
|
|
3614
|
+
* A step that errors or completes without emitting is handed to
|
|
3615
|
+
* `onStepFailure`: return an observable that emits to carry on with the next
|
|
3616
|
+
* step, or one that errors to abort the reset with that error.
|
|
3617
|
+
*/
|
|
3618
|
+
const stopAndWipeAccountState$ = ({ accountId, actions, store, stop$, onStepFailure }) => stop$.pipe((0, rxjs.take)(1), (0, rxjs.throwIfEmpty)(() => /* @__PURE__ */ new Error("Midnight account stop did not acknowledge completion")), (0, rxjs.catchError)((error) => onStepFailure("stop", error)), (0, rxjs.switchMap)(() => store.removeWhere((wallet) => wallet?.accountId === accountId).pipe((0, rxjs.throwIfEmpty)(() => /* @__PURE__ */ new Error("Midnight account storage wipe did not acknowledge completion")), (0, rxjs.catchError)((error) => onStepFailure("wipe", error)))), (0, rxjs.mergeMap)(() => [
|
|
3619
|
+
actions.addresses.resetAddresses({ accountId }),
|
|
3620
|
+
actions.tokens.resetAccountTokens({ accountId }),
|
|
3621
|
+
actions.activities.resetActivities({ accountId }),
|
|
3622
|
+
actions.midnightContext.resetAccountDust({ accountId }),
|
|
3623
|
+
actions.sync.resetAccountSyncStatus({ accountId })
|
|
3624
|
+
]));
|
|
3625
|
+
/**
|
|
3626
|
+
* The extension's per-account "reset sync state": stops and wipes the account,
|
|
3627
|
+
* then reloads the app so every engine restarts from empty state. Stop and wipe
|
|
3628
|
+
* failures are logged and the reset carries on, because the reload is what
|
|
3629
|
+
* recovers the account.
|
|
3630
|
+
*
|
|
3631
|
+
* The reload is emitted LAST, after the storage write settles: sequencing it
|
|
3632
|
+
* inside this chain (rather than firing it from a separate UI tap) is what stops
|
|
3633
|
+
* a hard reload from preempting the wipe and leaving the old SDK document to
|
|
3634
|
+
* restore from.
|
|
3635
|
+
*/
|
|
3636
|
+
const createResetSyncStateSideEffect = (store) => withMidnightAccounts((midnightAccounts$) => ({ midnightContext: { resetSyncState$ } }, _, { actions, stopMidnightWallet, logger }) => resetSyncState$.pipe((0, rxjs.withLatestFrom)(midnightAccounts$), (0, rxjs.switchMap)(([{ payload }, midnightAccounts]) => {
|
|
3637
|
+
const account = midnightAccounts.find(({ accountId }) => accountId === payload.accountId);
|
|
3638
|
+
if (!account) return rxjs.EMPTY;
|
|
3639
|
+
const { accountId } = account;
|
|
3640
|
+
return (0, rxjs.concat)(stopAndWipeAccountState$({
|
|
3641
|
+
accountId,
|
|
3642
|
+
actions,
|
|
3643
|
+
store,
|
|
3644
|
+
stop$: stopMidnightWallet(accountId),
|
|
3645
|
+
onStepFailure: (step, error) => {
|
|
3646
|
+
logger.error(`Midnight reset sync state: ${step} failed`, error);
|
|
3647
|
+
return (0, rxjs.of)(void 0);
|
|
3648
|
+
}
|
|
3649
|
+
}), (0, rxjs.of)(actions.app.reloadApplication()));
|
|
3650
|
+
})));
|
|
3651
|
+
/**
|
|
3652
|
+
* The headless per-account "reset sync state": stops and wipes the account,
|
|
3653
|
+
* then restarts that account's watcher in place, since a headless runtime has
|
|
3654
|
+
* no application to reload. The account's sync operation reads Pending while
|
|
3655
|
+
* the reset runs and Failed if a stop or wipe fails, so the caller can observe
|
|
3656
|
+
* the outcome and retry.
|
|
3657
|
+
*/
|
|
3658
|
+
const createHeadlessResetSyncStateSideEffect = (store) => withMidnightAccounts((midnightAccounts$) => ({ midnightContext: { resetSyncState$ } }, _, { actions, stopMidnightWallet, logger }) => resetSyncState$.pipe((0, rxjs.withLatestFrom)(midnightAccounts$), (0, rxjs.groupBy)(([{ payload }]) => payload.accountId), (0, rxjs.mergeMap)((requests$) => requests$.pipe((0, rxjs.exhaustMap)(([{ payload }, midnightAccounts]) => {
|
|
3659
|
+
const account = midnightAccounts.find(({ accountId }) => accountId === payload.accountId);
|
|
3660
|
+
if (!account) return rxjs.EMPTY;
|
|
3661
|
+
const { accountId } = account;
|
|
3662
|
+
const pendingOperation = () => actions.sync.addSyncOperation({
|
|
3663
|
+
accountId,
|
|
3664
|
+
operation: {
|
|
3665
|
+
operationId: `${accountId}-midnight-sync`,
|
|
3666
|
+
status: "Pending",
|
|
3667
|
+
description: "sync.operation.midnight-resync",
|
|
3668
|
+
startedAt: require_time_vo.Timestamp(Date.now())
|
|
3669
|
+
}
|
|
3670
|
+
});
|
|
3671
|
+
const stop$ = (0, rxjs.merge)((0, rxjs.of)(void 0), requests$).pipe((0, rxjs.switchMap)(() => (0, rxjs.defer)(() => stopMidnightWallet(accountId)).pipe((0, rxjs.throwIfEmpty)(() => /* @__PURE__ */ new Error("Midnight account stop did not acknowledge completion")))));
|
|
3672
|
+
return (0, rxjs.concat)((0, rxjs.of)(pendingOperation()), stopAndWipeAccountState$({
|
|
3673
|
+
accountId,
|
|
3674
|
+
actions,
|
|
3675
|
+
store,
|
|
3676
|
+
stop$,
|
|
3677
|
+
onStepFailure: (step, error) => {
|
|
3678
|
+
logger.error(`Midnight reset sync state: ${step} failed`, error);
|
|
3679
|
+
return (0, rxjs.throwError)(() => error);
|
|
3680
|
+
}
|
|
3681
|
+
}), (0, rxjs.defer)(() => (0, rxjs.of)(pendingOperation(), actions.midnightSync.restartAccountWatch({ accountId })))).pipe((0, rxjs.catchError)((error) => {
|
|
3682
|
+
logger.error("Midnight account resync failed", error);
|
|
3683
|
+
const failedAt = require_time_vo.Timestamp(Date.now());
|
|
3684
|
+
return (0, rxjs.of)(actions.sync.addSyncOperation({
|
|
3685
|
+
accountId,
|
|
3686
|
+
operation: {
|
|
3687
|
+
operationId: `${accountId}-midnight-sync`,
|
|
3688
|
+
status: "Failed",
|
|
3689
|
+
description: "sync.operation.midnight-resync",
|
|
3690
|
+
error: "sync.error.midnight-sync-failed",
|
|
3691
|
+
startedAt: failedAt,
|
|
3692
|
+
failedAt
|
|
3693
|
+
}
|
|
3694
|
+
}));
|
|
3695
|
+
}));
|
|
3696
|
+
})))));
|
|
3697
|
+
//#endregion
|
|
3698
|
+
//#region ../../packages/module/midnight-sync/src/store/side-effects/sync-failure.ts
|
|
3699
|
+
/**
|
|
3700
|
+
* Dismiss a Midnight account's sync failure once its own sync recovers.
|
|
3701
|
+
*
|
|
3702
|
+
* The `completeSyncOperation` for `${accountId}-midnight-sync` is the
|
|
3703
|
+
* "recovered" signal, whichever route got there — transparent retry, the
|
|
3704
|
+
* failure's tap-to-retry `restartWalletWatch`, or the resubscription `whileActive`
|
|
3705
|
+
* performs on unlock.
|
|
3706
|
+
*
|
|
3707
|
+
* Keyed per-account, so no lookup is needed: a completion for a sibling Midnight
|
|
3708
|
+
* account (or a Cardano/Bitcoin one) maps to a different, non-existent
|
|
3709
|
+
* MidnightSyncFailureId and no-ops, leaving a still-broken account's failure in
|
|
3710
|
+
* place until its OWN sync completes.
|
|
3711
|
+
*/
|
|
3712
|
+
const autoDismissMidnightSyncFailureOnSyncSuccess = ({ sync: { completeSyncOperation$ } }, { failures: { selectFailureById$ } }) => completeSyncOperation$.pipe((0, rxjs.map)(({ payload }) => require_watch.MidnightSyncFailureId(payload.accountId)), require_auto_dismiss_failure_on_success.autoDismissFailureOnSuccess(selectFailureById$));
|
|
3713
|
+
/**
|
|
3714
|
+
* On resume, clear the sync failure for every Midnight account.
|
|
3715
|
+
*
|
|
3716
|
+
* Complements the per-account recovery dismissal above by clearing a stale error
|
|
3717
|
+
* immediately, rather than leaving it on screen for the length of the first sync
|
|
3718
|
+
* after unlock. No restart is dispatched: `watchMidnightAccounts` ends its pipe
|
|
3719
|
+
* with `whileActive`, so resuming already resubscribes every account watcher.
|
|
3720
|
+
* Accounts with no failure are a no-op.
|
|
3721
|
+
*/
|
|
3722
|
+
const autoDismissMidnightSyncFailureOnResume = (_, { wallets: { selectAll$ }, failures: { selectFailureById$ } }, { walletResumed$ }) => walletResumed$.pipe((0, rxjs.withLatestFrom)(selectAll$), (0, rxjs.mergeMap)(([, wallets]) => (0, rxjs.from)(wallets.flatMap((wallet) => wallet.accounts).filter(require_utils.isInMemoryMidnightAccount).map((account) => require_watch.MidnightSyncFailureId(account.accountId)))), require_auto_dismiss_failure_on_success.autoDismissFailureOnSuccess(selectFailureById$));
|
|
3723
|
+
//#endregion
|
|
3724
|
+
//#region ../../packages/module/midnight-sync/src/store/side-effects/tee-attestation-progress.ts
|
|
3725
|
+
/**
|
|
3726
|
+
* Forwards attested-proving progress from the dependency-level stream into
|
|
3727
|
+
* redux, where the send-flow checklist UI reads it. Pure mapping — the
|
|
3728
|
+
* events originate inside the proving service (ADR 19).
|
|
3729
|
+
*/
|
|
3730
|
+
const watchTeeAttestationProgress = (_actionObservables, _stateObservables, { actions, teeAttestationProgress$ }) => teeAttestationProgress$.pipe((0, rxjs.map)((event) => event.type === "begin" ? actions.midnightContext.teeAttestationProgressStarted(event) : actions.midnightContext.teeAttestationProgressUpdated(event)));
|
|
3731
|
+
/**
|
|
3732
|
+
* Clears the previous run's checklist as soon as a new Midnight transaction
|
|
3733
|
+
* starts building, so a redone send never opens the
|
|
3734
|
+
* processing screen with stale step results. The attested proving service's
|
|
3735
|
+
* `reset` then rebuilds the pending checklist when verification actually
|
|
3736
|
+
* begins. The signer owns confirmation resets. Submit must not clear the
|
|
3737
|
+
* completed checklist while the transaction is being submitted.
|
|
3738
|
+
*/
|
|
3739
|
+
const clearTeeAttestationProgressOnNewTx = ({ txExecutor: { txPhaseRequested$ } }, _stateObservables, { actions }) => txPhaseRequested$.pipe((0, rxjs.filter)(({ payload: { config } }) => config.params.blockchainName === "Midnight" && config.type === "buildTx"), (0, rxjs.map)(() => actions.midnightContext.teeAttestationProgressCleared()));
|
|
3740
|
+
//#endregion
|
|
3741
|
+
//#region ../../packages/module/midnight-sync/src/store/side-effects/index.ts
|
|
3742
|
+
/**
|
|
3743
|
+
* The engine's side effects plus the ones a loadout adds over the same
|
|
3744
|
+
* persisted wallet-state storage. The engine set reads only the contracts
|
|
3745
|
+
* the engine itself depends on; a loadout decides what else it can run.
|
|
3746
|
+
*/
|
|
3747
|
+
const createInitializeSideEffects = (loadoutSideEffects) => () => [(actionObservables, stateObservables, dependencies) => {
|
|
3748
|
+
const midnightStateStorage = dependencies.createCollectionStorage({
|
|
3749
|
+
collectionId: "midnightWalletState",
|
|
3750
|
+
computeDocId: (wallet) => String(wallet.accountId)
|
|
3751
|
+
});
|
|
3752
|
+
return (0, rxjs.merge)(...[
|
|
3753
|
+
updateActivities,
|
|
3754
|
+
loadActivityDetails,
|
|
3755
|
+
createDeleteWalletSideEffect(midnightStateStorage),
|
|
3756
|
+
createClearWalletStateOnResync(midnightStateStorage),
|
|
3757
|
+
requestResyncWallet,
|
|
3758
|
+
autoDismissMidnightSyncFailureOnResume,
|
|
3759
|
+
autoDismissMidnightSyncFailureOnSyncSuccess,
|
|
3760
|
+
require_watch.watchMidnightAccounts(midnightStateStorage, require_watch.watchMidnightAccount),
|
|
3761
|
+
...loadoutSideEffects(midnightStateStorage)
|
|
3762
|
+
].map((sideEffect) => sideEffect(actionObservables, stateObservables, dependencies)));
|
|
3763
|
+
}];
|
|
3764
|
+
createInitializeSideEffects((storage) => [
|
|
3765
|
+
createResetSyncStateSideEffect(storage),
|
|
3766
|
+
resyncWalletOnConfigChangeFromFeatureFlags,
|
|
3767
|
+
migrateUnavailableProofServerSelection,
|
|
3768
|
+
watchProofActivities,
|
|
3769
|
+
dismissProofActivity,
|
|
3770
|
+
watchTeeAttestationProgress,
|
|
3771
|
+
clearTeeAttestationProgressOnNewTx
|
|
3772
|
+
]);
|
|
3773
|
+
//#endregion
|
|
3774
|
+
//#region ../../packages/module/midnight-sync/src/store/side-effects/network-config.ts
|
|
3775
|
+
/**
|
|
3776
|
+
* Applies a loadout's supported networks and default proof servers right
|
|
3777
|
+
* after the first action the store handles, which redux-persist dispatches
|
|
3778
|
+
* while the store is created. Both therefore hold before the store is handed
|
|
3779
|
+
* out and before any side effect starts: a side effect would land a tick
|
|
3780
|
+
* later, and a network selected in between would be checked against the
|
|
3781
|
+
* contract's full list.
|
|
3782
|
+
*/
|
|
3783
|
+
const createApplyNetworkDefaultsMiddleware = ({ supportedNetworkIds, defaultProofServers }) => {
|
|
3784
|
+
const { setDefaultProofServers, setSupportedNetworksIds } = require_slice.midnightContextActions.midnightContext;
|
|
3785
|
+
return (store) => (next) => {
|
|
3786
|
+
let pending = [...supportedNetworkIds ? [setSupportedNetworksIds(supportedNetworkIds)] : [], ...defaultProofServers ? [setDefaultProofServers(defaultProofServers)] : []];
|
|
3787
|
+
return (action) => {
|
|
3788
|
+
const result = next(action);
|
|
3789
|
+
const defaults = pending;
|
|
3790
|
+
pending = [];
|
|
3791
|
+
for (const defaultAction of defaults) store.dispatch(defaultAction);
|
|
3792
|
+
return result;
|
|
3793
|
+
};
|
|
3794
|
+
};
|
|
3795
|
+
};
|
|
3796
|
+
/**
|
|
3797
|
+
* Applies a loadout's endpoint choices as user overrides on startup, so they
|
|
3798
|
+
* take precedence over the contract defaults and the feature-flag values
|
|
3799
|
+
* without a settings UI to enter them through.
|
|
3800
|
+
*/
|
|
3801
|
+
const createApplyNetworkConfigOverrides = (overrides) => (_, { midnightContext: { selectNetworksConfig$, selectNetworksConfigFeatureFlagsOverrides$ } }, { actions }) => (0, rxjs.zip)(selectNetworksConfig$.pipe((0, rxjs.take)(1)), selectNetworksConfigFeatureFlagsOverrides$.pipe((0, rxjs.take)(1))).pipe((0, rxjs.mergeMap)(([networksConfig, featureFlagsOverrides]) => Object.entries(overrides).map(([networkId, override]) => actions.midnightContext.setUserNetworkConfigOverride({
|
|
3802
|
+
networkId,
|
|
3803
|
+
config: {
|
|
3804
|
+
...networksConfig[networkId],
|
|
3805
|
+
...override
|
|
3806
|
+
},
|
|
3807
|
+
featureFlagsOverrides: featureFlagsOverrides[networkId]
|
|
3808
|
+
}))));
|
|
3809
|
+
//#endregion
|
|
3810
|
+
//#region ../../packages/module/midnight-sync/src/store/sdk-init.ts
|
|
3811
|
+
const assertDefaultTestnetConfigured = (config) => {
|
|
3812
|
+
const networkId = config?.defaultMidnightTestnetNetworkId;
|
|
3813
|
+
if (!networkId || !require_const.MidnightSDKTestNetworkId.includes(networkId)) throw new Error(`createLaceWallet needs config.defaultMidnightTestnetNetworkId, the Midnight testnet a wallet starts on: one of ${require_const.MidnightSDKTestNetworkId.join(", ")}; got ${String(networkId)}`);
|
|
3814
|
+
};
|
|
3815
|
+
const createSdkStoreInit = ({ auth, batchUpdates, createAttestedProver, networks = {}, supportedNetworkIds, defaultProofServers }) => {
|
|
3816
|
+
const initializeSideEffects = createInitializeSideEffects((storage) => [
|
|
3817
|
+
registerMidnightBlockchainNetworks,
|
|
3818
|
+
createApplyNetworkConfigOverrides(networks),
|
|
3819
|
+
createHeadlessResetSyncStateSideEffect(storage)
|
|
3820
|
+
]);
|
|
3821
|
+
const initializeDependencies = createMidnightSideEffectDependencies({
|
|
3822
|
+
batchUpdates,
|
|
3823
|
+
createAttestedProver
|
|
3824
|
+
});
|
|
3825
|
+
return (props, dependencies) => {
|
|
3826
|
+
assertDefaultTestnetConfigured(props.runtime.config);
|
|
3827
|
+
return {
|
|
3828
|
+
middleware: [createApplyNetworkDefaultsMiddleware({
|
|
3829
|
+
supportedNetworkIds,
|
|
3830
|
+
defaultProofServers
|
|
3831
|
+
})],
|
|
3832
|
+
sideEffects: initializeSideEffects(props, dependencies),
|
|
3833
|
+
sideEffectDependencies: {
|
|
3834
|
+
...initializeDependencies(props, dependencies),
|
|
3835
|
+
...auth
|
|
3836
|
+
}
|
|
3837
|
+
};
|
|
3838
|
+
};
|
|
3839
|
+
};
|
|
3840
|
+
//#endregion
|
|
3841
|
+
exports.createSdkStoreInit = createSdkStoreInit;
|