@bsv/sdk 2.0.16 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- package/dist/cjs/package.json +14 -13
- package/dist/cjs/src/auth/Peer.js +8 -13
- package/dist/cjs/src/auth/Peer.js.map +1 -1
- package/dist/cjs/src/auth/SessionManager.js +4 -7
- package/dist/cjs/src/auth/SessionManager.js.map +1 -1
- package/dist/cjs/src/auth/certificates/MasterCertificate.js +1 -1
- package/dist/cjs/src/auth/certificates/MasterCertificate.js.map +1 -1
- package/dist/cjs/src/auth/certificates/__tests/CompletedProtoWallet.js +1 -1
- package/dist/cjs/src/auth/certificates/__tests/CompletedProtoWallet.js.map +1 -1
- package/dist/cjs/src/auth/clients/AuthFetch.js +32 -32
- package/dist/cjs/src/auth/clients/AuthFetch.js.map +1 -1
- package/dist/cjs/src/auth/transports/SimplifiedFetchTransport.js +4 -4
- package/dist/cjs/src/auth/transports/SimplifiedFetchTransport.js.map +1 -1
- package/dist/cjs/src/compat/ECIES.js +29 -34
- package/dist/cjs/src/compat/ECIES.js.map +1 -1
- package/dist/cjs/src/compat/HD.js +9 -4
- package/dist/cjs/src/compat/HD.js.map +1 -1
- package/dist/cjs/src/compat/Mnemonic.js +12 -12
- package/dist/cjs/src/compat/Mnemonic.js.map +1 -1
- package/dist/cjs/src/identity/ContactsManager.js +172 -232
- package/dist/cjs/src/identity/ContactsManager.js.map +1 -1
- package/dist/cjs/src/identity/IdentityClient.js +122 -55
- package/dist/cjs/src/identity/IdentityClient.js.map +1 -1
- package/dist/cjs/src/kvstore/GlobalKVStore.js +30 -31
- package/dist/cjs/src/kvstore/GlobalKVStore.js.map +1 -1
- package/dist/cjs/src/kvstore/LocalKVStore.js +9 -9
- package/dist/cjs/src/kvstore/LocalKVStore.js.map +1 -1
- package/dist/cjs/src/kvstore/kvStoreInterpreter.js +2 -2
- package/dist/cjs/src/kvstore/kvStoreInterpreter.js.map +1 -1
- package/dist/cjs/src/messages/SignedMessage.js +1 -1
- package/dist/cjs/src/messages/SignedMessage.js.map +1 -1
- package/dist/cjs/src/overlay-tools/Historian.js +1 -1
- package/dist/cjs/src/overlay-tools/Historian.js.map +1 -1
- package/dist/cjs/src/overlay-tools/LookupResolver.js +139 -46
- package/dist/cjs/src/overlay-tools/LookupResolver.js.map +1 -1
- package/dist/cjs/src/overlay-tools/SHIPBroadcaster.js +75 -146
- package/dist/cjs/src/overlay-tools/SHIPBroadcaster.js.map +1 -1
- package/dist/cjs/src/primitives/AESGCM.js +2 -2
- package/dist/cjs/src/primitives/AESGCM.js.map +1 -1
- package/dist/cjs/src/primitives/BigNumber.js +164 -148
- package/dist/cjs/src/primitives/BigNumber.js.map +1 -1
- package/dist/cjs/src/primitives/Curve.js +17 -15
- package/dist/cjs/src/primitives/Curve.js.map +1 -1
- package/dist/cjs/src/primitives/ECDSA.js +12 -7
- package/dist/cjs/src/primitives/ECDSA.js.map +1 -1
- package/dist/cjs/src/primitives/Hash.js +140 -56
- package/dist/cjs/src/primitives/Hash.js.map +1 -1
- package/dist/cjs/src/primitives/JacobianPoint.js +8 -8
- package/dist/cjs/src/primitives/JacobianPoint.js.map +1 -1
- package/dist/cjs/src/primitives/K256.js +3 -3
- package/dist/cjs/src/primitives/K256.js.map +1 -1
- package/dist/cjs/src/primitives/Point.js +36 -40
- package/dist/cjs/src/primitives/Point.js.map +1 -1
- package/dist/cjs/src/primitives/PrivateKey.js +4 -4
- package/dist/cjs/src/primitives/PrivateKey.js.map +1 -1
- package/dist/cjs/src/primitives/PublicKey.js +4 -4
- package/dist/cjs/src/primitives/PublicKey.js.map +1 -1
- package/dist/cjs/src/primitives/Random.js +10 -14
- package/dist/cjs/src/primitives/Random.js.map +1 -1
- package/dist/cjs/src/primitives/ReaderUint8Array.js +6 -6
- package/dist/cjs/src/primitives/ReaderUint8Array.js.map +1 -1
- package/dist/cjs/src/primitives/Schnorr.js +2 -2
- package/dist/cjs/src/primitives/Schnorr.js.map +1 -1
- package/dist/cjs/src/primitives/Secp256r1.js +2 -1
- package/dist/cjs/src/primitives/Secp256r1.js.map +1 -1
- package/dist/cjs/src/primitives/Signature.js +8 -8
- package/dist/cjs/src/primitives/Signature.js.map +1 -1
- package/dist/cjs/src/primitives/TransactionSignature.js +20 -21
- package/dist/cjs/src/primitives/TransactionSignature.js.map +1 -1
- package/dist/cjs/src/primitives/utils.js +39 -46
- package/dist/cjs/src/primitives/utils.js.map +1 -1
- package/dist/cjs/src/registry/RegistryClient.js +31 -23
- package/dist/cjs/src/registry/RegistryClient.js.map +1 -1
- package/dist/cjs/src/remittance/RemittanceManager.js +19 -18
- package/dist/cjs/src/remittance/RemittanceManager.js.map +1 -1
- package/dist/cjs/src/remittance/modules/BasicBRC29.js.map +1 -1
- package/dist/cjs/src/script/Script.js +93 -170
- package/dist/cjs/src/script/Script.js.map +1 -1
- package/dist/cjs/src/script/ScriptEvaluationError.js +2 -2
- package/dist/cjs/src/script/ScriptEvaluationError.js.map +1 -1
- package/dist/cjs/src/script/Spend.js +14 -12
- package/dist/cjs/src/script/Spend.js.map +1 -1
- package/dist/cjs/src/script/templates/PushDrop.js +22 -18
- package/dist/cjs/src/script/templates/PushDrop.js.map +1 -1
- package/dist/cjs/src/script/templates/RPuzzle.js +2 -4
- package/dist/cjs/src/script/templates/RPuzzle.js.map +1 -1
- package/dist/cjs/src/storage/StorageDownloader.js +42 -9
- package/dist/cjs/src/storage/StorageDownloader.js.map +1 -1
- package/dist/cjs/src/totp/totp.js +1 -1
- package/dist/cjs/src/totp/totp.js.map +1 -1
- package/dist/cjs/src/transaction/Beef.js +239 -192
- package/dist/cjs/src/transaction/Beef.js.map +1 -1
- package/dist/cjs/src/transaction/BeefConstants.js +19 -0
- package/dist/cjs/src/transaction/BeefConstants.js.map +1 -0
- package/dist/cjs/src/transaction/BeefTx.js +12 -12
- package/dist/cjs/src/transaction/BeefTx.js.map +1 -1
- package/dist/cjs/src/transaction/MerklePath.js +4 -4
- package/dist/cjs/src/transaction/MerklePath.js.map +1 -1
- package/dist/cjs/src/transaction/Transaction.js +49 -52
- package/dist/cjs/src/transaction/Transaction.js.map +1 -1
- package/dist/cjs/src/transaction/fee-models/SatoshisPerKilobyte.js +1 -1
- package/dist/cjs/src/transaction/fee-models/SatoshisPerKilobyte.js.map +1 -1
- package/dist/cjs/src/transaction/http/BinaryFetchClient.js +9 -9
- package/dist/cjs/src/transaction/http/BinaryFetchClient.js.map +1 -1
- package/dist/cjs/src/transaction/http/DefaultHttpClient.js +9 -9
- package/dist/cjs/src/transaction/http/DefaultHttpClient.js.map +1 -1
- package/dist/cjs/src/wallet/CachedKeyDeriver.js +1 -1
- package/dist/cjs/src/wallet/CachedKeyDeriver.js.map +1 -1
- package/dist/cjs/src/wallet/WalletClient.js.map +1 -1
- package/dist/cjs/src/wallet/WalletError.js.map +1 -1
- package/dist/cjs/src/wallet/substrates/HTTPWalletJSON.js +5 -4
- package/dist/cjs/src/wallet/substrates/HTTPWalletJSON.js.map +1 -1
- package/dist/cjs/src/wallet/substrates/ReactNativeWebView.js +9 -9
- package/dist/cjs/src/wallet/substrates/ReactNativeWebView.js.map +1 -1
- package/dist/cjs/src/wallet/substrates/WalletWireProcessor.js +92 -92
- package/dist/cjs/src/wallet/substrates/WalletWireProcessor.js.map +1 -1
- package/dist/cjs/src/wallet/substrates/WalletWireTransceiver.js +387 -711
- package/dist/cjs/src/wallet/substrates/WalletWireTransceiver.js.map +1 -1
- package/dist/cjs/src/wallet/substrates/XDM.js +4 -4
- package/dist/cjs/src/wallet/substrates/XDM.js.map +1 -1
- package/dist/cjs/src/wallet/substrates/window.CWI.js +2 -2
- package/dist/cjs/src/wallet/substrates/window.CWI.js.map +1 -1
- package/dist/cjs/src/wallet/validationHelpers.js +9 -9
- package/dist/cjs/src/wallet/validationHelpers.js.map +1 -1
- package/dist/cjs/tsconfig.cjs.tsbuildinfo +1 -1
- package/dist/esm/src/auth/Peer.js +25 -13
- package/dist/esm/src/auth/Peer.js.map +1 -1
- package/dist/esm/src/auth/SessionManager.js +4 -7
- package/dist/esm/src/auth/SessionManager.js.map +1 -1
- package/dist/esm/src/auth/certificates/MasterCertificate.js +1 -1
- package/dist/esm/src/auth/certificates/MasterCertificate.js.map +1 -1
- package/dist/esm/src/auth/certificates/__tests/CompletedProtoWallet.js +1 -1
- package/dist/esm/src/auth/certificates/__tests/CompletedProtoWallet.js.map +1 -1
- package/dist/esm/src/auth/clients/AuthFetch.js +32 -32
- package/dist/esm/src/auth/clients/AuthFetch.js.map +1 -1
- package/dist/esm/src/auth/transports/SimplifiedFetchTransport.js +4 -4
- package/dist/esm/src/auth/transports/SimplifiedFetchTransport.js.map +1 -1
- package/dist/esm/src/compat/ECIES.js +29 -34
- package/dist/esm/src/compat/ECIES.js.map +1 -1
- package/dist/esm/src/compat/HD.js +9 -4
- package/dist/esm/src/compat/HD.js.map +1 -1
- package/dist/esm/src/compat/Mnemonic.js +12 -12
- package/dist/esm/src/compat/Mnemonic.js.map +1 -1
- package/dist/esm/src/identity/ContactsManager.js +172 -232
- package/dist/esm/src/identity/ContactsManager.js.map +1 -1
- package/dist/esm/src/identity/IdentityClient.js +122 -55
- package/dist/esm/src/identity/IdentityClient.js.map +1 -1
- package/dist/esm/src/kvstore/GlobalKVStore.js +30 -31
- package/dist/esm/src/kvstore/GlobalKVStore.js.map +1 -1
- package/dist/esm/src/kvstore/LocalKVStore.js +9 -9
- package/dist/esm/src/kvstore/LocalKVStore.js.map +1 -1
- package/dist/esm/src/kvstore/kvStoreInterpreter.js +2 -2
- package/dist/esm/src/kvstore/kvStoreInterpreter.js.map +1 -1
- package/dist/esm/src/messages/SignedMessage.js +1 -1
- package/dist/esm/src/messages/SignedMessage.js.map +1 -1
- package/dist/esm/src/overlay-tools/Historian.js +1 -1
- package/dist/esm/src/overlay-tools/Historian.js.map +1 -1
- package/dist/esm/src/overlay-tools/LookupResolver.js +139 -46
- package/dist/esm/src/overlay-tools/LookupResolver.js.map +1 -1
- package/dist/esm/src/overlay-tools/SHIPBroadcaster.js +74 -146
- package/dist/esm/src/overlay-tools/SHIPBroadcaster.js.map +1 -1
- package/dist/esm/src/primitives/AESGCM.js +2 -2
- package/dist/esm/src/primitives/AESGCM.js.map +1 -1
- package/dist/esm/src/primitives/BigNumber.js +167 -154
- package/dist/esm/src/primitives/BigNumber.js.map +1 -1
- package/dist/esm/src/primitives/Curve.js +17 -15
- package/dist/esm/src/primitives/Curve.js.map +1 -1
- package/dist/esm/src/primitives/ECDSA.js +12 -7
- package/dist/esm/src/primitives/ECDSA.js.map +1 -1
- package/dist/esm/src/primitives/Hash.js +140 -56
- package/dist/esm/src/primitives/Hash.js.map +1 -1
- package/dist/esm/src/primitives/JacobianPoint.js +8 -8
- package/dist/esm/src/primitives/JacobianPoint.js.map +1 -1
- package/dist/esm/src/primitives/K256.js +3 -3
- package/dist/esm/src/primitives/K256.js.map +1 -1
- package/dist/esm/src/primitives/Point.js +36 -40
- package/dist/esm/src/primitives/Point.js.map +1 -1
- package/dist/esm/src/primitives/PrivateKey.js +4 -4
- package/dist/esm/src/primitives/PrivateKey.js.map +1 -1
- package/dist/esm/src/primitives/PublicKey.js +4 -4
- package/dist/esm/src/primitives/PublicKey.js.map +1 -1
- package/dist/esm/src/primitives/Random.js +10 -14
- package/dist/esm/src/primitives/Random.js.map +1 -1
- package/dist/esm/src/primitives/ReaderUint8Array.js +6 -6
- package/dist/esm/src/primitives/ReaderUint8Array.js.map +1 -1
- package/dist/esm/src/primitives/Schnorr.js +1 -1
- package/dist/esm/src/primitives/Schnorr.js.map +1 -1
- package/dist/esm/src/primitives/Secp256r1.js +2 -1
- package/dist/esm/src/primitives/Secp256r1.js.map +1 -1
- package/dist/esm/src/primitives/Signature.js +8 -8
- package/dist/esm/src/primitives/Signature.js.map +1 -1
- package/dist/esm/src/primitives/TransactionSignature.js +20 -21
- package/dist/esm/src/primitives/TransactionSignature.js.map +1 -1
- package/dist/esm/src/primitives/utils.js +39 -48
- package/dist/esm/src/primitives/utils.js.map +1 -1
- package/dist/esm/src/registry/RegistryClient.js +31 -23
- package/dist/esm/src/registry/RegistryClient.js.map +1 -1
- package/dist/esm/src/remittance/RemittanceManager.js +19 -18
- package/dist/esm/src/remittance/RemittanceManager.js.map +1 -1
- package/dist/esm/src/remittance/modules/BasicBRC29.js.map +1 -1
- package/dist/esm/src/script/Script.js +93 -170
- package/dist/esm/src/script/Script.js.map +1 -1
- package/dist/esm/src/script/ScriptEvaluationError.js +2 -2
- package/dist/esm/src/script/ScriptEvaluationError.js.map +1 -1
- package/dist/esm/src/script/Spend.js +14 -12
- package/dist/esm/src/script/Spend.js.map +1 -1
- package/dist/esm/src/script/templates/PushDrop.js +4 -3
- package/dist/esm/src/script/templates/PushDrop.js.map +1 -1
- package/dist/esm/src/script/templates/RPuzzle.js +2 -4
- package/dist/esm/src/script/templates/RPuzzle.js.map +1 -1
- package/dist/esm/src/storage/StorageDownloader.js +1 -1
- package/dist/esm/src/storage/StorageDownloader.js.map +1 -1
- package/dist/esm/src/totp/totp.js +1 -1
- package/dist/esm/src/totp/totp.js.map +1 -1
- package/dist/esm/src/transaction/Beef.js +229 -186
- package/dist/esm/src/transaction/Beef.js.map +1 -1
- package/dist/esm/src/transaction/BeefConstants.js +16 -0
- package/dist/esm/src/transaction/BeefConstants.js.map +1 -0
- package/dist/esm/src/transaction/BeefTx.js +3 -3
- package/dist/esm/src/transaction/BeefTx.js.map +1 -1
- package/dist/esm/src/transaction/MerklePath.js +4 -4
- package/dist/esm/src/transaction/MerklePath.js.map +1 -1
- package/dist/esm/src/transaction/Transaction.js +49 -52
- package/dist/esm/src/transaction/Transaction.js.map +1 -1
- package/dist/esm/src/transaction/fee-models/SatoshisPerKilobyte.js +1 -1
- package/dist/esm/src/transaction/fee-models/SatoshisPerKilobyte.js.map +1 -1
- package/dist/esm/src/transaction/http/BinaryFetchClient.js +9 -9
- package/dist/esm/src/transaction/http/BinaryFetchClient.js.map +1 -1
- package/dist/esm/src/transaction/http/DefaultHttpClient.js +9 -9
- package/dist/esm/src/transaction/http/DefaultHttpClient.js.map +1 -1
- package/dist/esm/src/wallet/CachedKeyDeriver.js +1 -1
- package/dist/esm/src/wallet/CachedKeyDeriver.js.map +1 -1
- package/dist/esm/src/wallet/WalletClient.js.map +1 -1
- package/dist/esm/src/wallet/WalletError.js.map +1 -1
- package/dist/esm/src/wallet/substrates/HTTPWalletJSON.js +5 -4
- package/dist/esm/src/wallet/substrates/HTTPWalletJSON.js.map +1 -1
- package/dist/esm/src/wallet/substrates/ReactNativeWebView.js +9 -9
- package/dist/esm/src/wallet/substrates/ReactNativeWebView.js.map +1 -1
- package/dist/esm/src/wallet/substrates/WalletWireProcessor.js +92 -92
- package/dist/esm/src/wallet/substrates/WalletWireProcessor.js.map +1 -1
- package/dist/esm/src/wallet/substrates/WalletWireTransceiver.js +387 -711
- package/dist/esm/src/wallet/substrates/WalletWireTransceiver.js.map +1 -1
- package/dist/esm/src/wallet/substrates/XDM.js +4 -4
- package/dist/esm/src/wallet/substrates/XDM.js.map +1 -1
- package/dist/esm/src/wallet/substrates/window.CWI.js +2 -2
- package/dist/esm/src/wallet/substrates/window.CWI.js.map +1 -1
- package/dist/esm/src/wallet/validationHelpers.js +9 -9
- package/dist/esm/src/wallet/validationHelpers.js.map +1 -1
- package/dist/esm/tsconfig.esm.tsbuildinfo +1 -1
- package/dist/types/src/auth/Peer.d.ts +13 -0
- package/dist/types/src/auth/Peer.d.ts.map +1 -1
- package/dist/types/src/auth/SessionManager.d.ts.map +1 -1
- package/dist/types/src/auth/clients/AuthFetch.d.ts.map +1 -1
- package/dist/types/src/compat/ECIES.d.ts.map +1 -1
- package/dist/types/src/compat/HD.d.ts.map +1 -1
- package/dist/types/src/identity/ContactsManager.d.ts +18 -0
- package/dist/types/src/identity/ContactsManager.d.ts.map +1 -1
- package/dist/types/src/identity/IdentityClient.d.ts +47 -8
- package/dist/types/src/identity/IdentityClient.d.ts.map +1 -1
- package/dist/types/src/kvstore/GlobalKVStore.d.ts.map +1 -1
- package/dist/types/src/overlay-tools/LookupResolver.d.ts +59 -1
- package/dist/types/src/overlay-tools/LookupResolver.d.ts.map +1 -1
- package/dist/types/src/overlay-tools/SHIPBroadcaster.d.ts +18 -3
- package/dist/types/src/overlay-tools/SHIPBroadcaster.d.ts.map +1 -1
- package/dist/types/src/primitives/BigNumber.d.ts +13 -3
- package/dist/types/src/primitives/BigNumber.d.ts.map +1 -1
- package/dist/types/src/primitives/Curve.d.ts.map +1 -1
- package/dist/types/src/primitives/ECDSA.d.ts.map +1 -1
- package/dist/types/src/primitives/Hash.d.ts +3 -3
- package/dist/types/src/primitives/Hash.d.ts.map +1 -1
- package/dist/types/src/primitives/JacobianPoint.d.ts +3 -1
- package/dist/types/src/primitives/JacobianPoint.d.ts.map +1 -1
- package/dist/types/src/primitives/Point.d.ts.map +1 -1
- package/dist/types/src/primitives/Random.d.ts +2 -2
- package/dist/types/src/primitives/Random.d.ts.map +1 -1
- package/dist/types/src/primitives/ReaderUint8Array.d.ts.map +1 -1
- package/dist/types/src/primitives/Schnorr.d.ts +2 -1
- package/dist/types/src/primitives/Schnorr.d.ts.map +1 -1
- package/dist/types/src/primitives/Secp256r1.d.ts.map +1 -1
- package/dist/types/src/primitives/utils.d.ts +2 -4
- package/dist/types/src/primitives/utils.d.ts.map +1 -1
- package/dist/types/src/registry/RegistryClient.d.ts.map +1 -1
- package/dist/types/src/remittance/RemittanceManager.d.ts.map +1 -1
- package/dist/types/src/remittance/modules/BasicBRC29.d.ts.map +1 -1
- package/dist/types/src/script/Script.d.ts +15 -8
- package/dist/types/src/script/Script.d.ts.map +1 -1
- package/dist/types/src/script/Spend.d.ts.map +1 -1
- package/dist/types/src/script/templates/PushDrop.d.ts +3 -1
- package/dist/types/src/script/templates/PushDrop.d.ts.map +1 -1
- package/dist/types/src/script/templates/RPuzzle.d.ts.map +1 -1
- package/dist/types/src/transaction/Beef.d.ts +46 -8
- package/dist/types/src/transaction/Beef.d.ts.map +1 -1
- package/dist/types/src/transaction/BeefConstants.d.ts +15 -0
- package/dist/types/src/transaction/BeefConstants.d.ts.map +1 -0
- package/dist/types/src/transaction/Transaction.d.ts.map +1 -1
- package/dist/types/src/wallet/CachedKeyDeriver.d.ts.map +1 -1
- package/dist/types/src/wallet/KeyDeriver.d.ts +1 -1
- package/dist/types/src/wallet/KeyDeriver.d.ts.map +1 -1
- package/dist/types/src/wallet/Wallet.interfaces.d.ts +2 -2
- package/dist/types/src/wallet/Wallet.interfaces.d.ts.map +1 -1
- package/dist/types/src/wallet/WalletClient.d.ts +7 -7
- package/dist/types/src/wallet/WalletClient.d.ts.map +1 -1
- package/dist/types/src/wallet/substrates/HTTPWalletJSON.d.ts +7 -7
- package/dist/types/src/wallet/substrates/HTTPWalletJSON.d.ts.map +1 -1
- package/dist/types/src/wallet/substrates/WalletWireTransceiver.d.ts +36 -7
- package/dist/types/src/wallet/substrates/WalletWireTransceiver.d.ts.map +1 -1
- package/dist/types/src/wallet/substrates/window.CWI.d.ts +8 -8
- package/dist/types/src/wallet/substrates/window.CWI.d.ts.map +1 -1
- package/dist/types/tsconfig.types.tsbuildinfo +1 -1
- package/dist/umd/bundle.js +3 -3
- package/docs/reference/kvstore.md +1 -2
- package/docs/reference/primitives.md +0 -1
- package/docs/reference/script.md +0 -7
- package/docs/reference/transaction.md +2 -2
- package/package.json +29 -28
- package/src/auth/Peer.ts +26 -13
- package/src/auth/SessionManager.ts +4 -7
- package/src/auth/certificates/MasterCertificate.ts +1 -1
- package/src/auth/certificates/__tests/CompletedProtoWallet.ts +1 -1
- package/src/auth/clients/AuthFetch.ts +41 -41
- package/src/auth/transports/SimplifiedFetchTransport.ts +4 -4
- package/src/compat/ECIES.ts +29 -34
- package/src/compat/HD.ts +10 -5
- package/src/compat/Mnemonic.ts +11 -11
- package/src/compat/__tests/HD.test.ts +19 -0
- package/src/identity/ContactsManager.ts +194 -257
- package/src/identity/IdentityClient.ts +155 -66
- package/src/identity/__tests/IdentityClient.test.ts +25 -1
- package/src/kvstore/GlobalKVStore.ts +31 -32
- package/src/kvstore/LocalKVStore.ts +8 -8
- package/src/kvstore/kvStoreInterpreter.ts +2 -2
- package/src/messages/SignedMessage.ts +1 -1
- package/src/overlay-tools/Historian.ts +1 -1
- package/src/overlay-tools/LookupResolver.ts +182 -45
- package/src/overlay-tools/SHIPBroadcaster.ts +92 -168
- package/src/primitives/AESGCM.ts +2 -2
- package/src/primitives/BigNumber.ts +122 -113
- package/src/primitives/Curve.ts +16 -15
- package/src/primitives/ECDSA.ts +10 -8
- package/src/primitives/Hash.ts +152 -53
- package/src/primitives/JacobianPoint.ts +13 -11
- package/src/primitives/K256.ts +3 -3
- package/src/primitives/Point.ts +35 -38
- package/src/primitives/PrivateKey.ts +3 -3
- package/src/primitives/PublicKey.ts +3 -3
- package/src/primitives/Random.ts +11 -14
- package/src/primitives/ReaderUint8Array.ts +7 -7
- package/src/primitives/Schnorr.ts +2 -1
- package/src/primitives/Secp256r1.ts +2 -1
- package/src/primitives/Signature.ts +8 -8
- package/src/primitives/TransactionSignature.ts +16 -16
- package/src/primitives/utils.ts +37 -47
- package/src/registry/RegistryClient.ts +25 -25
- package/src/remittance/RemittanceManager.ts +17 -18
- package/src/remittance/modules/BasicBRC29.ts +2 -5
- package/src/script/Script.ts +114 -170
- package/src/script/ScriptEvaluationError.ts +2 -2
- package/src/script/Spend.ts +14 -15
- package/src/script/templates/PushDrop.ts +5 -3
- package/src/script/templates/RPuzzle.ts +2 -4
- package/src/storage/StorageDownloader.ts +1 -1
- package/src/totp/totp.ts +1 -1
- package/src/transaction/Beef.ts +241 -203
- package/src/transaction/BeefConstants.ts +16 -0
- package/src/transaction/BeefTx.ts +3 -3
- package/src/transaction/MerklePath.ts +4 -4
- package/src/transaction/Transaction.ts +48 -51
- package/src/transaction/fee-models/SatoshisPerKilobyte.ts +1 -1
- package/src/transaction/http/BinaryFetchClient.ts +8 -8
- package/src/transaction/http/DefaultHttpClient.ts +8 -8
- package/src/wallet/CachedKeyDeriver.ts +8 -6
- package/src/wallet/KeyDeriver.ts +1 -1
- package/src/wallet/Wallet.interfaces.ts +2 -4
- package/src/wallet/WalletClient.ts +8 -8
- package/src/wallet/WalletError.ts +1 -1
- package/src/wallet/__tests/WalletClient.substrate.test.ts +10 -6
- package/src/wallet/substrates/HTTPWalletJSON.ts +22 -21
- package/src/wallet/substrates/ReactNativeWebView.ts +9 -9
- package/src/wallet/substrates/WalletWireProcessor.ts +83 -83
- package/src/wallet/substrates/WalletWireTransceiver.ts +528 -938
- package/src/wallet/substrates/XDM.ts +4 -4
- package/src/wallet/substrates/__tests/HTTPWalletJSON.test.ts +38 -25
- package/src/wallet/substrates/__tests/ReactNativeWebView.test.ts +174 -0
- package/src/wallet/substrates/__tests/window.CWI.test.ts +256 -0
- package/src/wallet/substrates/window.CWI.ts +10 -10
- package/src/wallet/validationHelpers.ts +9 -9
- package/docs/swagger/dist/LICENSE +0 -21
- package/docs/swagger/dist/favicon-16x16.png +0 -0
- package/docs/swagger/dist/favicon-32x32.png +0 -0
- package/docs/swagger/dist/index.css +0 -16
- package/docs/swagger/dist/oauth2-redirect.html +0 -79
- package/docs/swagger/dist/swagger-initializer.js +0 -20
- package/docs/swagger/dist/swagger-ui-bundle.js +0 -2
- package/docs/swagger/dist/swagger-ui-bundle.js.map +0 -1
- package/docs/swagger/dist/swagger-ui-es-bundle-core.js +0 -3
- package/docs/swagger/dist/swagger-ui-es-bundle-core.js.map +0 -1
- package/docs/swagger/dist/swagger-ui-es-bundle.js +0 -2
- package/docs/swagger/dist/swagger-ui-es-bundle.js.map +0 -1
- package/docs/swagger/dist/swagger-ui-standalone-preset.js +0 -2
- package/docs/swagger/dist/swagger-ui-standalone-preset.js.map +0 -1
- package/docs/swagger/dist/swagger-ui.css +0 -3
- package/docs/swagger/dist/swagger-ui.css.map +0 -1
- package/docs/swagger/dist/swagger-ui.js +0 -2
- package/docs/swagger/dist/swagger-ui.js.map +0 -1
|
@@ -47,55 +47,61 @@ export class ContactsManager {
|
|
|
47
47
|
* @returns A promise that resolves with an array of contacts
|
|
48
48
|
*/
|
|
49
49
|
async getContacts (identityKey?: PubKeyHex, forceRefresh = false, limit = 1000): Promise<Contact[]> {
|
|
50
|
-
// Check in-memory cache first unless forcing refresh
|
|
51
50
|
if (!forceRefresh) {
|
|
52
|
-
const
|
|
53
|
-
if (
|
|
54
|
-
try {
|
|
55
|
-
const cachedContacts: Contact[] = JSON.parse(cached)
|
|
56
|
-
return identityKey != null
|
|
57
|
-
? cachedContacts.filter(c => c.identityKey === identityKey)
|
|
58
|
-
: cachedContacts
|
|
59
|
-
} catch (e) {
|
|
60
|
-
console.warn('Invalid cached contacts JSON; will reload from chain', e)
|
|
61
|
-
}
|
|
62
|
-
}
|
|
51
|
+
const fromCache = this.loadCachedContacts(identityKey)
|
|
52
|
+
if (fromCache !== null) return fromCache
|
|
63
53
|
}
|
|
64
54
|
|
|
65
|
-
const tags
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
keyID: identityKey,
|
|
71
|
-
counterparty: 'self',
|
|
72
|
-
data: Utils.toArray(identityKey, 'utf8')
|
|
73
|
-
}, this.originator)
|
|
74
|
-
tags.push(`identityKey ${Utils.toHex(hashedIdentityKey)}`)
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// Get all contact outputs from the contacts basket
|
|
78
|
-
const outputs = await this.wallet.listOutputs({
|
|
79
|
-
basket: 'contacts',
|
|
80
|
-
include: 'locking scripts',
|
|
81
|
-
includeCustomInstructions: true,
|
|
82
|
-
tags,
|
|
83
|
-
limit
|
|
84
|
-
}, this.originator)
|
|
55
|
+
const tags = await this.buildIdentityKeyTags(identityKey)
|
|
56
|
+
const outputs = await this.wallet.listOutputs(
|
|
57
|
+
{ basket: 'contacts', include: 'locking scripts', includeCustomInstructions: true, tags, limit },
|
|
58
|
+
this.originator
|
|
59
|
+
)
|
|
85
60
|
|
|
86
61
|
if (outputs.outputs == null || outputs.outputs.length === 0) {
|
|
87
62
|
this.cache.setItem(this.CONTACTS_CACHE_KEY, JSON.stringify([]))
|
|
88
63
|
return []
|
|
89
64
|
}
|
|
90
65
|
|
|
91
|
-
|
|
92
|
-
|
|
66
|
+
const contacts = await this.decryptContactOutputs(outputs.outputs)
|
|
67
|
+
this.cache.setItem(this.CONTACTS_CACHE_KEY, JSON.stringify(contacts))
|
|
68
|
+
return identityKey != null ? contacts.filter(c => c.identityKey === identityKey) : contacts
|
|
69
|
+
}
|
|
93
70
|
|
|
94
|
-
|
|
71
|
+
/** Returns cached contacts (optionally filtered) or null if cache is missing/invalid. */
|
|
72
|
+
private loadCachedContacts (identityKey?: PubKeyHex): Contact[] | null {
|
|
73
|
+
const cached = this.cache.getItem(this.CONTACTS_CACHE_KEY)
|
|
74
|
+
if (cached == null || cached === '') return null
|
|
75
|
+
try {
|
|
76
|
+
const cachedContacts: Contact[] = JSON.parse(cached)
|
|
77
|
+
return identityKey != null ? cachedContacts.filter(c => c.identityKey === identityKey) : cachedContacts
|
|
78
|
+
} catch (e) {
|
|
79
|
+
console.warn('Invalid cached contacts JSON; will reload from chain', e)
|
|
80
|
+
return null
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** Builds the HMAC-based identity-key tag array; empty array if no identity key is given. */
|
|
85
|
+
private async buildIdentityKeyTags (identityKey?: PubKeyHex): Promise<string[]> {
|
|
86
|
+
if (identityKey == null) return []
|
|
87
|
+
const { hmac: hashedIdentityKey } = await this.wallet.createHmac({
|
|
88
|
+
protocolID: CONTACT_PROTOCOL_ID,
|
|
89
|
+
keyID: identityKey,
|
|
90
|
+
counterparty: 'self',
|
|
91
|
+
data: Utils.toArray(identityKey, 'utf8')
|
|
92
|
+
}, this.originator)
|
|
93
|
+
return [`identityKey ${Utils.toHex(hashedIdentityKey)}`]
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Decodes and decrypts all contact outputs in parallel, returning valid Contact objects. */
|
|
97
|
+
private async decryptContactOutputs (
|
|
98
|
+
rawOutputs: Awaited<ReturnType<WalletInterface['listOutputs']>>['outputs']
|
|
99
|
+
): Promise<Contact[]> {
|
|
100
|
+
const decryptTasks: Array<{ keyID: string, ciphertext: number[] }> = []
|
|
101
|
+
for (const output of rawOutputs) {
|
|
95
102
|
try {
|
|
96
|
-
if (output.lockingScript == null) continue
|
|
103
|
+
if (output.lockingScript == null || output.customInstructions == null) continue
|
|
97
104
|
const decoded = PushDrop.decode(LockingScript.fromHex(output.lockingScript))
|
|
98
|
-
if (output.customInstructions == null) continue
|
|
99
105
|
const keyID = JSON.parse(output.customInstructions).keyID
|
|
100
106
|
decryptTasks.push({ keyID, ciphertext: decoded.fields[0] })
|
|
101
107
|
} catch (error) {
|
|
@@ -103,25 +109,17 @@ export class ContactsManager {
|
|
|
103
109
|
}
|
|
104
110
|
}
|
|
105
111
|
|
|
106
|
-
// Decrypt all contacts in parallel — each call is a network round-trip over localhost
|
|
107
112
|
const decryptResults = await Promise.allSettled(
|
|
108
113
|
decryptTasks.map(async task =>
|
|
109
|
-
await this.wallet.decrypt({
|
|
110
|
-
ciphertext: task.ciphertext,
|
|
111
|
-
protocolID: CONTACT_PROTOCOL_ID,
|
|
112
|
-
keyID: task.keyID,
|
|
113
|
-
counterparty: 'self'
|
|
114
|
-
}, this.originator)
|
|
114
|
+
await this.wallet.decrypt({ ciphertext: task.ciphertext, protocolID: CONTACT_PROTOCOL_ID, keyID: task.keyID, counterparty: 'self' }, this.originator)
|
|
115
115
|
)
|
|
116
116
|
)
|
|
117
117
|
|
|
118
118
|
const contacts: Contact[] = []
|
|
119
|
-
for (
|
|
120
|
-
const result = decryptResults[i]
|
|
119
|
+
for (const result of decryptResults) {
|
|
121
120
|
if (result.status === 'fulfilled') {
|
|
122
121
|
try {
|
|
123
|
-
|
|
124
|
-
contacts.push(contactData)
|
|
122
|
+
contacts.push(JSON.parse(Utils.toUTF8(result.value.plaintext)) as Contact)
|
|
125
123
|
} catch (error) {
|
|
126
124
|
console.warn('ContactsManager: Failed to parse contact data:', error)
|
|
127
125
|
}
|
|
@@ -129,13 +127,7 @@ export class ContactsManager {
|
|
|
129
127
|
console.warn('ContactsManager: Failed to decrypt contact output:', result.reason)
|
|
130
128
|
}
|
|
131
129
|
}
|
|
132
|
-
|
|
133
|
-
// Cache the loaded contacts
|
|
134
|
-
this.cache.setItem(this.CONTACTS_CACHE_KEY, JSON.stringify(contacts))
|
|
135
|
-
const filteredContacts = identityKey != null
|
|
136
|
-
? contacts.filter(c => c.identityKey === identityKey)
|
|
137
|
-
: contacts
|
|
138
|
-
return filteredContacts
|
|
130
|
+
return contacts
|
|
139
131
|
}
|
|
140
132
|
|
|
141
133
|
/**
|
|
@@ -144,152 +136,123 @@ export class ContactsManager {
|
|
|
144
136
|
* @param metadata Optional metadata to store with the contact (ex. notes, aliases, etc)
|
|
145
137
|
*/
|
|
146
138
|
async saveContact (contact: DisplayableIdentity, metadata?: Record<string, any>): Promise<void> {
|
|
147
|
-
// Get current contacts from cache or blockchain
|
|
148
139
|
const cached = this.cache.getItem(this.CONTACTS_CACHE_KEY)
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
contacts = JSON.parse(cached)
|
|
152
|
-
} else {
|
|
153
|
-
// If cache is empty, get current data from blockchain
|
|
154
|
-
contacts = await this.getContacts()
|
|
155
|
-
}
|
|
156
|
-
|
|
140
|
+
const contacts: Contact[] = (cached != null && cached !== '') ? JSON.parse(cached) : await this.getContacts()
|
|
141
|
+
const contactToStore: Contact = { ...contact, metadata }
|
|
157
142
|
const existingIndex = contacts.findIndex(c => c.identityKey === contact.identityKey)
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
143
|
+
if (existingIndex >= 0) contacts[existingIndex] = contactToStore
|
|
144
|
+
else contacts.push(contactToStore)
|
|
145
|
+
|
|
146
|
+
const hashedIdentityKey = await this.hashIdentityKey(contact.identityKey)
|
|
147
|
+
const outputs = await this.wallet.listOutputs({
|
|
148
|
+
basket: 'contacts', include: 'entire transactions', includeCustomInstructions: true,
|
|
149
|
+
tags: [`identityKey ${Utils.toHex(hashedIdentityKey)}`], limit: 100
|
|
150
|
+
}, this.originator)
|
|
151
|
+
|
|
152
|
+
const { existingOutput, keyID } = await this.findExistingOutput(outputs, contact.identityKey)
|
|
153
|
+
const lockingScript = await this.encryptAndLock(contactToStore, keyID)
|
|
162
154
|
|
|
163
|
-
if (
|
|
164
|
-
|
|
155
|
+
if (existingOutput != null) {
|
|
156
|
+
await this.updateContactOutput(outputs, existingOutput, lockingScript, keyID, hashedIdentityKey, contact)
|
|
165
157
|
} else {
|
|
166
|
-
|
|
158
|
+
await this.createContactOutput(lockingScript, keyID, hashedIdentityKey, contact)
|
|
167
159
|
}
|
|
160
|
+
this.cache.setItem(this.CONTACTS_CACHE_KEY, JSON.stringify(contacts))
|
|
161
|
+
}
|
|
168
162
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
counterparty: 'self',
|
|
173
|
-
data: Utils.toArray(
|
|
174
|
-
}, this.originator)
|
|
175
|
-
|
|
176
|
-
// Check if this contact already exists (to update it)
|
|
177
|
-
const outputs = await this.wallet.listOutputs({
|
|
178
|
-
basket: 'contacts',
|
|
179
|
-
include: 'entire transactions',
|
|
180
|
-
includeCustomInstructions: true,
|
|
181
|
-
tags: [`identityKey ${Utils.toHex(hashedIdentityKey)}`],
|
|
182
|
-
limit: 100 // Should only be one contact!
|
|
163
|
+
/** Computes the HMAC-based hash of an identity key for tag indexing. */
|
|
164
|
+
private async hashIdentityKey (identityKey: string): Promise<number[]> {
|
|
165
|
+
const { hmac } = await this.wallet.createHmac({
|
|
166
|
+
protocolID: CONTACT_PROTOCOL_ID, keyID: identityKey, counterparty: 'self',
|
|
167
|
+
data: Utils.toArray(identityKey, 'utf8')
|
|
183
168
|
}, this.originator)
|
|
169
|
+
return hmac
|
|
170
|
+
}
|
|
184
171
|
|
|
172
|
+
/** Scans existing outputs to find the one matching the given identity key; returns output + keyID. */
|
|
173
|
+
private async findExistingOutput (
|
|
174
|
+
outputs: Awaited<ReturnType<WalletInterface['listOutputs']>>,
|
|
175
|
+
identityKey: string
|
|
176
|
+
): Promise<{ existingOutput: any, keyID: string }> {
|
|
185
177
|
let existingOutput: any = null
|
|
186
178
|
let keyID = Utils.toBase64(Random(32))
|
|
187
|
-
if (outputs.outputs
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
counterparty: 'self'
|
|
202
|
-
}, this.originator)
|
|
203
|
-
|
|
204
|
-
const storedContact: Contact = JSON.parse(Utils.toUTF8(plaintext))
|
|
205
|
-
if (storedContact.identityKey === contact.identityKey) {
|
|
206
|
-
// Found the right output
|
|
207
|
-
existingOutput = output
|
|
208
|
-
break
|
|
209
|
-
}
|
|
210
|
-
} catch (e) {
|
|
211
|
-
// Skip malformed or undecryptable outputs
|
|
212
|
-
}
|
|
213
|
-
}
|
|
179
|
+
if (outputs.outputs == null) return { existingOutput, keyID }
|
|
180
|
+
for (const output of outputs.outputs) {
|
|
181
|
+
try {
|
|
182
|
+
const [txid, outputIndex] = output.outpoint.split('.')
|
|
183
|
+
const tx = Transaction.fromBEEF(outputs.BEEF as number[], txid)
|
|
184
|
+
const decoded = PushDrop.decode(tx.outputs[Number(outputIndex)].lockingScript)
|
|
185
|
+
if (output.customInstructions == null) continue
|
|
186
|
+
keyID = JSON.parse(output.customInstructions).keyID
|
|
187
|
+
const { plaintext } = await this.wallet.decrypt(
|
|
188
|
+
{ ciphertext: decoded.fields[0], protocolID: CONTACT_PROTOCOL_ID, keyID, counterparty: 'self' }, this.originator
|
|
189
|
+
)
|
|
190
|
+
const storedContact: Contact = JSON.parse(Utils.toUTF8(plaintext))
|
|
191
|
+
if (storedContact.identityKey === identityKey) { existingOutput = output; break }
|
|
192
|
+
} catch (_malformedOrUndecryptableOutput) { /* skip */ }
|
|
214
193
|
}
|
|
194
|
+
return { existingOutput, keyID }
|
|
195
|
+
}
|
|
215
196
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
...contact,
|
|
219
|
-
metadata
|
|
220
|
-
}
|
|
197
|
+
/** Encrypts a contact and produces its PushDrop locking script. */
|
|
198
|
+
private async encryptAndLock (contactData: Contact, keyID: string): Promise<LockingScript> {
|
|
221
199
|
const { ciphertext } = await this.wallet.encrypt({
|
|
222
|
-
plaintext: Utils.toArray(JSON.stringify(
|
|
223
|
-
protocolID: CONTACT_PROTOCOL_ID,
|
|
224
|
-
keyID,
|
|
225
|
-
counterparty: 'self'
|
|
200
|
+
plaintext: Utils.toArray(JSON.stringify(contactData), 'utf8'),
|
|
201
|
+
protocolID: CONTACT_PROTOCOL_ID, keyID, counterparty: 'self'
|
|
226
202
|
}, this.originator)
|
|
203
|
+
return await new PushDrop(this.wallet, this.originator).lock([ciphertext], CONTACT_PROTOCOL_ID, keyID, 'self')
|
|
204
|
+
}
|
|
227
205
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
if (signableTransaction == null) throw new Error('Unable to update contact')
|
|
262
|
-
|
|
263
|
-
const unlocker = pushdrop.unlock(CONTACT_PROTOCOL_ID, keyID, 'self')
|
|
264
|
-
const unlockingScript = await unlocker.sign(
|
|
265
|
-
Transaction.fromBEEF(signableTransaction.tx),
|
|
266
|
-
0
|
|
267
|
-
)
|
|
268
|
-
|
|
269
|
-
const { tx } = await this.wallet.signAction({
|
|
270
|
-
reference: signableTransaction.reference,
|
|
271
|
-
spends: { 0: { unlockingScript: unlockingScript.toHex() } }
|
|
272
|
-
}, this.originator)
|
|
273
|
-
|
|
274
|
-
if (tx == null) throw new Error('Failed to update contact output')
|
|
275
|
-
} else {
|
|
276
|
-
// Create new contact output
|
|
277
|
-
const { tx } = await this.wallet.createAction({
|
|
278
|
-
description: 'Add Contact',
|
|
279
|
-
outputs: [{
|
|
280
|
-
basket: 'contacts',
|
|
281
|
-
satoshis: 1,
|
|
282
|
-
lockingScript: lockingScript.toHex(),
|
|
283
|
-
outputDescription: `Contact: ${contact.name ?? contact.identityKey.slice(0, 10)}`,
|
|
284
|
-
tags: [`identityKey ${Utils.toHex(hashedIdentityKey)}`],
|
|
285
|
-
customInstructions: JSON.stringify({ keyID })
|
|
286
|
-
}],
|
|
287
|
-
options: { acceptDelayedBroadcast: false, randomizeOutputs: false } // TODO: Support custom config as needed.
|
|
288
|
-
}, this.originator)
|
|
206
|
+
/** Spends an existing contact output and creates a replacement with updated data. */
|
|
207
|
+
private async updateContactOutput (
|
|
208
|
+
outputs: Awaited<ReturnType<WalletInterface['listOutputs']>>,
|
|
209
|
+
existingOutput: any,
|
|
210
|
+
lockingScript: LockingScript,
|
|
211
|
+
keyID: string,
|
|
212
|
+
hashedIdentityKey: number[],
|
|
213
|
+
contact: DisplayableIdentity
|
|
214
|
+
): Promise<void> {
|
|
215
|
+
const [txid, outputIndex] = String(existingOutput.outpoint).split('.')
|
|
216
|
+
const prevOutpoint = `${txid}.${outputIndex}` as const
|
|
217
|
+
const pushdrop = new PushDrop(this.wallet, this.originator)
|
|
218
|
+
const { signableTransaction } = await this.wallet.createAction({
|
|
219
|
+
description: 'Update Contact',
|
|
220
|
+
inputBEEF: outputs.BEEF as number[],
|
|
221
|
+
inputs: [{ outpoint: prevOutpoint, unlockingScriptLength: 74, inputDescription: 'Spend previous contact output' }],
|
|
222
|
+
outputs: [{
|
|
223
|
+
basket: 'contacts', satoshis: 1, lockingScript: lockingScript.toHex(),
|
|
224
|
+
outputDescription: `Updated Contact: ${contact.name ?? contact.identityKey.slice(0, 10)}`,
|
|
225
|
+
tags: [`identityKey ${Utils.toHex(hashedIdentityKey)}`], customInstructions: JSON.stringify({ keyID })
|
|
226
|
+
}],
|
|
227
|
+
options: { acceptDelayedBroadcast: false, randomizeOutputs: false }
|
|
228
|
+
}, this.originator)
|
|
229
|
+
if (signableTransaction == null) throw new Error('Unable to update contact')
|
|
230
|
+
const unlockingScript = await pushdrop.unlock(CONTACT_PROTOCOL_ID, keyID, 'self')
|
|
231
|
+
.sign(Transaction.fromBEEF(signableTransaction.tx), 0)
|
|
232
|
+
const { tx } = await this.wallet.signAction({
|
|
233
|
+
reference: signableTransaction.reference,
|
|
234
|
+
spends: { 0: { unlockingScript: unlockingScript.toHex() } }
|
|
235
|
+
}, this.originator)
|
|
236
|
+
if (tx == null) throw new Error('Failed to update contact output')
|
|
237
|
+
}
|
|
289
238
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
239
|
+
/** Creates a new on-chain contact output. */
|
|
240
|
+
private async createContactOutput (
|
|
241
|
+
lockingScript: LockingScript,
|
|
242
|
+
keyID: string,
|
|
243
|
+
hashedIdentityKey: number[],
|
|
244
|
+
contact: DisplayableIdentity
|
|
245
|
+
): Promise<void> {
|
|
246
|
+
const { tx } = await this.wallet.createAction({
|
|
247
|
+
description: 'Add Contact',
|
|
248
|
+
outputs: [{
|
|
249
|
+
basket: 'contacts', satoshis: 1, lockingScript: lockingScript.toHex(),
|
|
250
|
+
outputDescription: `Contact: ${contact.name ?? contact.identityKey.slice(0, 10)}`,
|
|
251
|
+
tags: [`identityKey ${Utils.toHex(hashedIdentityKey)}`], customInstructions: JSON.stringify({ keyID })
|
|
252
|
+
}],
|
|
253
|
+
options: { acceptDelayedBroadcast: false, randomizeOutputs: false }
|
|
254
|
+
}, this.originator)
|
|
255
|
+
if (tx == null) throw new Error('Failed to create contact output')
|
|
293
256
|
}
|
|
294
257
|
|
|
295
258
|
/**
|
|
@@ -302,87 +265,61 @@ export class ContactsManager {
|
|
|
302
265
|
if (cached != null && cached !== '') {
|
|
303
266
|
try {
|
|
304
267
|
const contacts: Contact[] = JSON.parse(cached)
|
|
305
|
-
|
|
306
|
-
this.cache.setItem(this.CONTACTS_CACHE_KEY, JSON.stringify(filteredContacts))
|
|
268
|
+
this.cache.setItem(this.CONTACTS_CACHE_KEY, JSON.stringify(contacts.filter(c => c.identityKey !== identityKey)))
|
|
307
269
|
} catch (e) {
|
|
308
270
|
console.warn('Failed to update cache after contact removal:', e)
|
|
309
271
|
}
|
|
310
272
|
}
|
|
311
273
|
|
|
312
|
-
|
|
313
|
-
const
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
counterparty: 'self',
|
|
318
|
-
data: Utils.toArray(identityKey, 'utf8')
|
|
319
|
-
}, this.originator)
|
|
320
|
-
tags.push(`identityKey ${Utils.toHex(hashedIdentityKey)}`)
|
|
321
|
-
|
|
322
|
-
// Find and spend the contact's output
|
|
323
|
-
const outputs = await this.wallet.listOutputs({
|
|
324
|
-
basket: 'contacts',
|
|
325
|
-
include: 'entire transactions',
|
|
326
|
-
includeCustomInstructions: true,
|
|
327
|
-
tags,
|
|
328
|
-
limit: 100 // Should only be one contact!
|
|
329
|
-
}, this.originator)
|
|
330
|
-
|
|
274
|
+
const tags = await this.buildIdentityKeyTags(identityKey)
|
|
275
|
+
const outputs = await this.wallet.listOutputs(
|
|
276
|
+
{ basket: 'contacts', include: 'entire transactions', includeCustomInstructions: true, tags, limit: 100 },
|
|
277
|
+
this.originator
|
|
278
|
+
)
|
|
331
279
|
if (outputs.outputs == null) return
|
|
332
280
|
|
|
333
|
-
// Find the output for this specific contact by decrypting and checking identityKey
|
|
334
281
|
for (const output of outputs.outputs) {
|
|
335
282
|
try {
|
|
336
|
-
const
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
if (output.customInstructions == null) continue
|
|
340
|
-
const keyID = JSON.parse(output.customInstructions).keyID
|
|
341
|
-
|
|
342
|
-
const { plaintext } = await this.wallet.decrypt({
|
|
343
|
-
ciphertext: decoded.fields[0],
|
|
344
|
-
protocolID: CONTACT_PROTOCOL_ID,
|
|
345
|
-
keyID,
|
|
346
|
-
counterparty: 'self'
|
|
347
|
-
}, this.originator)
|
|
348
|
-
|
|
349
|
-
const storedContact: Contact = JSON.parse(Utils.toUTF8(plaintext))
|
|
350
|
-
if (storedContact.identityKey === identityKey) {
|
|
351
|
-
// Found the contact's output, spend it without creating a new one
|
|
352
|
-
const prevOutpoint = `${txid}.${outputIndex}` as const
|
|
353
|
-
|
|
354
|
-
const pushdrop = new PushDrop(this.wallet, this.originator)
|
|
355
|
-
const { signableTransaction } = await this.wallet.createAction({
|
|
356
|
-
description: 'Delete Contact',
|
|
357
|
-
inputBEEF: outputs.BEEF as number[],
|
|
358
|
-
inputs: [{
|
|
359
|
-
outpoint: prevOutpoint,
|
|
360
|
-
unlockingScriptLength: 74,
|
|
361
|
-
inputDescription: 'Spend contact output to delete'
|
|
362
|
-
}],
|
|
363
|
-
outputs: [], // No outputs = deletion
|
|
364
|
-
options: { acceptDelayedBroadcast: false, randomizeOutputs: false } // TODO: Support custom config as needed.
|
|
365
|
-
}, this.originator)
|
|
366
|
-
|
|
367
|
-
if (signableTransaction == null) throw new Error('Unable to delete contact')
|
|
368
|
-
|
|
369
|
-
const unlocker = pushdrop.unlock(CONTACT_PROTOCOL_ID, keyID, 'self')
|
|
370
|
-
const unlockingScript = await unlocker.sign(
|
|
371
|
-
Transaction.fromBEEF(signableTransaction.tx),
|
|
372
|
-
0
|
|
373
|
-
)
|
|
374
|
-
|
|
375
|
-
const { tx: deleteTx } = await this.wallet.signAction({
|
|
376
|
-
reference: signableTransaction.reference,
|
|
377
|
-
spends: { 0: { unlockingScript: unlockingScript.toHex() } }
|
|
378
|
-
}, this.originator)
|
|
379
|
-
|
|
380
|
-
if (deleteTx == null) throw new Error('Failed to delete contact output')
|
|
381
|
-
return
|
|
382
|
-
}
|
|
383
|
-
} catch (e) {
|
|
384
|
-
// Skip malformed or undecryptable outputs
|
|
385
|
-
}
|
|
283
|
+
const spent = await this.trySpendContactOutput(output, outputs, identityKey)
|
|
284
|
+
if (spent) return
|
|
285
|
+
} catch (_malformedOrUndecryptableOutput) { /* skip */ }
|
|
386
286
|
}
|
|
387
287
|
}
|
|
288
|
+
|
|
289
|
+
/** Attempts to decrypt and spend a single output if it matches the given identity key. Returns true if spent. */
|
|
290
|
+
private async trySpendContactOutput (
|
|
291
|
+
output: Awaited<ReturnType<WalletInterface['listOutputs']>>['outputs'][number],
|
|
292
|
+
outputs: Awaited<ReturnType<WalletInterface['listOutputs']>>,
|
|
293
|
+
identityKey: string
|
|
294
|
+
): Promise<boolean> {
|
|
295
|
+
const [txid, outputIndex] = String(output.outpoint).split('.')
|
|
296
|
+
const tx = Transaction.fromBEEF(outputs.BEEF as number[], txid)
|
|
297
|
+
const decoded = PushDrop.decode(tx.outputs[Number(outputIndex)].lockingScript)
|
|
298
|
+
if (output.customInstructions == null) return false
|
|
299
|
+
const keyID = JSON.parse(output.customInstructions).keyID
|
|
300
|
+
const { plaintext } = await this.wallet.decrypt(
|
|
301
|
+
{ ciphertext: decoded.fields[0], protocolID: CONTACT_PROTOCOL_ID, keyID, counterparty: 'self' }, this.originator
|
|
302
|
+
)
|
|
303
|
+
const storedContact: Contact = JSON.parse(Utils.toUTF8(plaintext))
|
|
304
|
+
if (storedContact.identityKey !== identityKey) return false
|
|
305
|
+
|
|
306
|
+
const prevOutpoint = `${txid}.${outputIndex}` as const
|
|
307
|
+
const pushdrop = new PushDrop(this.wallet, this.originator)
|
|
308
|
+
const { signableTransaction } = await this.wallet.createAction({
|
|
309
|
+
description: 'Delete Contact',
|
|
310
|
+
inputBEEF: outputs.BEEF as number[],
|
|
311
|
+
inputs: [{ outpoint: prevOutpoint, unlockingScriptLength: 74, inputDescription: 'Spend contact output to delete' }],
|
|
312
|
+
outputs: [],
|
|
313
|
+
options: { acceptDelayedBroadcast: false, randomizeOutputs: false }
|
|
314
|
+
}, this.originator)
|
|
315
|
+
if (signableTransaction == null) throw new Error('Unable to delete contact')
|
|
316
|
+
const unlockingScript = await pushdrop.unlock(CONTACT_PROTOCOL_ID, keyID, 'self')
|
|
317
|
+
.sign(Transaction.fromBEEF(signableTransaction.tx), 0)
|
|
318
|
+
const { tx: deleteTx } = await this.wallet.signAction({
|
|
319
|
+
reference: signableTransaction.reference,
|
|
320
|
+
spends: { 0: { unlockingScript: unlockingScript.toHex() } }
|
|
321
|
+
}, this.originator)
|
|
322
|
+
if (deleteTx == null) throw new Error('Failed to delete contact output')
|
|
323
|
+
return true
|
|
324
|
+
}
|
|
388
325
|
}
|