@laceio/sdk 0.1.1 → 0.1.2-canary.0
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-CCjOn7NA.cjs} +42 -0
- package/dist/{TransactionBuilder-V6aLx4SV.js → TransactionBuilder-CIzdw18M.js} +1 -1
- 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 +16956 -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-CCjiakoy.cjs} +6 -6
- package/dist/{delegation-tx-builder-CGVqlaFE.js → delegation-tx-builder-DZFjHDS8.js} +5 -5
- package/dist/{deregistration-tx-builder-B-CrUyX6.js → deregistration-tx-builder-Bf6xAYp4.js} +5 -5
- package/dist/{deregistration-tx-builder-DZGwB4cz.cjs → deregistration-tx-builder-CQP35yex.cjs} +6 -6
- 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-BDbTDZmD.js → earn-rewards-tx-builder-Bsga3yFb.js} +5 -5
- package/dist/{earn-rewards-tx-builder-D5sUT5v8.cjs → earn-rewards-tx-builder-GuxofYns.cjs} +6 -6
- 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 +86273 -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 +37496 -10033
- 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-8v_n8boO.js +1177 -0
- 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-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-CuW7rHNA.js +3584 -0
- package/dist/{init-CFYsq82V.js → init-CyAY4Lzl.js} +1 -1
- package/dist/init-Cz0rz5fU.cjs +3585 -0
- 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-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-DrRdf5sZ.cjs +1176 -0
- 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-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-B1nDUWqy.js +995 -0
- package/dist/modules-cardano-BYeYHrRm.cjs +1108 -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-BpEMSti4.cjs → vote-delegation-tx-builder-BUg1S2Ep.cjs} +6 -6
- package/dist/{vote-delegation-tx-builder-CmKv6GoG.js → vote-delegation-tx-builder-C6FiS7zI.js} +5 -5
- 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
package/dist/midnight.js
ADDED
|
@@ -0,0 +1,1352 @@
|
|
|
1
|
+
import { r as __exportAll } from "./rolldown-runtime-OvD0k9op.js";
|
|
2
|
+
import "./_web-crypto-random-bytes-Bo-GTcRS.js";
|
|
3
|
+
import { n as import_buffer, r as init__polyfill_buffer_patch } from "./_polyfill-buffer-patch-yNxN4d5E.js";
|
|
4
|
+
import "./libsodium-wrappers-BhbOA8dQ.js";
|
|
5
|
+
import "./codecs-Dc1Krpbt.js";
|
|
6
|
+
import "./util-Cp5cZkfK.js";
|
|
7
|
+
import { t as ByteArray } from "./bytes.vo-BB7_4JK6.js";
|
|
8
|
+
import { A as ContractName, C as walletRepoStoreContract, E as featureStoreContract, M as WalletId, O as combineStore, S as WalletType, T as failuresStoreContract, _ as walletActiveStateDependencyContract, a as createInMemoryWalletEntity, b as addressesStoreContract, c as createLaceWallet, i as createBlockchainWalletEntity, j as ModuleName, k as createMixin, l as signerFactoryAddonContract, n as sdk_default$1, o as inMemoryIntegrationAddonContract, r as sdk_default, s as AuthSecret, t as sdk_default$2, v as tokensStoreContract, w as networkStoreContract, x as activitiesStoreContract, y as syncStoreContract } from "./sdk-Cb-gZnS9.js";
|
|
9
|
+
import { s as Timestamp } from "./time.vo-tNheinXm.js";
|
|
10
|
+
import { t as BigNumber } from "./bignum.vo-CEXOIew0.js";
|
|
11
|
+
import { n as Ok, t as Err } from "./asyncoption-CruEYOBI.js";
|
|
12
|
+
import { t as createPasskeyKeySource } from "./key-source-B08HukZg.js";
|
|
13
|
+
import { a as inferStoreContext, i as inferModuleContext, n as combineContracts, r as inferContractContext } from "./store-DuBG8qh5.js";
|
|
14
|
+
import { t as FEATURE_FLAG_NETWORK_TYPE } from "./const-CjmfjBP3.js";
|
|
15
|
+
import { t as AccountId } from "./account-id.vo-OPz2v-JZ.js";
|
|
16
|
+
import "./slice-DBpJ2QGf.js";
|
|
17
|
+
import "./retry-config-Dmgt28wM.js";
|
|
18
|
+
import { t as ActivityType } from "./activity-type-GsJGWs-3.js";
|
|
19
|
+
import { t as TokenId } from "./token-id.vo-Bvwhr3ZE.js";
|
|
20
|
+
import { c as MidnightSDKNetworkIds, d as NIGHT_TOKEN_ID, g as MidnightNetworkId, m as defaultTxTtlLength, s as MidnightSDKNetworkId, v as TEMENOS_PROOF_SERVER_MODES, y as assertProofServerRouting } from "./const-D0CbQlo4.js";
|
|
21
|
+
import { t as MidnightAccountId } from "./midnight-account-id.vo-DjCAGcqc.js";
|
|
22
|
+
import { i as midnightContextSelectors, n as midnightContextActions } from "./slice-oWnc7YVD.js";
|
|
23
|
+
import { c as toUnshieldedTokenType, i as fromUnshieldedTokenType, s as isInMemoryMidnightAccount } from "./utils-DFwzEvbv.js";
|
|
24
|
+
import { a as AttestationError, ju as FEATURE_FLAG_MIDNIGHT_UNSHIELDED, ku as FEATURE_FLAG_MIDNIGHT, l as createProvingProviderFromCircuits, t as midnightDustBalances } from "./watch-CUEvcP-V.js";
|
|
25
|
+
import { ReplaySubject, catchError, combineLatest, concat, defaultIfEmpty, defer, distinctUntilChanged, filter, finalize, firstValueFrom, from, ignoreElements, map, of, scan, share, skipWhile, startWith, switchMap, take, tap, throwError, timeout, timer, withLatestFrom } from "rxjs";
|
|
26
|
+
import { createAction } from "@reduxjs/toolkit";
|
|
27
|
+
import { dummyLogger } from "ts-log";
|
|
28
|
+
import { DustAddress, MidnightBech32m, ShieldedAddress, UnshieldedAddress } from "@midnightntwrk/wallet-sdk-address-format";
|
|
29
|
+
import inRange from "lodash/inRange.js";
|
|
30
|
+
import toLower from "lodash/toLower.js";
|
|
31
|
+
import * as ledger from "@midnight-ntwrk/ledger-v8";
|
|
32
|
+
import { addressFromKey } from "@midnight-ntwrk/ledger-v8";
|
|
33
|
+
//#region src/create-midnight-accounts.ts
|
|
34
|
+
/**
|
|
35
|
+
* Derives a Midnight account index using the entity's encrypted recovery material.
|
|
36
|
+
* Indexes must be integers in `[0, 2³¹)`. Omitted networks use the integration's
|
|
37
|
+
* defaults. Rejects duplicate accounts, an entity with neither a Midnight
|
|
38
|
+
* seed nor a recovery phrase (a passkey entity), unavailable integration and
|
|
39
|
+
* decryption or derivation errors. Other blockchain accounts are preserved.
|
|
40
|
+
*
|
|
41
|
+
* Returns an updated entity without dispatching. For a new entity, dispatch
|
|
42
|
+
* `wallets.addWallet`; for an existing one, dispatch `wallets.updateWallet`
|
|
43
|
+
* with its updated `accounts` and `blockchainSpecific`.
|
|
44
|
+
*/
|
|
45
|
+
const createMidnightAccounts = async (wallet, props) => {
|
|
46
|
+
if (!Number.isInteger(props.accountIndex) || props.accountIndex < 0 || props.accountIndex >= 2 ** 31) throw new RangeError("Midnight account index must be an integer in [0, 2³¹)");
|
|
47
|
+
if (!props.wallet.blockchainSpecific.Midnight?.encryptedSeed && !props.wallet.encryptedRecoveryPhrase) throw new Error("The entity holds no Midnight seed and no recovery phrase: derive the accounts of a passkey entity with createMidnightPasskeyWalletEntity({ accounts })");
|
|
48
|
+
const integration = (await wallet._loadModules("addons.loadInMemoryWalletIntegration")).find((candidate) => candidate.blockchainName === "Midnight");
|
|
49
|
+
if (!integration) throw new Error("Midnight integration is not loaded");
|
|
50
|
+
const { wallet: updated } = await integration.addAccounts(props, { logger: dummyLogger });
|
|
51
|
+
const accountIds = updated.accounts.map((account) => account.accountId);
|
|
52
|
+
if (new Set(accountIds).size !== accountIds.length) throw new Error("Midnight account already exists");
|
|
53
|
+
return updated;
|
|
54
|
+
};
|
|
55
|
+
//#endregion
|
|
56
|
+
//#region ../../packages/contract/midnight-context/src/store/index.ts
|
|
57
|
+
var store_default = inferStoreContext({
|
|
58
|
+
load: async () => import("./init-BpHTq2R5.js"),
|
|
59
|
+
context: {
|
|
60
|
+
actions: midnightContextActions,
|
|
61
|
+
selectors: midnightContextSelectors
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
//#endregion
|
|
65
|
+
//#region ../../packages/contract/midnight-context/src/contract.ts
|
|
66
|
+
const midnightContextStoreContract = inferContractContext({
|
|
67
|
+
name: ContractName("midnight-context-store"),
|
|
68
|
+
instance: "exactly-one",
|
|
69
|
+
contractType: "store",
|
|
70
|
+
dependsOn: combineContracts([networkStoreContract, featureStoreContract]),
|
|
71
|
+
mixin: createMixin((laceModule) => ({ store: combineStore(laceModule, store_default) }))
|
|
72
|
+
});
|
|
73
|
+
const midnightDependencyContract = inferContractContext({
|
|
74
|
+
contractType: "sideEffectDependency",
|
|
75
|
+
name: ContractName("midnight-dependency"),
|
|
76
|
+
instance: "exactly-one"
|
|
77
|
+
});
|
|
78
|
+
//#endregion
|
|
79
|
+
//#region ../../packages/contract/midnight-context/src/midnight-engine-addon.ts
|
|
80
|
+
/**
|
|
81
|
+
* Engine access for code outside the store, such as the SDK's Midnight
|
|
82
|
+
* helpers. Implemented by the headless Midnight engine module only.
|
|
83
|
+
*/
|
|
84
|
+
const midnightEngineAddonContract = inferContractContext({
|
|
85
|
+
name: ContractName("midnight-engine-addon"),
|
|
86
|
+
instance: "exactly-one",
|
|
87
|
+
contractType: "addon",
|
|
88
|
+
provides: { addons: ["loadMidnightEngine"] }
|
|
89
|
+
});
|
|
90
|
+
//#endregion
|
|
91
|
+
//#region ../../packages/contract/midnight-context/src/dust-utils.ts
|
|
92
|
+
/**
|
|
93
|
+
* Determines the designation target type based on NIGHT coin registration and dust balance.
|
|
94
|
+
*
|
|
95
|
+
* TODO: Update when SDK supports distinguishing self vs external designation.
|
|
96
|
+
* Currently, the SDK's `registeredForDustGeneration` flag only indicates that NIGHT is
|
|
97
|
+
* participating in dust generation, but does not specify the target dust address.
|
|
98
|
+
* Until SDK provides this information, we treat all designation as 'self'.
|
|
99
|
+
*
|
|
100
|
+
* @returns 'self' when user has designation (registered NIGHT or dust balance), 'none' otherwise.
|
|
101
|
+
* Note: 'external' is not returned until SDK supports proper detection.
|
|
102
|
+
*/
|
|
103
|
+
const getDesignationTargetType = (coins, currentDustValue) => {
|
|
104
|
+
return coins.some((coin) => coin.registeredForDustGeneration === true) || currentDustValue > 0n ? "self" : "none";
|
|
105
|
+
};
|
|
106
|
+
const TOKEN_FORBIDDEN_NAMES = [
|
|
107
|
+
"dust",
|
|
108
|
+
"lace",
|
|
109
|
+
"midnight",
|
|
110
|
+
"tdust",
|
|
111
|
+
"night",
|
|
112
|
+
"tnight"
|
|
113
|
+
];
|
|
114
|
+
/** Checks reserved and additional excluded names case-insensitively; trim input first. */
|
|
115
|
+
const isForbiddenTokenName = (name, extraExcludedTokenNames = []) => [...TOKEN_FORBIDDEN_NAMES, ...extraExcludedTokenNames.map(toLower)].includes(toLower(name));
|
|
116
|
+
/** Checks case-insensitive display-name collisions; omit the current token from the list. */
|
|
117
|
+
const isTakenTokenName = (name, takenTokenNames = []) => takenTokenNames.map(toLower).includes(toLower(name));
|
|
118
|
+
const createTokenNameValidator = (minLength, maxLength) => (name, excludedNames = []) => {
|
|
119
|
+
const isInvalidNameLength = !inRange(name.trim().length, minLength, maxLength + 1);
|
|
120
|
+
return !(isForbiddenTokenName(name, excludedNames) || isInvalidNameLength);
|
|
121
|
+
};
|
|
122
|
+
/** Validates display-name length and reserved names; trim before validating and saving. */
|
|
123
|
+
const isTokenFullNameValid = createTokenNameValidator(1, 30);
|
|
124
|
+
/** Validates ticker length and reserved names; trim before validating and saving. */
|
|
125
|
+
const isTokenShortNameValid = createTokenNameValidator(1, 4);
|
|
126
|
+
/** Direct import of this is an anti-pattern. OK for tests. */
|
|
127
|
+
const midnightSyncActions = { midnightSync: {
|
|
128
|
+
requestResync: createAction("midnight/requestResync"),
|
|
129
|
+
resync: createAction("midnight/resync"),
|
|
130
|
+
restartWalletWatch: createAction("midnight/restartWalletWatch"),
|
|
131
|
+
restartAccountWatch: createAction("midnight/restartAccountWatch")
|
|
132
|
+
} };
|
|
133
|
+
//#endregion
|
|
134
|
+
//#region ../../packages/module/midnight-sync/src/store/prepare-midnight-tx.ts
|
|
135
|
+
const constructDustDesignationTransaction = ({ address, networkId, nightUtxos, nightVerifyingKey, ttl = new Date(Date.now() + defaultTxTtlLength), allowFeePayment }) => {
|
|
136
|
+
const parsedAddress = MidnightBech32m.parse(address);
|
|
137
|
+
const receiverData = DustAddress.codec.decode(networkId, parsedAddress).data;
|
|
138
|
+
const currentTime = /* @__PURE__ */ new Date();
|
|
139
|
+
const intent = ledger.Intent.new(ttl);
|
|
140
|
+
const totalNightValue = nightUtxos.map(({ utxo: { value } }) => BigNumber.valueOf(value)).reduce((total, value) => total + value, 0n);
|
|
141
|
+
const inputs = nightUtxos.map(({ utxo }) => ({
|
|
142
|
+
...utxo,
|
|
143
|
+
owner: nightVerifyingKey
|
|
144
|
+
}));
|
|
145
|
+
const outputs = inputs.map((input) => ({
|
|
146
|
+
owner: ledger.addressFromKey(nightVerifyingKey),
|
|
147
|
+
type: input.type,
|
|
148
|
+
value: input.value
|
|
149
|
+
}));
|
|
150
|
+
intent.guaranteedUnshieldedOffer = ledger.UnshieldedOffer.new(inputs, outputs, []);
|
|
151
|
+
const dustRegistration = new ledger.DustRegistration("signature", nightVerifyingKey, receiverData, allowFeePayment ?? totalNightValue);
|
|
152
|
+
intent.dustActions = new ledger.DustActions("signature", "pre-proof", currentTime, [], [dustRegistration]);
|
|
153
|
+
return ledger.Transaction.fromParts(networkId, void 0, void 0, intent);
|
|
154
|
+
};
|
|
155
|
+
const constructUnshieldedTransaction = ({ networkId, transfers, ttl = new Date(Date.now() + defaultTxTtlLength) }) => {
|
|
156
|
+
const intent = ledger.Intent.new(ttl);
|
|
157
|
+
const outputs = transfers.map(({ address, amount, tokenId }) => ({
|
|
158
|
+
value: amount,
|
|
159
|
+
owner: UnshieldedAddress.codec.decode(networkId, MidnightBech32m.parse(address)).data.toString("hex"),
|
|
160
|
+
type: tokenId
|
|
161
|
+
}));
|
|
162
|
+
intent.guaranteedUnshieldedOffer = ledger.UnshieldedOffer.new([], outputs, []);
|
|
163
|
+
return ledger.Transaction.fromParts(networkId, void 0, void 0, intent);
|
|
164
|
+
};
|
|
165
|
+
const constructShieldedTransaction = ({ networkId, transfers }) => {
|
|
166
|
+
const toOffer = ({ address, amount, tokenId }) => {
|
|
167
|
+
const decodedAddress = ShieldedAddress.codec.decode(networkId, MidnightBech32m.parse(address));
|
|
168
|
+
const output = ledger.ZswapOutput.new(ledger.createShieldedCoinInfo(tokenId, amount), 0, decodedAddress.coinPublicKey.toHexString(), decodedAddress.encryptionPublicKey.toHexString());
|
|
169
|
+
return ledger.ZswapOffer.fromOutput(output, tokenId, amount);
|
|
170
|
+
};
|
|
171
|
+
const [firstTransfer, ...remainingTransfers] = transfers;
|
|
172
|
+
if (!firstTransfer) throw new Error("At least one token transfer is required");
|
|
173
|
+
const offer = remainingTransfers.map(toOffer).reduce((merged, singleton) => merged.merge(singleton), toOffer(firstTransfer));
|
|
174
|
+
return ledger.Transaction.fromParts(networkId, offer);
|
|
175
|
+
};
|
|
176
|
+
/** Normalize token-state IDs and reject a batch before any engine operation. */
|
|
177
|
+
const normalizeMidnightTransfers = (networkId, kind, outputs) => {
|
|
178
|
+
if (kind !== "shielded" && kind !== "unshielded") throw new Error("Unsupported Midnight transfer kind");
|
|
179
|
+
if (outputs.length === 0) throw new Error("At least one token transfer is required");
|
|
180
|
+
return outputs.map(({ to, tokenId, amount }) => {
|
|
181
|
+
if (typeof amount !== "bigint" || amount <= 0n) throw new Error("Transfer amount must be a positive bigint");
|
|
182
|
+
const prefix = `unshielded-${networkId}`;
|
|
183
|
+
if (kind === "unshielded" && !tokenId.startsWith(prefix)) throw new Error("Unshielded token ID must match the transfer kind and network");
|
|
184
|
+
const raw = kind === "unshielded" ? fromUnshieldedTokenType(tokenId, networkId) : tokenId;
|
|
185
|
+
if (!/^[0-9a-f]{64}$/.test(raw)) throw new Error("Invalid token ID or token-kind mismatch");
|
|
186
|
+
const parsed = MidnightBech32m.parse(to);
|
|
187
|
+
if (kind === "shielded") ShieldedAddress.codec.decode(networkId, parsed);
|
|
188
|
+
else UnshieldedAddress.codec.decode(networkId, parsed);
|
|
189
|
+
return {
|
|
190
|
+
address: to,
|
|
191
|
+
tokenId: TokenId(raw),
|
|
192
|
+
amount
|
|
193
|
+
};
|
|
194
|
+
});
|
|
195
|
+
};
|
|
196
|
+
/** Keep designation's zero-fee exception identical in headless and UI preparation. */
|
|
197
|
+
const estimatePreparedMidnightFee = (wallet, tx, { isDustDesignation, dustBalance, areKeysAvailable }) => {
|
|
198
|
+
if (isDustDesignation && dustBalance === 0n) return of(0n);
|
|
199
|
+
return areKeysAvailable ? wallet.estimateTransactionFee(tx, { currentTime: /* @__PURE__ */ new Date() }) : wallet.calculateTransactionFee(tx);
|
|
200
|
+
};
|
|
201
|
+
//#endregion
|
|
202
|
+
//#region ../../packages/lib/vendor/src/temenos-attested-prover.ts
|
|
203
|
+
var TemenosAttestationError = class extends AttestationError {
|
|
204
|
+
constructor(phase, checkId) {
|
|
205
|
+
super("temenos", phase === "obtain-evidence" ? "evidence" : phase === "fetch-expected-values" ? "policy" : phase === "bind-channel" ? "channel" : "appraisal", checkId ? `Temenos attestation failed: check "${checkId}" of phase "${phase}"` : `Temenos attestation failed at phase "${phase}"`);
|
|
206
|
+
this.phase = phase;
|
|
207
|
+
this.checkId = checkId;
|
|
208
|
+
this.name = "TemenosAttestationError";
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
/**
|
|
212
|
+
* `pointerContractAddress` is the one on-chain constant: the pointer's
|
|
213
|
+
* `current` cell names the attestation ledger, so a ledger redeploy is a
|
|
214
|
+
* pointer update, not a Lace release. All Temenos deployments register on the
|
|
215
|
+
* single preprod pointer, whatever network the proof server serves, so this
|
|
216
|
+
* stays on preprod on every network. The caller resolves the ledger
|
|
217
|
+
* indexer from Lace configuration at the start of each attestation run.
|
|
218
|
+
*
|
|
219
|
+
* `wardenTlsCertificate` is empty by design: a browser context cannot pin
|
|
220
|
+
* the transport certificate, so the Warden is reached over public WebPKI
|
|
221
|
+
* TLS — its verdict is defense-in-depth on top of the local checks, not a
|
|
222
|
+
* trust root.
|
|
223
|
+
*/
|
|
224
|
+
const SHARED_TEMENOS_DEPLOYMENT = {
|
|
225
|
+
pointerContractAddress: "a58974f1cacda177edfea3bdc76c1cd48d5e3107b9a543b9d65cee6b454c9122",
|
|
226
|
+
wardenUrl: "https://warden.wastedp.io",
|
|
227
|
+
wardenTlsCertificate: ""
|
|
228
|
+
};
|
|
229
|
+
const TEMENOS_PREPROD_DEPLOYMENT = {
|
|
230
|
+
...SHARED_TEMENOS_DEPLOYMENT,
|
|
231
|
+
proofServerApiUrl: "https://api.proofserver.wastedp.io",
|
|
232
|
+
attestationHost: "attestation.proofserver.wastedp.io",
|
|
233
|
+
akxServerUrl: "https://attestation.proofserver.wastedp.io/tee_attestation",
|
|
234
|
+
applicationId: "afe48970b7083e1b2855acce95a488e93a7c257a34f6275e77ac26f79ac7ad05"
|
|
235
|
+
};
|
|
236
|
+
/**
|
|
237
|
+
* Attestation parameters per network, matching `TEMENOS_PROOF_SERVER_MODES`
|
|
238
|
+
* entry for entry. Values are build-baked and reviewed like code; the
|
|
239
|
+
* persisted mode carries only the URL, so nothing here can be injected via
|
|
240
|
+
* feature-flag payloads.
|
|
241
|
+
*/
|
|
242
|
+
const TEMENOS_ATTESTATION_CONFIGS = {
|
|
243
|
+
mainnet: {
|
|
244
|
+
...SHARED_TEMENOS_DEPLOYMENT,
|
|
245
|
+
proofServerApiUrl: "https://api.proofserver.mainnet.wastedp.io",
|
|
246
|
+
attestationHost: "attestation.proofserver.mainnet.wastedp.io",
|
|
247
|
+
akxServerUrl: "https://attestation.proofserver.mainnet.wastedp.io/tee_attestation",
|
|
248
|
+
applicationId: "70402462424c122c65e2d3d2312757face3974940c9ac5d09249b61028350427"
|
|
249
|
+
},
|
|
250
|
+
preprod: TEMENOS_PREPROD_DEPLOYMENT,
|
|
251
|
+
preview: {
|
|
252
|
+
...SHARED_TEMENOS_DEPLOYMENT,
|
|
253
|
+
proofServerApiUrl: "https://api.proofserver.preview.wastedp.io",
|
|
254
|
+
attestationHost: "attestation.proofserver.preview.wastedp.io",
|
|
255
|
+
akxServerUrl: "https://attestation.proofserver.preview.wastedp.io/tee_attestation",
|
|
256
|
+
applicationId: "b294b8879607f7d0f5cca3808a4b64aab7992de2a73d1e55dbafb091efca25f2"
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
for (const [networkId, mode] of Object.entries(TEMENOS_PROOF_SERVER_MODES)) {
|
|
260
|
+
if (!mode) continue;
|
|
261
|
+
if (TEMENOS_ATTESTATION_CONFIGS[networkId]?.proofServerApiUrl !== mode.url) throw new Error(`TEMENOS_PROOF_SERVER_MODES[${networkId}] ("${mode.url}") has no matching entry in TEMENOS_ATTESTATION_CONFIGS`);
|
|
262
|
+
}
|
|
263
|
+
/** temenos-spec phases 1–5 of the AKX flow, in execution order. */
|
|
264
|
+
const TEMENOS_ATTESTATION_PHASES = [
|
|
265
|
+
"obtain-evidence",
|
|
266
|
+
"fetch-expected-values",
|
|
267
|
+
"verify-locally",
|
|
268
|
+
"warden-verify",
|
|
269
|
+
"bind-channel"
|
|
270
|
+
];
|
|
271
|
+
const PHASE_MAP = {
|
|
272
|
+
"obtain-evidence": "obtain-evidence",
|
|
273
|
+
"fetch-expected-values": "fetch-expected-values",
|
|
274
|
+
"verify-locally": "verify-locally",
|
|
275
|
+
"warden-verify": "warden-verify",
|
|
276
|
+
"bind-channel": "bind-channel"
|
|
277
|
+
};
|
|
278
|
+
/**
|
|
279
|
+
* `nonce-freshness` belongs to the library's SPKI-pin flow, which Lace never
|
|
280
|
+
* runs (the AKX evidence provider always yields epoch-key evidence) — it has
|
|
281
|
+
* no contract ID, so its events are dropped rather than mislabeled.
|
|
282
|
+
*/
|
|
283
|
+
const mapCheckId = (id) => id === "nonce-freshness" ? void 0 : id;
|
|
284
|
+
const mapPhaseEvent = (event) => {
|
|
285
|
+
if (event.status === "check") {
|
|
286
|
+
const id = mapCheckId(event.check.id);
|
|
287
|
+
if (!id) return void 0;
|
|
288
|
+
return {
|
|
289
|
+
type: "check",
|
|
290
|
+
check: {
|
|
291
|
+
id,
|
|
292
|
+
status: event.check.status,
|
|
293
|
+
detail: event.check.detail
|
|
294
|
+
}
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
if (event.phase === "prove") return void 0;
|
|
298
|
+
const phase = PHASE_MAP[event.phase];
|
|
299
|
+
switch (event.status) {
|
|
300
|
+
case "started": return {
|
|
301
|
+
type: "phase",
|
|
302
|
+
phase,
|
|
303
|
+
status: "started"
|
|
304
|
+
};
|
|
305
|
+
case "completed": return {
|
|
306
|
+
type: "phase",
|
|
307
|
+
phase,
|
|
308
|
+
status: "completed",
|
|
309
|
+
...event.detail === void 0 ? {} : { detail: event.detail }
|
|
310
|
+
};
|
|
311
|
+
case "failed": return {
|
|
312
|
+
type: "phase",
|
|
313
|
+
phase,
|
|
314
|
+
status: "failed",
|
|
315
|
+
detail: event.error.message
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
const toTemenosAttestationError = (error, fallbackPhase, { LocalCheckFailedError, AttestationVerificationError }) => {
|
|
320
|
+
const mapped = error instanceof LocalCheckFailedError ? new TemenosAttestationError("verify-locally", mapCheckId(error.checkId)) : error instanceof AttestationVerificationError ? new TemenosAttestationError(error.phase === "prove" ? fallbackPhase : PHASE_MAP[error.phase]) : new TemenosAttestationError(fallbackPhase);
|
|
321
|
+
mapped.cause = error;
|
|
322
|
+
return mapped;
|
|
323
|
+
};
|
|
324
|
+
/**
|
|
325
|
+
* `/prove` payloads travel as AEAD records tunneled through the AKX channel.
|
|
326
|
+
* The enclave proxy forwards to `/prove` only, so the session offers nothing
|
|
327
|
+
* else: the public API endpoint is never contacted from this flow.
|
|
328
|
+
*/
|
|
329
|
+
const createTunneledSession = (session) => ({
|
|
330
|
+
prove: async (payload) => {
|
|
331
|
+
const response = await session.prove({ body: payload });
|
|
332
|
+
if (response.status !== 200) throw new Error(`Proof server returned ${response.status} through the attested channel`);
|
|
333
|
+
return response.body;
|
|
334
|
+
},
|
|
335
|
+
close: async () => session.close()
|
|
336
|
+
});
|
|
337
|
+
/**
|
|
338
|
+
* {@link createTemenosAttestedProver} with a deployment override that replaces
|
|
339
|
+
* the baked deployment and skips its proof-server URL match. No public entry
|
|
340
|
+
* re-exports it; only tests driving the verifier library's mock fixtures pass
|
|
341
|
+
* the override.
|
|
342
|
+
*
|
|
343
|
+
* @internal
|
|
344
|
+
*/
|
|
345
|
+
const createTemenosAttestedProverWith = ({ networkId, proofServerApiUrl, trustRoots, getLedgerIndexerUrl, verifier }, testSeam) => {
|
|
346
|
+
const baked = TEMENOS_ATTESTATION_CONFIGS[networkId];
|
|
347
|
+
const deployment = testSeam?.config ?? (baked?.proofServerApiUrl === proofServerApiUrl ? baked : void 0);
|
|
348
|
+
if (!deployment) throw new Error(`No baked Temenos attestation config on ${networkId} for proof server "${proofServerApiUrl}"`);
|
|
349
|
+
if (!trustRoots?.amdRootCertificates?.length || trustRoots.amdRootCertificates.some((root) => root.trim().length === 0)) throw new AttestationError("temenos", "policy", "Temenos requires explicit AMD trust roots");
|
|
350
|
+
const amdRootCertificates = [...trustRoots.amdRootCertificates];
|
|
351
|
+
return {
|
|
352
|
+
id: "temenos",
|
|
353
|
+
operations: ["prove"],
|
|
354
|
+
phases: TEMENOS_ATTESTATION_PHASES,
|
|
355
|
+
establishAttestedSession: async (onEvent, signal) => {
|
|
356
|
+
signal?.throwIfAborted();
|
|
357
|
+
const config = {
|
|
358
|
+
...deployment,
|
|
359
|
+
amdRootCertificates,
|
|
360
|
+
indexerUrl: await getLedgerIndexerUrl()
|
|
361
|
+
};
|
|
362
|
+
const operationVerifier = verifier.createVerifier(config, signal);
|
|
363
|
+
let currentPhase = "obtain-evidence";
|
|
364
|
+
try {
|
|
365
|
+
return createTunneledSession(await operationVerifier.establishVerifiedSession((event) => {
|
|
366
|
+
if (event.status === "started") signal?.throwIfAborted();
|
|
367
|
+
if (event.status === "started" && event.phase !== "prove") currentPhase = PHASE_MAP[event.phase];
|
|
368
|
+
const mapped = mapPhaseEvent(event);
|
|
369
|
+
if (mapped) onEvent(mapped);
|
|
370
|
+
}));
|
|
371
|
+
} catch (error) {
|
|
372
|
+
throw toTemenosAttestationError(error, currentPhase, verifier);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
};
|
|
377
|
+
/**
|
|
378
|
+
* The real Temenos attestation driver: runs the verifier library's full
|
|
379
|
+
* pipeline — evidence from `GET /enclave-key`, expected values from the
|
|
380
|
+
* on-chain registration via the indexer, the nine local checks against
|
|
381
|
+
* explicitly supplied AMD roots, Warden verification, and the AKX
|
|
382
|
+
* attested-channel handshake — then hands back a session that tunnels
|
|
383
|
+
* through that channel. Trust-root sourcing is separate from this adapter.
|
|
384
|
+
* Only the deployment baked for `networkId` is accepted, and only
|
|
385
|
+
* when `proofServerApiUrl` names its proof server.
|
|
386
|
+
*/
|
|
387
|
+
const createTemenosAttestedProver = (props) => createTemenosAttestedProverWith(props);
|
|
388
|
+
//#endregion
|
|
389
|
+
//#region ../../packages/module/midnight-sync/src/sdk.ts
|
|
390
|
+
const createMidnightSyncModule = (options) => inferModuleContext({
|
|
391
|
+
moduleName: ModuleName("midnight-sync"),
|
|
392
|
+
implements: combineContracts([
|
|
393
|
+
inMemoryIntegrationAddonContract,
|
|
394
|
+
tokensStoreContract,
|
|
395
|
+
syncStoreContract,
|
|
396
|
+
addressesStoreContract,
|
|
397
|
+
midnightContextStoreContract,
|
|
398
|
+
midnightDependencyContract,
|
|
399
|
+
midnightEngineAddonContract,
|
|
400
|
+
signerFactoryAddonContract
|
|
401
|
+
]),
|
|
402
|
+
dependsOn: combineContracts([
|
|
403
|
+
activitiesStoreContract,
|
|
404
|
+
failuresStoreContract,
|
|
405
|
+
featureStoreContract,
|
|
406
|
+
networkStoreContract,
|
|
407
|
+
walletActiveStateDependencyContract,
|
|
408
|
+
walletRepoStoreContract
|
|
409
|
+
]),
|
|
410
|
+
feature: {
|
|
411
|
+
willLoad: (featureFlags) => featureFlags.some((flag) => flag.key === FEATURE_FLAG_MIDNIGHT),
|
|
412
|
+
metadata: {
|
|
413
|
+
name: "MidnightSync",
|
|
414
|
+
description: "Midnight engine, wallet lifecycle and signer"
|
|
415
|
+
}
|
|
416
|
+
},
|
|
417
|
+
store: inferStoreContext({
|
|
418
|
+
load: async () => {
|
|
419
|
+
const { createSdkStoreInit } = await import("./sdk-init-Bln9rFtn.js");
|
|
420
|
+
return { default: createSdkStoreInit(options) };
|
|
421
|
+
},
|
|
422
|
+
context: {
|
|
423
|
+
actions: midnightSyncActions,
|
|
424
|
+
selectors: {}
|
|
425
|
+
}
|
|
426
|
+
}),
|
|
427
|
+
addons: {
|
|
428
|
+
loadSignerFactory: async () => import("./signer-factory-hzSRaIw2.js"),
|
|
429
|
+
loadMidnightEngine: async () => import("./midnight-engine-DpemplKO.js"),
|
|
430
|
+
loadInMemoryWalletIntegration: async () => import("./in-memory-wallet-integration-CBRiPjLO.js").then((module) => ({ default: module.inMemoryWalletIntegrationReactNative }))
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
//#endregion
|
|
434
|
+
//#region src/midnight-module.ts
|
|
435
|
+
const publicEndpoints = (networkId) => ({
|
|
436
|
+
nodeAddress: `https://rpc.${networkId}.midnight.network`,
|
|
437
|
+
indexerAddress: `https://indexer.${networkId}.midnight.network/api/v4/graphql`
|
|
438
|
+
});
|
|
439
|
+
/**
|
|
440
|
+
* The public Midnight endpoints the SDK syncs through by default. Every other
|
|
441
|
+
* network needs its endpoints from `networks` before `selectMidnightNetwork`
|
|
442
|
+
* accepts it.
|
|
443
|
+
*/
|
|
444
|
+
const MIDNIGHT_PUBLIC_ENDPOINTS = {
|
|
445
|
+
[MidnightSDKNetworkIds.MainNet]: publicEndpoints(MidnightSDKNetworkIds.MainNet),
|
|
446
|
+
[MidnightSDKNetworkIds.PreProd]: publicEndpoints(MidnightSDKNetworkIds.PreProd),
|
|
447
|
+
[MidnightSDKNetworkIds.Preview]: publicEndpoints(MidnightSDKNetworkIds.Preview),
|
|
448
|
+
[MidnightSDKNetworkIds.QaNet]: publicEndpoints(MidnightSDKNetworkIds.QaNet)
|
|
449
|
+
};
|
|
450
|
+
/** The public node of Midnight Preview. */
|
|
451
|
+
const MIDNIGHT_PREVIEW_NODE_URL = MIDNIGHT_PUBLIC_ENDPOINTS[MidnightSDKNetworkIds.Preview].nodeAddress;
|
|
452
|
+
/** The public indexer of Midnight Preview. */
|
|
453
|
+
const MIDNIGHT_PREVIEW_INDEXER_URL = MIDNIGHT_PUBLIC_ENDPOINTS[MidnightSDKNetworkIds.Preview].indexerAddress;
|
|
454
|
+
/** A proof server on the consumer's own machine, the default prover. */
|
|
455
|
+
const MIDNIGHT_LOCAL_PROOF_SERVER_URL = "http://localhost:6300";
|
|
456
|
+
const isPublicNetworkId = (networkId) => networkId in MIDNIGHT_PUBLIC_ENDPOINTS;
|
|
457
|
+
const passwordAuth = (password) => {
|
|
458
|
+
const owned = ByteArray.clone(ByteArray(password));
|
|
459
|
+
return {
|
|
460
|
+
authenticate: () => of(true),
|
|
461
|
+
accessAuthSecret: (callback) => {
|
|
462
|
+
const clone = AuthSecret(ByteArray.clone(owned));
|
|
463
|
+
return callback(clone).pipe(tap(() => clone.fill(0)), finalize(() => clone.fill(0)));
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
};
|
|
467
|
+
const proofServerMode = (url) => {
|
|
468
|
+
const { hostname } = new URL(url);
|
|
469
|
+
return hostname === "localhost" || hostname === "127.0.0.1" ? {
|
|
470
|
+
kind: "local-host",
|
|
471
|
+
url
|
|
472
|
+
} : {
|
|
473
|
+
kind: "delegated",
|
|
474
|
+
url,
|
|
475
|
+
label: hostname
|
|
476
|
+
};
|
|
477
|
+
};
|
|
478
|
+
const defaultProofServers = (proofServerUrl, networks, createAttestedProver) => Object.fromEntries(MidnightSDKNetworkId.map((networkId) => {
|
|
479
|
+
const mode = networks[networkId]?.proofServer ?? proofServerMode(proofServerUrl);
|
|
480
|
+
assertProofServerRouting(mode, !!createAttestedProver);
|
|
481
|
+
return [networkId, mode];
|
|
482
|
+
}));
|
|
483
|
+
const networkOverrides = (networks) => Object.fromEntries(MidnightSDKNetworkId.map((networkId) => {
|
|
484
|
+
const { proofServer: _, ...endpoints } = networks[networkId] ?? {};
|
|
485
|
+
return [networkId, {
|
|
486
|
+
...isPublicNetworkId(networkId) && MIDNIGHT_PUBLIC_ENDPOINTS[networkId],
|
|
487
|
+
...endpoints
|
|
488
|
+
}];
|
|
489
|
+
}));
|
|
490
|
+
/** The networks whose overrides carry both endpoints; the contract defaults are not served. */
|
|
491
|
+
const supportedNetworkIds = (overrides) => MidnightSDKNetworkId.filter((networkId) => overrides[networkId]?.nodeAddress !== void 0 && overrides[networkId]?.indexerAddress !== void 0);
|
|
492
|
+
/**
|
|
493
|
+
* The Midnight engine for `createLaceWallet`: syncs every in-memory Midnight
|
|
494
|
+
* account on the active network, persists its state through the loaded
|
|
495
|
+
* storage module and signs with the password instead of a prompt. Loads
|
|
496
|
+
* behind `FEATURE_FLAG_MIDNIGHT`. The password is copied here, but the
|
|
497
|
+
* caller's buffer must stay intact until its last entity helper call that
|
|
498
|
+
* takes the same bytes.
|
|
499
|
+
*
|
|
500
|
+
* The `config` of `createLaceWallet` must then set
|
|
501
|
+
* `defaultMidnightTestnetNetworkId`, the testnet a wallet starts on, as
|
|
502
|
+
* Cardano needs `defaultTestnetChainId`; without a testnet there,
|
|
503
|
+
* `createLaceWallet` rejects.
|
|
504
|
+
*/
|
|
505
|
+
const createMidnightModule = ({ password, proofServerUrl = MIDNIGHT_LOCAL_PROOF_SERVER_URL, networks = {}, batchUpdates, createAttestedProver }) => {
|
|
506
|
+
const overrides = networkOverrides(networks);
|
|
507
|
+
return createMidnightSyncModule({
|
|
508
|
+
auth: passwordAuth(password),
|
|
509
|
+
networks: overrides,
|
|
510
|
+
supportedNetworkIds: supportedNetworkIds(overrides),
|
|
511
|
+
defaultProofServers: defaultProofServers(proofServerUrl, networks, createAttestedProver),
|
|
512
|
+
batchUpdates,
|
|
513
|
+
createAttestedProver
|
|
514
|
+
});
|
|
515
|
+
};
|
|
516
|
+
//#endregion
|
|
517
|
+
//#region src/midnight-passkey-wallet-entity.ts
|
|
518
|
+
/**
|
|
519
|
+
* Derives the Midnight accounts of the passkey's words inside one assertion.
|
|
520
|
+
* Unlike the Cardano passkey entity, the result is an `InMemory` wallet: the
|
|
521
|
+
* Midnight engine needs the account keys while it syncs, so each account
|
|
522
|
+
* holds its keys sealed under `password`. The entity holds no recovery
|
|
523
|
+
* phrase and no seed, and no account of another blockchain.
|
|
524
|
+
*/
|
|
525
|
+
const createMidnightPasskeyWalletEntity = async (wallet, { keySource, password, walletName, accounts = [] }) => keySource.withPasskeyMnemonic(async (words) => {
|
|
526
|
+
let entity = await createBlockchainWalletEntity(wallet, "Midnight", {
|
|
527
|
+
mnemonicWords: [...words],
|
|
528
|
+
password,
|
|
529
|
+
walletName
|
|
530
|
+
});
|
|
531
|
+
if (entity.accounts.length === 0) throw new Error("No Midnight account derived: load createMidnightModule behind FEATURE_FLAG_MIDNIGHT");
|
|
532
|
+
for (const account of accounts) entity = await createMidnightAccounts(wallet, {
|
|
533
|
+
...account,
|
|
534
|
+
wallet: entity,
|
|
535
|
+
password
|
|
536
|
+
});
|
|
537
|
+
return withoutSeedMaterial(entity);
|
|
538
|
+
});
|
|
539
|
+
const withoutSeedMaterial = ({ encryptedRecoveryPhrase: _phrase, blockchainSpecific: { Midnight: _seed, ...blockchainSpecific }, ...entity }) => ({
|
|
540
|
+
...entity,
|
|
541
|
+
blockchainSpecific
|
|
542
|
+
});
|
|
543
|
+
//#endregion
|
|
544
|
+
//#region src/midnight-errors.ts
|
|
545
|
+
/** The loadout has no endpoints for the network: none public, none from `networks`. */
|
|
546
|
+
var MidnightNetworkNotConfiguredError = class extends Error {
|
|
547
|
+
code = "midnight-network-not-configured";
|
|
548
|
+
constructor(networkId) {
|
|
549
|
+
super(`Midnight network "${networkId}" has no endpoints in this loadout: pass networks.${networkId} with nodeAddress and indexerAddress to createMidnightModule`);
|
|
550
|
+
this.name = "MidnightNetworkNotConfiguredError";
|
|
551
|
+
}
|
|
552
|
+
};
|
|
553
|
+
/** No single in-memory Midnight account on the active network answers the request. */
|
|
554
|
+
var MidnightAccountNotFoundError = class extends Error {
|
|
555
|
+
code = "midnight-account-not-found";
|
|
556
|
+
constructor(message) {
|
|
557
|
+
super(message);
|
|
558
|
+
this.name = "MidnightAccountNotFoundError";
|
|
559
|
+
}
|
|
560
|
+
};
|
|
561
|
+
/** The engine did not start the account's wallets within the wait. */
|
|
562
|
+
var MidnightWalletNotReadyError = class extends Error {
|
|
563
|
+
code = "midnight-wallet-not-ready";
|
|
564
|
+
constructor(accountId, timeoutMs) {
|
|
565
|
+
super(`Midnight wallet for account "${accountId}" did not start within ${timeoutMs}ms`);
|
|
566
|
+
this.name = "MidnightWalletNotReadyError";
|
|
567
|
+
}
|
|
568
|
+
};
|
|
569
|
+
/** The account holds no available NIGHT to register for DUST generation. */
|
|
570
|
+
var MidnightNothingToRegisterError = class extends Error {
|
|
571
|
+
code = "midnight-nothing-to-register";
|
|
572
|
+
constructor(accountId) {
|
|
573
|
+
super(`Account "${accountId}" has no available NIGHT to register`);
|
|
574
|
+
this.name = "MidnightNothingToRegisterError";
|
|
575
|
+
}
|
|
576
|
+
};
|
|
577
|
+
/**
|
|
578
|
+
* `submitMidnightTx` stopped waiting for the node to report the transaction final. The engine had already been
|
|
579
|
+
* given the transaction, so it may be on chain or reach it later: look for `activityHash` in the account's
|
|
580
|
+
* activities before submitting again.
|
|
581
|
+
*/
|
|
582
|
+
var MidnightSubmitTimeoutError = class extends Error {
|
|
583
|
+
code = "midnight-submit-timeout";
|
|
584
|
+
/** The transaction's hash, which is the `activityId` of its activity. */
|
|
585
|
+
activityHash;
|
|
586
|
+
constructor(activityHash, timeoutMs) {
|
|
587
|
+
super(`Midnight transaction ${activityHash} was not reported final within ${timeoutMs}ms and may still reach the chain`);
|
|
588
|
+
this.name = "MidnightSubmitTimeoutError";
|
|
589
|
+
this.activityHash = activityHash;
|
|
590
|
+
}
|
|
591
|
+
};
|
|
592
|
+
//#endregion
|
|
593
|
+
//#region src/select-midnight-network.ts
|
|
594
|
+
/**
|
|
595
|
+
* Makes `networkId` the active Midnight network. A testnet also becomes the
|
|
596
|
+
* selected testnet, so the wallet's testnet toggle returns to it. Throws
|
|
597
|
+
* `MidnightNetworkNotConfiguredError` for a network the loadout has no
|
|
598
|
+
* endpoints for: one outside `MIDNIGHT_PUBLIC_ENDPOINTS` whose `networks`
|
|
599
|
+
* override lacks `nodeAddress` or `indexerAddress`.
|
|
600
|
+
*/
|
|
601
|
+
const selectMidnightNetwork = (wallet, networkId) => {
|
|
602
|
+
if (!(wallet.getState().midnightContext?.supportedNetworksIds ?? []).includes(networkId)) throw new MidnightNetworkNotConfiguredError(networkId);
|
|
603
|
+
if (networkId === MidnightSDKNetworkIds.MainNet) {
|
|
604
|
+
wallet.dispatch("network.setNetworkType", "mainnet");
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
wallet.dispatch("network.setBlockchainNetworks", {
|
|
608
|
+
blockchain: "Midnight",
|
|
609
|
+
mainnet: MidnightNetworkId(MidnightSDKNetworkIds.MainNet),
|
|
610
|
+
testnet: MidnightNetworkId(networkId)
|
|
611
|
+
});
|
|
612
|
+
wallet.dispatch("network.setNetworkType", "testnet");
|
|
613
|
+
};
|
|
614
|
+
//#endregion
|
|
615
|
+
//#region src/midnight-timeouts.ts
|
|
616
|
+
/** The longest delay a timer honours; a longer one, or `Infinity`, fires at once. */
|
|
617
|
+
const MAX_TIMEOUT_MS = 2 ** 31 - 1;
|
|
618
|
+
/**
|
|
619
|
+
* Applies a timeout option's default and refuses a value no timer can honour:
|
|
620
|
+
* not a finite positive number of milliseconds, or above `MAX_TIMEOUT_MS`.
|
|
621
|
+
*/
|
|
622
|
+
const resolveTimeoutMs = (name, value, fallback) => {
|
|
623
|
+
const resolved = value ?? fallback;
|
|
624
|
+
if (typeof resolved !== "number" || !Number.isFinite(resolved) || resolved <= 0 || resolved > MAX_TIMEOUT_MS) throw new RangeError(`${name} must be a positive number of milliseconds up to ${MAX_TIMEOUT_MS}; got ${String(resolved)}`);
|
|
625
|
+
return resolved;
|
|
626
|
+
};
|
|
627
|
+
//#endregion
|
|
628
|
+
//#region src/midnight-wallet.ts
|
|
629
|
+
const DEFAULT_START_TIMEOUT_MS = 12e4;
|
|
630
|
+
const resolveMidnightAccountId = async ({ stateObservables }, requestedAccountId) => {
|
|
631
|
+
const wallets = await firstValueFrom(stateObservables.wallets.selectAll$);
|
|
632
|
+
const activeNetworkIds = await firstValueFrom(stateObservables.network.selectAllActiveNetworkIds$);
|
|
633
|
+
const accounts = wallets.flatMap((wallet) => wallet.accounts).filter(isInMemoryMidnightAccount).filter((account) => activeNetworkIds.includes(account.blockchainNetworkId));
|
|
634
|
+
if (requestedAccountId) {
|
|
635
|
+
const found = accounts.find((account) => account.accountId === requestedAccountId);
|
|
636
|
+
if (!found) throw new MidnightAccountNotFoundError(`Midnight account "${requestedAccountId}" not found on the active network`);
|
|
637
|
+
return found.accountId;
|
|
638
|
+
}
|
|
639
|
+
if (accounts.length === 0) throw new MidnightAccountNotFoundError("No Midnight accounts found on the active network");
|
|
640
|
+
if (accounts.length > 1) throw new MidnightAccountNotFoundError(`Multiple Midnight accounts found (${accounts.length}) — specify accountId to disambiguate`);
|
|
641
|
+
return accounts[0].accountId;
|
|
642
|
+
};
|
|
643
|
+
/**
|
|
644
|
+
* The engine's wallet for the account, emitted once the engine starts it and
|
|
645
|
+
* again whenever the engine replaces it (a sync reset or a restart). Emits
|
|
646
|
+
* `undefined` while the engine has stopped the account's wallet and not yet
|
|
647
|
+
* replaced it. Resolves the account on subscription and errors with
|
|
648
|
+
* `MidnightAccountNotFoundError`, or with `MidnightWalletNotReadyError` when
|
|
649
|
+
* no wallet arrives within `startTimeout`, at first or after a stop, so a
|
|
650
|
+
* subscriber that was already watching fails the same way a new one would.
|
|
651
|
+
*/
|
|
652
|
+
const observeMidnightWallet = (wallet, { accountId, startTimeout: requestedStartTimeout }) => defer(async () => {
|
|
653
|
+
const startTimeout = resolveTimeoutMs("startTimeout", requestedStartTimeout, DEFAULT_START_TIMEOUT_MS);
|
|
654
|
+
const resolvedAccountId = await resolveMidnightAccountId(wallet, accountId);
|
|
655
|
+
const [registry$] = await wallet._loadModules("addons.loadMidnightEngine");
|
|
656
|
+
if (!registry$) throw new MidnightWalletNotReadyError(resolvedAccountId, startTimeout);
|
|
657
|
+
return {
|
|
658
|
+
resolvedAccountId,
|
|
659
|
+
registry$,
|
|
660
|
+
startTimeout
|
|
661
|
+
};
|
|
662
|
+
}).pipe(switchMap(({ resolvedAccountId, registry$, startTimeout }) => {
|
|
663
|
+
const notReady = () => throwError(() => new MidnightWalletNotReadyError(resolvedAccountId, startTimeout));
|
|
664
|
+
return registry$.pipe(map((wallets) => wallets[resolvedAccountId]), distinctUntilChanged(), skipWhile((candidate) => !candidate), timeout({
|
|
665
|
+
first: startTimeout,
|
|
666
|
+
with: notReady
|
|
667
|
+
}), switchMap((candidate) => candidate ? of(candidate) : concat(of(void 0), timer(startTimeout).pipe(switchMap(notReady)))));
|
|
668
|
+
}));
|
|
669
|
+
/** The engine's wallet for the account, once the engine has started it. */
|
|
670
|
+
const midnightWalletFor = async (wallet, props) => firstValueFrom(observeMidnightWallet(wallet, props).pipe(filter((candidate) => !!candidate)));
|
|
671
|
+
const toError = (error) => error instanceof Error ? error : new Error(String(error));
|
|
672
|
+
/** Runs one engine operation for the account and settles it as a `Result`. */
|
|
673
|
+
const withMidnightWallet = async (wallet, props, operation) => {
|
|
674
|
+
try {
|
|
675
|
+
return Ok(await firstValueFrom(operation(await midnightWalletFor(wallet, props))));
|
|
676
|
+
} catch (error) {
|
|
677
|
+
return Err(toError(error));
|
|
678
|
+
}
|
|
679
|
+
};
|
|
680
|
+
//#endregion
|
|
681
|
+
//#region src/observe-midnight-balances.ts
|
|
682
|
+
const sumNight = (coins) => coins.filter(({ utxo }) => utxo.type === NIGHT_TOKEN_ID).reduce((sum, { utxo }) => sum + utxo.value, 0n);
|
|
683
|
+
const sameBalances = (a, b) => a.address.unshielded === b.address.unshielded && a.night.available === b.night.available && a.night.pending === b.night.pending && a.dust.balance === b.dust.balance && a.dust.available === b.dust.available && a.synced.unshielded === b.synced.unshielded && a.synced.shielded === b.synced.shielded && a.synced.dust === b.synced.dust;
|
|
684
|
+
const NOT_SYNCED = {
|
|
685
|
+
unshielded: false,
|
|
686
|
+
shielded: false,
|
|
687
|
+
dust: false
|
|
688
|
+
};
|
|
689
|
+
const balancesOf = (midnightWallet) => combineLatest([
|
|
690
|
+
midnightWallet.state(),
|
|
691
|
+
midnightWallet.syncProgress$,
|
|
692
|
+
midnightWallet.address$
|
|
693
|
+
]).pipe(map(([state, progress, address]) => ({
|
|
694
|
+
accountId: midnightWallet.accountId,
|
|
695
|
+
address,
|
|
696
|
+
night: {
|
|
697
|
+
available: sumNight(state.unshielded.availableCoins),
|
|
698
|
+
pending: sumNight(state.unshielded.pendingCoins)
|
|
699
|
+
},
|
|
700
|
+
dust: midnightDustBalances(state),
|
|
701
|
+
synced: progress.isStrictlyComplete
|
|
702
|
+
})));
|
|
703
|
+
/**
|
|
704
|
+
* The account's NIGHT and DUST, straight from the engine, from the moment
|
|
705
|
+
* it starts the account's wallets. Balances are complete once `synced`
|
|
706
|
+
* reports the sub-wallet caught up; a transfer needs unshielded and dust.
|
|
707
|
+
* NIGHT is summed from the engine's state, not from the store's token
|
|
708
|
+
* balances; DUST is summed as the store sums it.
|
|
709
|
+
*
|
|
710
|
+
* Follows the engine across a sync reset or restart. While the engine has
|
|
711
|
+
* stopped the account's wallets and not yet replaced them, it repeats the
|
|
712
|
+
* last balances with every `synced` flag false; once the new wallets start,
|
|
713
|
+
* it emits theirs.
|
|
714
|
+
*
|
|
715
|
+
* Cold: the account is resolved on subscription. Errors the subscriber with
|
|
716
|
+
* `MidnightAccountNotFoundError`, or with `MidnightWalletNotReadyError` when
|
|
717
|
+
* no wallets run for `startTimeout`, at first or after a stop.
|
|
718
|
+
*/
|
|
719
|
+
const observeMidnightBalances = (wallet, props = {}) => observeMidnightWallet(wallet, props).pipe(switchMap((midnightWallet) => midnightWallet ? balancesOf(midnightWallet) : of(void 0)), scan((last, next) => next ?? (last && {
|
|
720
|
+
...last,
|
|
721
|
+
synced: NOT_SYNCED
|
|
722
|
+
}), void 0), filter((balances) => !!balances), distinctUntilChanged(sameBalances));
|
|
723
|
+
//#endregion
|
|
724
|
+
//#region src/balance-midnight-recipe.ts
|
|
725
|
+
const messageOf = (error) => error instanceof Error ? error.message : String(error);
|
|
726
|
+
/**
|
|
727
|
+
* Releases a recipe the engine built, then rethrows the error that made it
|
|
728
|
+
* useless. The engine reserves a recipe's inputs when it builds it and the
|
|
729
|
+
* caller never receives this recipe, so nothing else could release them. If
|
|
730
|
+
* the release fails too, the error is an `AggregateError` of both failures and
|
|
731
|
+
* the coins stay reserved until a sync reset.
|
|
732
|
+
*/
|
|
733
|
+
const releaseThenThrow = (midnightWallet, recipe, error) => concat(midnightWallet.revert(recipe).pipe(ignoreElements(), catchError((releaseError) => throwError(() => new AggregateError([error, releaseError], `${messageOf(error)}; the coins it reserved could not be released: ${messageOf(releaseError)}`)))), throwError(() => error));
|
|
734
|
+
/**
|
|
735
|
+
* Pays a built recipe's fee with DUST. The engine books the recipe's inputs
|
|
736
|
+
* when it builds it, so a failure here releases them before the error is
|
|
737
|
+
* returned: the caller has no recipe to discard.
|
|
738
|
+
*/
|
|
739
|
+
const balanceMidnightRecipe = (midnightWallet, recipe, ttl) => midnightWallet.balanceUnprovenTransaction(recipe.transaction, {
|
|
740
|
+
ttl,
|
|
741
|
+
tokenKindsToBalance: ["dust"]
|
|
742
|
+
}).pipe(catchError((balancingError) => releaseThenThrow(midnightWallet, recipe, balancingError)));
|
|
743
|
+
//#endregion
|
|
744
|
+
//#region src/build-midnight-transfer.ts
|
|
745
|
+
/**
|
|
746
|
+
* Builds an unshielded NIGHT transfer, selecting the inputs and the DUST
|
|
747
|
+
* that pays its fee. The recipe is unsigned and unproven, and reserves its
|
|
748
|
+
* inputs (see `MidnightTxRecipe`): obtain consent from `estimateMidnightFee`,
|
|
749
|
+
* which reserves nothing, before building. When the fee cannot be paid, the
|
|
750
|
+
* inputs the build reserved are released and the balancing error is returned;
|
|
751
|
+
* if that release fails too, the error is an `AggregateError` of both failures
|
|
752
|
+
* and the NIGHT stays reserved until a sync reset.
|
|
753
|
+
*/
|
|
754
|
+
const buildMidnightTransfer = async (wallet, { to, amount, ttl, ...account }) => withMidnightWallet(wallet, account, (midnightWallet) => defer(() => {
|
|
755
|
+
normalizeMidnightTransfers(midnightWallet.networkId, "unshielded", [{
|
|
756
|
+
to,
|
|
757
|
+
amount,
|
|
758
|
+
tokenId: toUnshieldedTokenType(NIGHT_TOKEN_ID, midnightWallet.networkId)
|
|
759
|
+
}]);
|
|
760
|
+
const resolvedTtl = ttl ?? new Date(Date.now() + 36e5);
|
|
761
|
+
return midnightWallet.transferTransaction([{
|
|
762
|
+
type: "unshielded",
|
|
763
|
+
outputs: [{
|
|
764
|
+
type: NIGHT_TOKEN_ID,
|
|
765
|
+
receiverAddress: UnshieldedAddress.codec.decode(midnightWallet.networkId, MidnightBech32m.parse(to)),
|
|
766
|
+
amount
|
|
767
|
+
}]
|
|
768
|
+
}], {
|
|
769
|
+
ttl: resolvedTtl,
|
|
770
|
+
payFees: false
|
|
771
|
+
}).pipe(switchMap((recipe) => balanceMidnightRecipe(midnightWallet, recipe, resolvedTtl)));
|
|
772
|
+
}));
|
|
773
|
+
//#endregion
|
|
774
|
+
//#region src/build-midnight-transfers.ts
|
|
775
|
+
/**
|
|
776
|
+
* Builds an unsigned, unproven batch. The engine selects tokens and fee DUST
|
|
777
|
+
* and reserves them (see `MidnightTxRecipe`): obtain consent from
|
|
778
|
+
* `estimateMidnightFee`, which reserves nothing, before building. When the
|
|
779
|
+
* fee cannot be paid, the inputs the build reserved are released and the
|
|
780
|
+
* balancing error is returned; if that release fails too, the error is an
|
|
781
|
+
* `AggregateError` of both failures and the coins stay reserved until a sync
|
|
782
|
+
* reset.
|
|
783
|
+
*/
|
|
784
|
+
const buildMidnightTransfers = async (wallet, { kind, outputs, ttl, ...account }) => withMidnightWallet(wallet, account, (engine) => defer(() => {
|
|
785
|
+
const transfers = normalizeMidnightTransfers(engine.networkId, kind, outputs);
|
|
786
|
+
const desiredOutputs = kind === "shielded" ? {
|
|
787
|
+
type: "shielded",
|
|
788
|
+
outputs: transfers.map(({ address, tokenId, amount }) => ({
|
|
789
|
+
type: tokenId,
|
|
790
|
+
amount,
|
|
791
|
+
receiverAddress: ShieldedAddress.codec.decode(engine.networkId, MidnightBech32m.parse(address))
|
|
792
|
+
}))
|
|
793
|
+
} : {
|
|
794
|
+
type: "unshielded",
|
|
795
|
+
outputs: transfers.map(({ address, tokenId, amount }) => ({
|
|
796
|
+
type: tokenId,
|
|
797
|
+
amount,
|
|
798
|
+
receiverAddress: UnshieldedAddress.codec.decode(engine.networkId, MidnightBech32m.parse(address))
|
|
799
|
+
}))
|
|
800
|
+
};
|
|
801
|
+
const resolvedTtl = ttl ?? new Date(Date.now() + 36e5);
|
|
802
|
+
return engine.transferTransaction([desiredOutputs], {
|
|
803
|
+
ttl: resolvedTtl,
|
|
804
|
+
payFees: false
|
|
805
|
+
}).pipe(switchMap((recipe) => balanceMidnightRecipe(engine, recipe, resolvedTtl)));
|
|
806
|
+
}));
|
|
807
|
+
//#endregion
|
|
808
|
+
//#region src/register-midnight-dust.ts
|
|
809
|
+
/**
|
|
810
|
+
* Whether the account already takes part in DUST generation: registered
|
|
811
|
+
* NIGHT, generated DUST, or generation capacity (the contract's
|
|
812
|
+
* `getDesignationTargetType` plus capacity). The engine does not report where
|
|
813
|
+
* registered NIGHT generates, so this covers a designation to the account's
|
|
814
|
+
* own address and to an external one alike.
|
|
815
|
+
*/
|
|
816
|
+
const isDesignatedForDust = (state, nightCoins) => getDesignationTargetType(nightCoins.map(({ utxo, meta }) => ({
|
|
817
|
+
status: "available",
|
|
818
|
+
value: BigNumber(utxo.value),
|
|
819
|
+
registeredForDustGeneration: meta.registeredForDustGeneration
|
|
820
|
+
})), state.dust.totalCoins.reduce((sum, coin) => sum + coin.generatedNow, 0n)) !== "none" || state.dust.totalCoins.some((coin) => coin.maxCap > 0n);
|
|
821
|
+
/** Internal unsigned selection shared with fee estimation. */
|
|
822
|
+
const prepareMidnightDustRegistration = (midnightWallet, { dustAddress: destination, ttl }) => combineLatest([midnightWallet.state().pipe(take(1)), midnightWallet.address$.pipe(take(1))]).pipe(map(([state, address]) => {
|
|
823
|
+
if (ttl !== void 0) throw new Error("A DUST registration does not accept ttl: the engine sets its validity window");
|
|
824
|
+
const nightCoins = state.unshielded.availableCoins.filter(({ utxo }) => utxo.type === NIGHT_TOKEN_ID);
|
|
825
|
+
if (nightCoins.length === 0 || nightCoins.every(({ utxo }) => utxo.value <= 0n)) throw new MidnightNothingToRegisterError(midnightWallet.accountId);
|
|
826
|
+
const dustAddress = DustAddress.codec.decode(midnightWallet.networkId, MidnightBech32m.parse(destination ?? address.dust));
|
|
827
|
+
if (destination !== void 0 && isDesignatedForDust(state, nightCoins)) throw new Error("DUST destination cannot be changed while the account is designated for DUST generation");
|
|
828
|
+
return {
|
|
829
|
+
state,
|
|
830
|
+
nightCoins,
|
|
831
|
+
dustAddress,
|
|
832
|
+
destination: destination ?? address.dust,
|
|
833
|
+
isRepeatRegistration: nightCoins.some((coin) => coin.meta.registeredForDustGeneration)
|
|
834
|
+
};
|
|
835
|
+
}));
|
|
836
|
+
/**
|
|
837
|
+
* Registers every available NIGHT UTXO. Obtain consumer consent before
|
|
838
|
+
* calling: registration signs internally.
|
|
839
|
+
*
|
|
840
|
+
* - An explicit `dustAddress` is refused while the account is designated for
|
|
841
|
+
* DUST generation (registered NIGHT, generated DUST or generation capacity),
|
|
842
|
+
* so it never redirects an existing designation.
|
|
843
|
+
* - Without `dustAddress` the NIGHT is registered to the account's own DUST
|
|
844
|
+
* address, whatever it is registered to now. NIGHT registered to an external
|
|
845
|
+
* address is therefore re-registered to the account's own address. When some
|
|
846
|
+
* NIGHT is already registered, the registration is balanced with DUST.
|
|
847
|
+
*
|
|
848
|
+
* The returned recipe reserves the NIGHT it registers (see `MidnightTxRecipe`).
|
|
849
|
+
* When the registration cannot be built, the NIGHT it reserved is released
|
|
850
|
+
* and the build error is returned; if that release fails too, the error is an
|
|
851
|
+
* `AggregateError` of both failures, and the NIGHT stays reserved until a
|
|
852
|
+
* sync reset. The wallet library does not release it when the fee query of a
|
|
853
|
+
* first registration fails; it then also stays reserved until a sync reset.
|
|
854
|
+
*/
|
|
855
|
+
const registerMidnightDust = async (wallet, { ttl, dustAddress: destination, ...account } = {}) => withMidnightWallet(wallet, account, (midnightWallet) => prepareMidnightDustRegistration(midnightWallet, {
|
|
856
|
+
dustAddress: destination,
|
|
857
|
+
ttl
|
|
858
|
+
}).pipe(switchMap(({ nightCoins, dustAddress, isRepeatRegistration }) => {
|
|
859
|
+
const registration$ = midnightWallet.registerNightUtxosForDustGeneration(nightCoins, dustAddress);
|
|
860
|
+
if (!isRepeatRegistration) return registration$;
|
|
861
|
+
return registration$.pipe(switchMap((registration) => balanceMidnightRecipe(midnightWallet, registration, new Date(Date.now() + defaultTxTtlLength))));
|
|
862
|
+
})));
|
|
863
|
+
//#endregion
|
|
864
|
+
//#region src/estimate-midnight-fee.ts
|
|
865
|
+
/**
|
|
866
|
+
* Estimates DUST from unsigned preparation, without registering or signing.
|
|
867
|
+
* A first registration with no spendable DUST estimates zero; a repeat
|
|
868
|
+
* registration is estimated like the DUST balancing it performs.
|
|
869
|
+
* Estimates depend on current state/time and are not guaranteed final charges.
|
|
870
|
+
* Insufficient spendable DUST returns an error.
|
|
871
|
+
*/
|
|
872
|
+
const estimateMidnightFee = async (wallet, request) => {
|
|
873
|
+
return withMidnightWallet(wallet, request.kind === "transfer" ? request.transfer : request.registration, (engine) => defer(() => {
|
|
874
|
+
return combineLatest([request.kind === "transfer" ? engine.state().pipe(take(1), map((state) => {
|
|
875
|
+
const { kind, outputs, ttl } = request.transfer;
|
|
876
|
+
const transfers = normalizeMidnightTransfers(engine.networkId, kind, outputs);
|
|
877
|
+
return {
|
|
878
|
+
state,
|
|
879
|
+
tx: (kind === "shielded" ? constructShieldedTransaction : constructUnshieldedTransaction)({
|
|
880
|
+
networkId: engine.networkId,
|
|
881
|
+
transfers,
|
|
882
|
+
ttl
|
|
883
|
+
}),
|
|
884
|
+
isFirstDesignation: false
|
|
885
|
+
};
|
|
886
|
+
})) : prepareMidnightDustRegistration(engine, request.registration).pipe(map(({ state, nightCoins, destination, isRepeatRegistration }) => ({
|
|
887
|
+
state,
|
|
888
|
+
tx: constructDustDesignationTransaction({
|
|
889
|
+
networkId: engine.networkId,
|
|
890
|
+
address: destination,
|
|
891
|
+
nightUtxos: nightCoins,
|
|
892
|
+
nightVerifyingKey: engine.nightVerifyingKey,
|
|
893
|
+
allowFeePayment: isRepeatRegistration ? 0n : void 0
|
|
894
|
+
}),
|
|
895
|
+
isFirstDesignation: !isRepeatRegistration
|
|
896
|
+
}))), engine.areKeysAvailable$.pipe(take(1))]).pipe(switchMap(([{ state, tx, isFirstDesignation }, areKeysAvailable]) => {
|
|
897
|
+
const availableDust = state.dust.balance(/* @__PURE__ */ new Date());
|
|
898
|
+
return estimatePreparedMidnightFee(engine, tx, {
|
|
899
|
+
isDustDesignation: isFirstDesignation,
|
|
900
|
+
dustBalance: availableDust,
|
|
901
|
+
areKeysAvailable
|
|
902
|
+
}).pipe(map((dustFee) => {
|
|
903
|
+
if (dustFee > availableDust) throw new Error("Insufficient spendable DUST");
|
|
904
|
+
return {
|
|
905
|
+
dustFee,
|
|
906
|
+
availableDust
|
|
907
|
+
};
|
|
908
|
+
}));
|
|
909
|
+
}));
|
|
910
|
+
}));
|
|
911
|
+
};
|
|
912
|
+
//#endregion
|
|
913
|
+
//#region ../../packages/lib/vendor/src/midnight-sign-data.ts
|
|
914
|
+
init__polyfill_buffer_patch();
|
|
915
|
+
/** Decode the connector transport form, preserving Buffer's permissive hex/base64 handling. */
|
|
916
|
+
const decodeMidnightSignData = (data, encoding) => {
|
|
917
|
+
switch (encoding) {
|
|
918
|
+
case "hex": return new Uint8Array(import_buffer.Buffer.from(data, "hex"));
|
|
919
|
+
case "base64": return new Uint8Array(import_buffer.Buffer.from(data, "base64"));
|
|
920
|
+
case "text": return new TextEncoder().encode(data);
|
|
921
|
+
default: throw new Error(`Unsupported encoding: ${String(encoding)}`);
|
|
922
|
+
}
|
|
923
|
+
};
|
|
924
|
+
const SIGNED_MESSAGE_PREFIX = "midnight_signed_message:";
|
|
925
|
+
/**
|
|
926
|
+
* Prefixes decoded payload bytes with UTF-8 `midnight_signed_message:<byteLength>:`.
|
|
927
|
+
* The length excludes the prefix; sign and verify these bytes, not the transport encoding.
|
|
928
|
+
*/
|
|
929
|
+
const applyMidnightSignedMessagePrefix = (data) => {
|
|
930
|
+
const header = new TextEncoder().encode(`${SIGNED_MESSAGE_PREFIX}${data.length}:`);
|
|
931
|
+
const prefixed = new Uint8Array(header.length + data.length);
|
|
932
|
+
prefixed.set(header, 0);
|
|
933
|
+
prefixed.set(data, header.length);
|
|
934
|
+
return prefixed;
|
|
935
|
+
};
|
|
936
|
+
//#endregion
|
|
937
|
+
//#region src/sign-midnight-data.ts
|
|
938
|
+
/**
|
|
939
|
+
* Signs a connector-compatible message with the selected account's unshielded
|
|
940
|
+
* NIGHT key. Obtain consumer consent for this payload and account before calling;
|
|
941
|
+
* this helper shows no prompt and the module's password unlocks the key.
|
|
942
|
+
*
|
|
943
|
+
* Decodes hex/base64 with Buffer (including permissive malformed input), or text
|
|
944
|
+
* as UTF-8, then prefixes `midnight_signed_message:<byteLength>:`. Empty payloads
|
|
945
|
+
* still receive the prefix. Only the `unshielded` key type is supported.
|
|
946
|
+
* Returns the original payload, signature and verifying key. Account resolution,
|
|
947
|
+
* unsupported options and signing failures settle as `Err<Error>`.
|
|
948
|
+
*/
|
|
949
|
+
const signMidnightData = async (wallet, { data, options, ...account }) => withMidnightWallet(wallet, account, (midnightWallet) => defer(() => {
|
|
950
|
+
if (options.keyType !== "unshielded") throw new Error(`Unsupported key type: ${String(options.keyType)}`);
|
|
951
|
+
const bytes = applyMidnightSignedMessagePrefix(decodeMidnightSignData(data, options.encoding));
|
|
952
|
+
return midnightWallet.signData(bytes).pipe(map(({ signature, verifyingKey }) => ({
|
|
953
|
+
data,
|
|
954
|
+
signature,
|
|
955
|
+
verifyingKey
|
|
956
|
+
})));
|
|
957
|
+
}));
|
|
958
|
+
//#endregion
|
|
959
|
+
//#region src/discard-midnight-tx.ts
|
|
960
|
+
/**
|
|
961
|
+
* Releases the coins a built recipe holds, so they return to the account's
|
|
962
|
+
* available balance and a later build can select them.
|
|
963
|
+
*
|
|
964
|
+
* Discard only a recipe that never reached proving: consent declined,
|
|
965
|
+
* `signMidnightTx` failed, or `proveMidnightTx` returned
|
|
966
|
+
* `MidnightAccountNotFoundError`, `MidnightWalletNotReadyError` or a
|
|
967
|
+
* `RangeError` for its `proveTimeout`, which are raised before proving. Do
|
|
968
|
+
* not discard after any other `proveMidnightTx`
|
|
969
|
+
* error, including a timeout, nor after it returned a transaction: the engine
|
|
970
|
+
* releases a recipe whose proving fails, and releases a proved transaction
|
|
971
|
+
* that never reaches the chain once its validity window (`ttl`) has passed.
|
|
972
|
+
* Pass the `accountId` the recipe was built with: under another account the
|
|
973
|
+
* release finds no reserved coins and still reports `Ok`. The release works
|
|
974
|
+
* per coin, not per transaction, so discarding a recipe the engine has
|
|
975
|
+
* already released, or one built before a sync reset cleared its
|
|
976
|
+
* reservation, can free coins that a later build reserved
|
|
977
|
+
* for a transaction still in flight. For the same reason, never discard a
|
|
978
|
+
* recipe whose transaction was passed to `submitMidnightTx`.
|
|
979
|
+
*/
|
|
980
|
+
const discardMidnightTx = async (wallet, { recipe, ...account }) => withMidnightWallet(wallet, account, (midnightWallet) => defer(() => midnightWallet.revert(recipe)));
|
|
981
|
+
//#endregion
|
|
982
|
+
//#region src/sign-midnight-tx.ts
|
|
983
|
+
/**
|
|
984
|
+
* Signs the recipe's unshielded inputs with the account's NIGHT key. The
|
|
985
|
+
* module's password unlocks the key; no prompt is shown. Obtain consumer consent
|
|
986
|
+
* for the exact transaction and account before invoking this helper.
|
|
987
|
+
*/
|
|
988
|
+
const signMidnightTx = async (wallet, { recipe, ...account }) => withMidnightWallet(wallet, account, (midnightWallet) => defer(() => midnightWallet.signRecipe(recipe)));
|
|
989
|
+
//#endregion
|
|
990
|
+
//#region src/prove-midnight-tx.ts
|
|
991
|
+
/** How long every proving helper waits for the proof server unless told otherwise. */
|
|
992
|
+
const DEFAULT_PROVE_TIMEOUT_MS = 10 * 6e4;
|
|
993
|
+
/** Applies the default `proveTimeout` and refuses a value no timer can honour. */
|
|
994
|
+
const resolveProveTimeout = (proveTimeout) => resolveTimeoutMs("proveTimeout", proveTimeout, DEFAULT_PROVE_TIMEOUT_MS);
|
|
995
|
+
/**
|
|
996
|
+
* Proves the recipe through the proof server the module was configured
|
|
997
|
+
* with. Timeout stops observation; it does not cancel underlying proving.
|
|
998
|
+
*/
|
|
999
|
+
const proveMidnightTx = async (wallet, { recipe, onProgress, proveTimeout, ...account }) => withMidnightWallet(wallet, account, (midnightWallet) => {
|
|
1000
|
+
const limit = resolveProveTimeout(proveTimeout);
|
|
1001
|
+
let observer = onProgress;
|
|
1002
|
+
return defer(() => onProgress ? midnightWallet.finalizeRecipe(recipe, (event) => observer?.(event)) : midnightWallet.finalizeRecipe(recipe)).pipe(timeout(limit), finalize(() => {
|
|
1003
|
+
observer = void 0;
|
|
1004
|
+
}));
|
|
1005
|
+
});
|
|
1006
|
+
//#endregion
|
|
1007
|
+
//#region ../../packages/module/dapp-connector-midnight/src/store/helpers/derive-pending-activity-from-midnight-tx.ts
|
|
1008
|
+
const utxoKey = (intentHash, outputNo) => `${intentHash}#${outputNo}`;
|
|
1009
|
+
const processOffer = (offer, ownUtxoIndex, ownUserAddressHex) => {
|
|
1010
|
+
if (!offer) return {
|
|
1011
|
+
nightDelta: 0n,
|
|
1012
|
+
isInvolved: false
|
|
1013
|
+
};
|
|
1014
|
+
let nightDelta = 0n;
|
|
1015
|
+
let isInvolved = false;
|
|
1016
|
+
for (const input of offer.inputs) {
|
|
1017
|
+
const own = ownUtxoIndex.get(utxoKey(input.intentHash, input.outputNo));
|
|
1018
|
+
if (!own) continue;
|
|
1019
|
+
isInvolved = true;
|
|
1020
|
+
if (own.utxo.type === "0000000000000000000000000000000000000000000000000000000000000000") nightDelta -= own.utxo.value;
|
|
1021
|
+
}
|
|
1022
|
+
for (const output of offer.outputs) {
|
|
1023
|
+
if (output.owner !== ownUserAddressHex) continue;
|
|
1024
|
+
isInvolved = true;
|
|
1025
|
+
if (output.type === "0000000000000000000000000000000000000000000000000000000000000000") nightDelta += output.value;
|
|
1026
|
+
}
|
|
1027
|
+
return {
|
|
1028
|
+
nightDelta,
|
|
1029
|
+
isInvolved
|
|
1030
|
+
};
|
|
1031
|
+
};
|
|
1032
|
+
const buildOwnUtxoIndex = (nightUtxos) => {
|
|
1033
|
+
const index = /* @__PURE__ */ new Map();
|
|
1034
|
+
for (const entry of nightUtxos) index.set(utxoKey(entry.utxo.intentHash, entry.utxo.outputNo), entry);
|
|
1035
|
+
return index;
|
|
1036
|
+
};
|
|
1037
|
+
const derivePendingActivityFromMidnightTx = ({ deserializedTx, accountId, ownUserAddressHex, nightUtxos, networkId }) => {
|
|
1038
|
+
const ownUtxoIndex = buildOwnUtxoIndex(nightUtxos);
|
|
1039
|
+
let nightAmount = 0n;
|
|
1040
|
+
let isAccountInvolved = false;
|
|
1041
|
+
for (const intent of deserializedTx.intents?.values() ?? []) for (const offer of [intent.guaranteedUnshieldedOffer, intent.fallibleUnshieldedOffer]) {
|
|
1042
|
+
const { nightDelta, isInvolved } = processOffer(offer, ownUtxoIndex, ownUserAddressHex);
|
|
1043
|
+
nightAmount += nightDelta;
|
|
1044
|
+
isAccountInvolved = isAccountInvolved || isInvolved;
|
|
1045
|
+
}
|
|
1046
|
+
if (!isAccountInvolved) return void 0;
|
|
1047
|
+
const tokenBalanceChanges = nightAmount === 0n ? [] : [{
|
|
1048
|
+
tokenId: TokenId(toUnshieldedTokenType(NIGHT_TOKEN_ID, networkId)),
|
|
1049
|
+
amount: BigNumber(nightAmount)
|
|
1050
|
+
}];
|
|
1051
|
+
return {
|
|
1052
|
+
accountId,
|
|
1053
|
+
activityId: deserializedTx.transactionHash(),
|
|
1054
|
+
timestamp: Timestamp(Date.now()),
|
|
1055
|
+
tokenBalanceChanges,
|
|
1056
|
+
type: ActivityType.Pending
|
|
1057
|
+
};
|
|
1058
|
+
};
|
|
1059
|
+
//#endregion
|
|
1060
|
+
//#region src/submit-midnight-tx.ts
|
|
1061
|
+
const DEFAULT_SUBMIT_TIMEOUT_MS = 5 * 6e4;
|
|
1062
|
+
const PENDING_ROW_STATE_TIMEOUT_MS = 1e4;
|
|
1063
|
+
/** Records the Pending activity unless the account already has a confirmed row for the transaction. */
|
|
1064
|
+
const recordPendingActivity = ({ dispatch, activities, midnightWallet, transaction, utxos }) => {
|
|
1065
|
+
try {
|
|
1066
|
+
const activity = derivePendingActivityFromMidnightTx({
|
|
1067
|
+
deserializedTx: transaction,
|
|
1068
|
+
accountId: midnightWallet.accountId,
|
|
1069
|
+
ownUserAddressHex: addressFromKey(midnightWallet.nightVerifyingKey),
|
|
1070
|
+
nightUtxos: utxos,
|
|
1071
|
+
networkId: midnightWallet.networkId
|
|
1072
|
+
});
|
|
1073
|
+
if (!activity) return void 0;
|
|
1074
|
+
const current = activities[activity.accountId]?.find((row) => row.activityId === activity.activityId);
|
|
1075
|
+
if (current && current.type !== ActivityType.Pending) return void 0;
|
|
1076
|
+
dispatch("activities.upsertActivities", {
|
|
1077
|
+
accountId: activity.accountId,
|
|
1078
|
+
activities: [activity]
|
|
1079
|
+
});
|
|
1080
|
+
return activity;
|
|
1081
|
+
} catch {
|
|
1082
|
+
return;
|
|
1083
|
+
}
|
|
1084
|
+
};
|
|
1085
|
+
/**
|
|
1086
|
+
* Submits a proved transaction after consumer authorization and resolves once the node reports it final: the
|
|
1087
|
+
* engine submits at its `Finalized` stage, so `Ok` means the transaction is on chain. `txId` is the engine's
|
|
1088
|
+
* identifier, which is not the activity hash; the activity hash is `transaction.transactionHash()`.
|
|
1089
|
+
*
|
|
1090
|
+
* On an instance that tracks activities, the transaction's Pending activity, keyed by the activity hash, is
|
|
1091
|
+
* recorded when the submission is handed to the engine, before finality; the history sync then replaces it with
|
|
1092
|
+
* the confirmed row. The engine reports no acceptance before finality, so the row is written as soon as the call
|
|
1093
|
+
* is issued. When the engine fails the submission it releases the transaction's coins and the Pending row is
|
|
1094
|
+
* removed; if the transaction reaches the chain anyway, the history sync records it. Tracking failures never fail
|
|
1095
|
+
* a submission.
|
|
1096
|
+
*
|
|
1097
|
+
* An `Err` does not prove that nothing was broadcast. {@link MidnightSubmitTimeoutError} (`code`
|
|
1098
|
+
* `midnight-submit-timeout`) means the node did not report finality within `submitTimeout`: the transaction may
|
|
1099
|
+
* still reach the chain, and its Pending row stays. The SDK keeps listening to the engine's submission after the
|
|
1100
|
+
* timeout, for as long as that submission runs in this process: a failure it reports later removes the row, a
|
|
1101
|
+
* confirmation reaches the history sync. A row whose outcome this process never learns (it ends first) stays
|
|
1102
|
+
* until the history sync confirms it or the consumer removes it. The account-resolution errors
|
|
1103
|
+
* (`MidnightAccountNotFoundError`, `MidnightWalletNotReadyError`) precede the call and so precede any broadcast;
|
|
1104
|
+
* any other error is the engine's, and may also arrive after broadcast. Before retrying, check the account's
|
|
1105
|
+
* activities for the activity hash.
|
|
1106
|
+
*/
|
|
1107
|
+
const submitMidnightTx = async (wallet, { transaction, submitTimeout: requestedSubmitTimeout, ...account }) => withMidnightWallet(wallet, account, (midnightWallet) => defer(() => {
|
|
1108
|
+
const submitTimeout = resolveTimeoutMs("submitTimeout", requestedSubmitTimeout, DEFAULT_SUBMIT_TIMEOUT_MS);
|
|
1109
|
+
const { dispatch } = wallet;
|
|
1110
|
+
const activities$ = dispatch ? wallet.stateObservables.activities?.selectAllMap$ : void 0;
|
|
1111
|
+
const latestActivities$ = activities$ ? activities$.pipe(startWith(void 0), catchError(() => of(void 0))) : of(void 0);
|
|
1112
|
+
const utxos$ = activities$ ? defer(() => midnightWallet.state()).pipe(take(1), map((state) => [...state.unshielded.availableCoins, ...state.unshielded.pendingCoins]), defaultIfEmpty(void 0), catchError(() => of(void 0))) : of(void 0);
|
|
1113
|
+
const removePendingRow = (pending) => {
|
|
1114
|
+
if (!dispatch || !activities$) return;
|
|
1115
|
+
activities$.pipe(take(1), catchError(() => of(void 0))).subscribe((latest) => {
|
|
1116
|
+
if ((latest?.[pending.accountId]?.find((row) => row.activityId === pending.activityId))?.type !== ActivityType.Pending) return;
|
|
1117
|
+
try {
|
|
1118
|
+
dispatch("activities.removeActivities", {
|
|
1119
|
+
accountId: pending.accountId,
|
|
1120
|
+
activityIds: [pending.activityId]
|
|
1121
|
+
});
|
|
1122
|
+
} catch {}
|
|
1123
|
+
});
|
|
1124
|
+
};
|
|
1125
|
+
const settle = (finality$, pending) => {
|
|
1126
|
+
const outcome$ = finality$.pipe(share({
|
|
1127
|
+
connector: () => new ReplaySubject(1),
|
|
1128
|
+
resetOnError: false,
|
|
1129
|
+
resetOnComplete: false
|
|
1130
|
+
}));
|
|
1131
|
+
if (pending) outcome$.subscribe({
|
|
1132
|
+
next: () => void 0,
|
|
1133
|
+
error: () => {
|
|
1134
|
+
removePendingRow(pending);
|
|
1135
|
+
}
|
|
1136
|
+
});
|
|
1137
|
+
return outcome$.pipe(timeout({
|
|
1138
|
+
first: submitTimeout,
|
|
1139
|
+
with: () => throwError(() => new MidnightSubmitTimeoutError(transaction.transactionHash(), submitTimeout))
|
|
1140
|
+
}), map((txId) => ({ txId })));
|
|
1141
|
+
};
|
|
1142
|
+
return utxos$.pipe(timeout({
|
|
1143
|
+
first: Math.min(PENDING_ROW_STATE_TIMEOUT_MS, submitTimeout),
|
|
1144
|
+
with: () => of(void 0)
|
|
1145
|
+
}), switchMap((utxos) => {
|
|
1146
|
+
const finality$ = midnightWallet.submitTransaction(transaction);
|
|
1147
|
+
return of(utxos).pipe(withLatestFrom(latestActivities$), map(([coins, activities]) => dispatch && activities && coins ? recordPendingActivity({
|
|
1148
|
+
dispatch,
|
|
1149
|
+
activities,
|
|
1150
|
+
midnightWallet,
|
|
1151
|
+
transaction,
|
|
1152
|
+
utxos: coins
|
|
1153
|
+
}) : void 0), switchMap((pending) => settle(finality$, pending)));
|
|
1154
|
+
}));
|
|
1155
|
+
}));
|
|
1156
|
+
//#endregion
|
|
1157
|
+
//#region src/modules-midnight.ts
|
|
1158
|
+
var modules_midnight_exports = /* @__PURE__ */ __exportAll({
|
|
1159
|
+
featureDev: () => sdk_default,
|
|
1160
|
+
storageInMemory: () => sdk_default$1,
|
|
1161
|
+
storageWebIndexeddb: () => sdk_default$2
|
|
1162
|
+
});
|
|
1163
|
+
//#endregion
|
|
1164
|
+
//#region src/midnight-proving-provider.ts
|
|
1165
|
+
const withinTimeout = async (operation, milliseconds) => firstValueFrom(from(operation).pipe(timeout(milliseconds)));
|
|
1166
|
+
/**
|
|
1167
|
+
* Captures one account identity and resolves its current engine on every use.
|
|
1168
|
+
* No proof-server URL or wallet keys are exposed. Factory failures are `Err`;
|
|
1169
|
+
* `check`/`prove` reject on transport or attestation failure without fallback,
|
|
1170
|
+
* and on timeout.
|
|
1171
|
+
* The consumer must authorize disclosure of the circuit preimage to the configured prover.
|
|
1172
|
+
*/
|
|
1173
|
+
const getMidnightProvingProvider = async (wallet, { keyMaterialProvider, proveTimeout: requestedProveTimeout, ...selection }) => {
|
|
1174
|
+
try {
|
|
1175
|
+
const proveTimeout = resolveProveTimeout(requestedProveTimeout);
|
|
1176
|
+
const accountId = await resolveMidnightAccountId(wallet, selection.accountId);
|
|
1177
|
+
const account = {
|
|
1178
|
+
...selection,
|
|
1179
|
+
accountId
|
|
1180
|
+
};
|
|
1181
|
+
await midnightWalletFor(wallet, account);
|
|
1182
|
+
const provider = createProvingProviderFromCircuits({
|
|
1183
|
+
check: async (payload) => (await midnightWalletFor(wallet, account)).proofCircuitProvider.check(payload),
|
|
1184
|
+
prove: async (payload) => (await midnightWalletFor(wallet, account)).proofCircuitProvider.prove(payload)
|
|
1185
|
+
}, keyMaterialProvider, { onKeyMaterialError: "propagate" });
|
|
1186
|
+
return Ok({
|
|
1187
|
+
check: async (serializedPreimage, keyLocation) => withinTimeout(provider.check(serializedPreimage, keyLocation), proveTimeout),
|
|
1188
|
+
prove: async (serializedPreimage, keyLocation, overwriteBindingInput) => withinTimeout(provider.prove(serializedPreimage, keyLocation, overwriteBindingInput), proveTimeout)
|
|
1189
|
+
});
|
|
1190
|
+
} catch (error) {
|
|
1191
|
+
return Err(error instanceof Error ? error : new Error(String(error)));
|
|
1192
|
+
}
|
|
1193
|
+
};
|
|
1194
|
+
//#endregion
|
|
1195
|
+
//#region ../../packages/lib/vendor/src/midnight-connector-transaction.ts
|
|
1196
|
+
init__polyfill_buffer_patch();
|
|
1197
|
+
/** Deserialize a hex-encoded, proven and bound connector transaction. */
|
|
1198
|
+
const deserializeMidnightSealedTransaction = async (tx) => ledger.Transaction.deserialize("signature", "proof", "binding", import_buffer.Buffer.from(tx, "hex"));
|
|
1199
|
+
/** Deserialize a hex-encoded, proven connector transaction that is not yet bound. */
|
|
1200
|
+
const deserializeMidnightUnsealedTransaction = async (tx) => ledger.Transaction.deserialize("signature", "proof", "pre-binding", import_buffer.Buffer.from(tx, "hex"));
|
|
1201
|
+
/**
|
|
1202
|
+
* Groups connector outputs into the wallet SDK's transfer shape, unshielded
|
|
1203
|
+
* first; a kind without outputs is omitted. Throws when a recipient is not a
|
|
1204
|
+
* Bech32m address of its kind on `networkId`.
|
|
1205
|
+
*/
|
|
1206
|
+
const groupMidnightConnectorOutputs = (desiredOutputs, networkId) => {
|
|
1207
|
+
const unshielded = [];
|
|
1208
|
+
const shielded = [];
|
|
1209
|
+
for (const { kind, type, recipient, value } of desiredOutputs) {
|
|
1210
|
+
const parsedAddress = MidnightBech32m.parse(recipient);
|
|
1211
|
+
if (kind === "unshielded") unshielded.push({
|
|
1212
|
+
type,
|
|
1213
|
+
receiverAddress: UnshieldedAddress.codec.decode(networkId, parsedAddress),
|
|
1214
|
+
amount: value
|
|
1215
|
+
});
|
|
1216
|
+
if (kind === "shielded") shielded.push({
|
|
1217
|
+
type,
|
|
1218
|
+
receiverAddress: ShieldedAddress.codec.decode(networkId, parsedAddress),
|
|
1219
|
+
amount: value
|
|
1220
|
+
});
|
|
1221
|
+
}
|
|
1222
|
+
const result = [];
|
|
1223
|
+
if (unshielded.length) result.push({
|
|
1224
|
+
type: "unshielded",
|
|
1225
|
+
outputs: unshielded
|
|
1226
|
+
});
|
|
1227
|
+
if (shielded.length) result.push({
|
|
1228
|
+
type: "shielded",
|
|
1229
|
+
outputs: shielded
|
|
1230
|
+
});
|
|
1231
|
+
return result;
|
|
1232
|
+
};
|
|
1233
|
+
/** Sums connector inputs per kind and token type into the wallet SDK's swap shape. */
|
|
1234
|
+
const groupMidnightConnectorInputs = (desiredInputs) => desiredInputs.reduce((inputs, { kind, type, value }) => {
|
|
1235
|
+
if (kind === "shielded" || kind === "unshielded") {
|
|
1236
|
+
const tokens = inputs[kind] ?? {};
|
|
1237
|
+
tokens[type] = (tokens[type] ?? 0n) + value;
|
|
1238
|
+
inputs[kind] = tokens;
|
|
1239
|
+
}
|
|
1240
|
+
return inputs;
|
|
1241
|
+
}, {});
|
|
1242
|
+
//#endregion
|
|
1243
|
+
//#region src/midnight-connector-transactions.ts
|
|
1244
|
+
const validateOptions = (options) => {
|
|
1245
|
+
if (options !== void 0 && (!options || typeof options !== "object" || Array.isArray(options) || options.payFees !== void 0 && typeof options.payFees !== "boolean")) throw new Error("Invalid Midnight fee options");
|
|
1246
|
+
};
|
|
1247
|
+
const validateTokens = (tokens) => {
|
|
1248
|
+
if (!Array.isArray(tokens)) throw new Error("Expected Midnight token array");
|
|
1249
|
+
for (const token of tokens) {
|
|
1250
|
+
if (!token || token.kind !== "shielded" && token.kind !== "unshielded") throw new Error("Unsupported Midnight token kind");
|
|
1251
|
+
if (typeof token.type !== "string" || !/^[\da-f]{64}$/i.test(token.type)) throw new Error("Expected a raw Midnight ledger token type");
|
|
1252
|
+
if (typeof token.value !== "bigint" || token.value < 0n) throw new Error("Expected a non-negative Midnight token value");
|
|
1253
|
+
}
|
|
1254
|
+
};
|
|
1255
|
+
const validateBalance = ({ tx, options }) => {
|
|
1256
|
+
validateOptions(options);
|
|
1257
|
+
if (typeof tx !== "string" || !/^(?:[\da-f]{2})+$/i.test(tx)) throw new Error("Expected a hexadecimal Midnight transaction");
|
|
1258
|
+
};
|
|
1259
|
+
const reservedBy = (recipe) => recipe.type === "UNPROVEN_TRANSACTION" ? recipe : recipe.balancingTransaction && {
|
|
1260
|
+
type: "UNPROVEN_TRANSACTION",
|
|
1261
|
+
transaction: recipe.balancingTransaction
|
|
1262
|
+
};
|
|
1263
|
+
const finalize$1 = async (wallet, recipe, { sign, proveTimeout }) => {
|
|
1264
|
+
const reserved = reservedBy(recipe);
|
|
1265
|
+
const prepared = sign ? await firstValueFrom(wallet.signRecipe(recipe).pipe(catchError((signingError) => reserved ? releaseThenThrow(wallet, reserved, signingError) : throwError(() => signingError)))) : recipe;
|
|
1266
|
+
return firstValueFrom(wallet.finalizeRecipe(prepared).pipe(timeout(proveTimeout)));
|
|
1267
|
+
};
|
|
1268
|
+
/**
|
|
1269
|
+
* Balances, signs and proves a binding transaction; never submits it.
|
|
1270
|
+
* Obtain consumer consent for the transaction, account and prover disclosure before calling.
|
|
1271
|
+
*/
|
|
1272
|
+
const balanceMidnightSealedTransaction = async (wallet, props) => withMidnightWallet(wallet, props, (engine) => defer(async () => {
|
|
1273
|
+
const proveTimeout = resolveProveTimeout(props.proveTimeout);
|
|
1274
|
+
validateBalance(props);
|
|
1275
|
+
const transaction = await deserializeMidnightSealedTransaction(props.tx);
|
|
1276
|
+
return finalize$1(engine, await firstValueFrom(engine.balanceFinalizedTransaction(transaction, {
|
|
1277
|
+
ttl: new Date(Date.now() + defaultTxTtlLength),
|
|
1278
|
+
tokenKindsToBalance: props.options?.payFees === false ? ["shielded", "unshielded"] : void 0
|
|
1279
|
+
})), {
|
|
1280
|
+
sign: true,
|
|
1281
|
+
proveTimeout
|
|
1282
|
+
});
|
|
1283
|
+
}));
|
|
1284
|
+
/**
|
|
1285
|
+
* Balances, signs and proves a pre-binding transaction; never submits it.
|
|
1286
|
+
* Obtain consumer consent for the transaction, account and prover disclosure before calling.
|
|
1287
|
+
*/
|
|
1288
|
+
const balanceMidnightUnsealedTransaction = async (wallet, props) => withMidnightWallet(wallet, props, (engine) => defer(async () => {
|
|
1289
|
+
const proveTimeout = resolveProveTimeout(props.proveTimeout);
|
|
1290
|
+
validateBalance(props);
|
|
1291
|
+
const transaction = await deserializeMidnightUnsealedTransaction(props.tx);
|
|
1292
|
+
return finalize$1(engine, await firstValueFrom(engine.balanceUnboundTransaction(transaction, {
|
|
1293
|
+
ttl: new Date(Date.now() + defaultTxTtlLength),
|
|
1294
|
+
tokenKindsToBalance: props.options?.payFees === false ? ["shielded", "unshielded"] : void 0
|
|
1295
|
+
})), {
|
|
1296
|
+
sign: true,
|
|
1297
|
+
proveTimeout
|
|
1298
|
+
});
|
|
1299
|
+
}));
|
|
1300
|
+
/**
|
|
1301
|
+
* Builds and proves connector transfers, including mixed token kinds; signs when unshielded outputs exist.
|
|
1302
|
+
* Obtain consumer consent before calling. Returns a native finalized transaction without submitting.
|
|
1303
|
+
* Fees default to enabled; use `buildMidnightTransfers` for separate homogeneous build/sign/prove stages.
|
|
1304
|
+
*/
|
|
1305
|
+
const makeMidnightTransfer = async (wallet, props) => withMidnightWallet(wallet, props, (engine) => defer(async () => {
|
|
1306
|
+
const proveTimeout = resolveProveTimeout(props.proveTimeout);
|
|
1307
|
+
validateOptions(props.options);
|
|
1308
|
+
validateTokens(props.desiredOutputs);
|
|
1309
|
+
const outputs = groupMidnightConnectorOutputs(props.desiredOutputs, engine.networkId);
|
|
1310
|
+
const ttl = new Date(Date.now() + defaultTxTtlLength);
|
|
1311
|
+
return finalize$1(engine, await firstValueFrom(engine.transferTransaction(outputs, {
|
|
1312
|
+
ttl,
|
|
1313
|
+
payFees: false
|
|
1314
|
+
}).pipe(switchMap((built) => props.options?.payFees ?? true ? balanceMidnightRecipe(engine, built, ttl) : of(built)))), {
|
|
1315
|
+
sign: outputs.some((output) => output.type === "unshielded"),
|
|
1316
|
+
proveTimeout
|
|
1317
|
+
});
|
|
1318
|
+
}));
|
|
1319
|
+
const assertOutputKindsHaveInputs = (inputs, outputs) => {
|
|
1320
|
+
const missing = outputs.map((output) => output.type).filter((kind) => inputs[kind] === void 0);
|
|
1321
|
+
if (missing.length > 0) throw new Error(`Midnight intent requests ${missing.join(" and ")} outputs without inputs of that kind, which the wallet library would drop`);
|
|
1322
|
+
};
|
|
1323
|
+
/**
|
|
1324
|
+
* Builds and proves an intent, signing when inputs or outputs include unshielded tokens.
|
|
1325
|
+
* Obtain consumer consent before calling. Never submits. `intentId` is accepted but ignored,
|
|
1326
|
+
* matching the existing connector; no intent ordering is guaranteed. Every output kind
|
|
1327
|
+
* needs an input of the same kind: the wallet library builds a leg from its inputs and
|
|
1328
|
+
* drops the outputs of a kind without any, so such a request is refused before anything
|
|
1329
|
+
* is reserved or signed. When the fee cannot be paid, the inputs the build reserved are
|
|
1330
|
+
* released and the balancing error is returned; if that release fails too, the error is
|
|
1331
|
+
* an `AggregateError` of both failures and the coins stay reserved until a sync reset.
|
|
1332
|
+
*/
|
|
1333
|
+
const makeMidnightIntent = async (wallet, props) => withMidnightWallet(wallet, props, (engine) => defer(async () => {
|
|
1334
|
+
const proveTimeout = resolveProveTimeout(props.proveTimeout);
|
|
1335
|
+
validateOptions(props.options);
|
|
1336
|
+
if (!props.options || typeof props.options.payFees !== "boolean" || props.options.intentId !== "random" && typeof props.options.intentId !== "number") throw new Error("Invalid Midnight intent options");
|
|
1337
|
+
validateTokens(props.desiredInputs);
|
|
1338
|
+
validateTokens(props.desiredOutputs);
|
|
1339
|
+
const inputs = groupMidnightConnectorInputs(props.desiredInputs);
|
|
1340
|
+
const outputs = groupMidnightConnectorOutputs(props.desiredOutputs, engine.networkId);
|
|
1341
|
+
assertOutputKindsHaveInputs(inputs, outputs);
|
|
1342
|
+
const ttl = new Date(Date.now() + defaultTxTtlLength);
|
|
1343
|
+
return finalize$1(engine, await firstValueFrom(engine.initSwap(inputs, outputs, {
|
|
1344
|
+
ttl,
|
|
1345
|
+
payFees: false
|
|
1346
|
+
}).pipe(switchMap((built) => props.options.payFees ? balanceMidnightRecipe(engine, built, ttl) : of(built)))), {
|
|
1347
|
+
sign: !!inputs.unshielded || outputs.some((output) => output.type === "unshielded"),
|
|
1348
|
+
proveTimeout
|
|
1349
|
+
});
|
|
1350
|
+
}));
|
|
1351
|
+
//#endregion
|
|
1352
|
+
export { AccountId, Err, FEATURE_FLAG_MIDNIGHT, FEATURE_FLAG_MIDNIGHT_UNSHIELDED, FEATURE_FLAG_NETWORK_TYPE, MIDNIGHT_LOCAL_PROOF_SERVER_URL, MIDNIGHT_PREVIEW_INDEXER_URL, MIDNIGHT_PREVIEW_NODE_URL, MIDNIGHT_PUBLIC_ENDPOINTS, MidnightAccountId, MidnightAccountNotFoundError, MidnightNetworkId, MidnightNetworkNotConfiguredError, MidnightNothingToRegisterError, MidnightSDKNetworkIds, MidnightSubmitTimeoutError, MidnightWalletNotReadyError, NIGHT_TOKEN_ID, Ok, WalletId, WalletType, balanceMidnightSealedTransaction, balanceMidnightUnsealedTransaction, buildMidnightTransfer, buildMidnightTransfers, createInMemoryWalletEntity, createLaceWallet, createMidnightAccounts, createMidnightModule, createMidnightPasskeyWalletEntity, createPasskeyKeySource, createTemenosAttestedProver, discardMidnightTx, estimateMidnightFee, getMidnightProvingProvider, isForbiddenTokenName, isTakenTokenName, isTokenFullNameValid, isTokenShortNameValid, modules_midnight_exports as m, makeMidnightIntent, makeMidnightTransfer, observeMidnightBalances, proveMidnightTx, registerMidnightDust, selectMidnightNetwork, signMidnightData, signMidnightTx, submitMidnightTx };
|