@buildonspark/issuer-sdk 0.0.22 → 0.0.24
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/chunk-GB7N6I5O.js +48 -0
- package/dist/index.cjs +518 -0
- package/dist/index.d.cts +110 -0
- package/dist/index.d.ts +110 -0
- package/dist/index.js +497 -0
- package/dist/types.cjs +77 -0
- package/dist/types.d.cts +99 -0
- package/dist/{issuer-sdk/src/types.d.ts → types.d.ts} +14 -12
- package/dist/types.js +12 -0
- package/package.json +31 -32
- package/src/examples/example.ts +1 -1
- package/src/index.ts +1 -0
- package/src/interface/wallet-interface.ts +7 -6
- package/src/{issuer-sdk.ts → issuer-spark-wallet.ts} +5 -5
- package/src/tests/integration/spark.test.ts +3 -12
- package/src/types.ts +1 -2
- package/src/utils/constants.ts +2 -2
- package/dist/issuer-sdk/src/interface/wallet-interface.d.ts +0 -67
- package/dist/issuer-sdk/src/interface/wallet-interface.js +0 -2
- package/dist/issuer-sdk/src/interface/wallet-interface.js.map +0 -1
- package/dist/issuer-sdk/src/issuer-sdk.d.ts +0 -43
- package/dist/issuer-sdk/src/issuer-sdk.js +0 -153
- package/dist/issuer-sdk/src/issuer-sdk.js.map +0 -1
- package/dist/issuer-sdk/src/proto/common.d.ts +0 -58
- package/dist/issuer-sdk/src/proto/common.js +0 -350
- package/dist/issuer-sdk/src/proto/common.js.map +0 -1
- package/dist/issuer-sdk/src/proto/google/protobuf/descriptor.d.ts +0 -1228
- package/dist/issuer-sdk/src/proto/google/protobuf/descriptor.js +0 -5070
- package/dist/issuer-sdk/src/proto/google/protobuf/descriptor.js.map +0 -1
- package/dist/issuer-sdk/src/proto/google/protobuf/duration.d.ts +0 -99
- package/dist/issuer-sdk/src/proto/google/protobuf/duration.js +0 -90
- package/dist/issuer-sdk/src/proto/google/protobuf/duration.js.map +0 -1
- package/dist/issuer-sdk/src/proto/google/protobuf/empty.d.ts +0 -33
- package/dist/issuer-sdk/src/proto/google/protobuf/empty.js +0 -46
- package/dist/issuer-sdk/src/proto/google/protobuf/empty.js.map +0 -1
- package/dist/issuer-sdk/src/proto/google/protobuf/timestamp.d.ts +0 -128
- package/dist/issuer-sdk/src/proto/google/protobuf/timestamp.js +0 -90
- package/dist/issuer-sdk/src/proto/google/protobuf/timestamp.js.map +0 -1
- package/dist/issuer-sdk/src/proto/mock.d.ts +0 -48
- package/dist/issuer-sdk/src/proto/mock.js +0 -103
- package/dist/issuer-sdk/src/proto/mock.js.map +0 -1
- package/dist/issuer-sdk/src/proto/spark.d.ts +0 -1101
- package/dist/issuer-sdk/src/proto/spark.js +0 -9565
- package/dist/issuer-sdk/src/proto/spark.js.map +0 -1
- package/dist/issuer-sdk/src/proto/spark_authn.d.ts +0 -111
- package/dist/issuer-sdk/src/proto/spark_authn.js +0 -517
- package/dist/issuer-sdk/src/proto/spark_authn.js.map +0 -1
- package/dist/issuer-sdk/src/proto/validate/validate.d.ts +0 -1087
- package/dist/issuer-sdk/src/proto/validate/validate.js +0 -4437
- package/dist/issuer-sdk/src/proto/validate/validate.js.map +0 -1
- package/dist/issuer-sdk/src/services/freeze.d.ts +0 -11
- package/dist/issuer-sdk/src/services/freeze.js +0 -44
- package/dist/issuer-sdk/src/services/freeze.js.map +0 -1
- package/dist/issuer-sdk/src/services/token-transactions.d.ts +0 -8
- package/dist/issuer-sdk/src/services/token-transactions.js +0 -27
- package/dist/issuer-sdk/src/services/token-transactions.js.map +0 -1
- package/dist/issuer-sdk/src/tests/integration/spark.test.d.ts +0 -1
- package/dist/issuer-sdk/src/tests/integration/spark.test.js +0 -373
- package/dist/issuer-sdk/src/tests/integration/spark.test.js.map +0 -1
- package/dist/issuer-sdk/src/types.js +0 -33
- package/dist/issuer-sdk/src/types.js.map +0 -1
- package/dist/issuer-sdk/src/utils/constants.d.ts +0 -16
- package/dist/issuer-sdk/src/utils/constants.js +0 -18
- package/dist/issuer-sdk/src/utils/constants.js.map +0 -1
- package/dist/issuer-sdk/src/utils/enum-mappers.d.ts +0 -6
- package/dist/issuer-sdk/src/utils/enum-mappers.js +0 -66
- package/dist/issuer-sdk/src/utils/enum-mappers.js.map +0 -1
- package/dist/issuer-sdk/src/utils/token-hashing.d.ts +0 -2
- package/dist/issuer-sdk/src/utils/token-hashing.js +0 -45
- package/dist/issuer-sdk/src/utils/token-hashing.js.map +0 -1
- package/dist/issuer-sdk/src/utils/type-mappers.d.ts +0 -4
- package/dist/issuer-sdk/src/utils/type-mappers.js +0 -106
- package/dist/issuer-sdk/src/utils/type-mappers.js.map +0 -1
- package/dist/spark-sdk/src/graphql/client.d.ts +0 -29
- package/dist/spark-sdk/src/graphql/client.js +0 -246
- package/dist/spark-sdk/src/graphql/client.js.map +0 -1
- package/dist/spark-sdk/src/graphql/mutations/CompleteCoopExit.d.ts +0 -1
- package/dist/spark-sdk/src/graphql/mutations/CompleteCoopExit.js +0 -19
- package/dist/spark-sdk/src/graphql/mutations/CompleteCoopExit.js.map +0 -1
- package/dist/spark-sdk/src/graphql/mutations/CompleteLeavesSwap.d.ts +0 -1
- package/dist/spark-sdk/src/graphql/mutations/CompleteLeavesSwap.js +0 -17
- package/dist/spark-sdk/src/graphql/mutations/CompleteLeavesSwap.js.map +0 -1
- package/dist/spark-sdk/src/graphql/mutations/RequestCoopExit.d.ts +0 -1
- package/dist/spark-sdk/src/graphql/mutations/RequestCoopExit.js +0 -20
- package/dist/spark-sdk/src/graphql/mutations/RequestCoopExit.js.map +0 -1
- package/dist/spark-sdk/src/graphql/mutations/RequestLightningReceive.d.ts +0 -1
- package/dist/spark-sdk/src/graphql/mutations/RequestLightningReceive.js +0 -26
- package/dist/spark-sdk/src/graphql/mutations/RequestLightningReceive.js.map +0 -1
- package/dist/spark-sdk/src/graphql/mutations/RequestLightningSend.d.ts +0 -1
- package/dist/spark-sdk/src/graphql/mutations/RequestLightningSend.js +0 -18
- package/dist/spark-sdk/src/graphql/mutations/RequestLightningSend.js.map +0 -1
- package/dist/spark-sdk/src/graphql/mutations/RequestSwapLeaves.d.ts +0 -1
- package/dist/spark-sdk/src/graphql/mutations/RequestSwapLeaves.js +0 -24
- package/dist/spark-sdk/src/graphql/mutations/RequestSwapLeaves.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/BitcoinNetwork.d.ts +0 -17
- package/dist/spark-sdk/src/graphql/objects/BitcoinNetwork.js +0 -20
- package/dist/spark-sdk/src/graphql/objects/BitcoinNetwork.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/CompleteCoopExitInput.d.ts +0 -7
- package/dist/spark-sdk/src/graphql/objects/CompleteCoopExitInput.js +0 -14
- package/dist/spark-sdk/src/graphql/objects/CompleteCoopExitInput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/CompleteCoopExitOutput.d.ts +0 -7
- package/dist/spark-sdk/src/graphql/objects/CompleteCoopExitOutput.js +0 -19
- package/dist/spark-sdk/src/graphql/objects/CompleteCoopExitOutput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/CompleteLeavesSwapInput.d.ts +0 -8
- package/dist/spark-sdk/src/graphql/objects/CompleteLeavesSwapInput.js +0 -16
- package/dist/spark-sdk/src/graphql/objects/CompleteLeavesSwapInput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/CompleteLeavesSwapOutput.d.ts +0 -7
- package/dist/spark-sdk/src/graphql/objects/CompleteLeavesSwapOutput.js +0 -19
- package/dist/spark-sdk/src/graphql/objects/CompleteLeavesSwapOutput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/CompleteSeedReleaseInput.d.ts +0 -7
- package/dist/spark-sdk/src/graphql/objects/CompleteSeedReleaseInput.js +0 -14
- package/dist/spark-sdk/src/graphql/objects/CompleteSeedReleaseInput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/CompleteSeedReleaseOutput.d.ts +0 -7
- package/dist/spark-sdk/src/graphql/objects/CompleteSeedReleaseOutput.js +0 -17
- package/dist/spark-sdk/src/graphql/objects/CompleteSeedReleaseOutput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/Connection.d.ts +0 -16
- package/dist/spark-sdk/src/graphql/objects/Connection.js +0 -56
- package/dist/spark-sdk/src/graphql/objects/Connection.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/CoopExitFeeEstimateInput.d.ts +0 -7
- package/dist/spark-sdk/src/graphql/objects/CoopExitFeeEstimateInput.js +0 -14
- package/dist/spark-sdk/src/graphql/objects/CoopExitFeeEstimateInput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/CoopExitFeeEstimateOutput.d.ts +0 -8
- package/dist/spark-sdk/src/graphql/objects/CoopExitFeeEstimateOutput.js +0 -26
- package/dist/spark-sdk/src/graphql/objects/CoopExitFeeEstimateOutput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/CoopExitRequest.d.ts +0 -35
- package/dist/spark-sdk/src/graphql/objects/CoopExitRequest.js +0 -68
- package/dist/spark-sdk/src/graphql/objects/CoopExitRequest.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/CurrencyAmount.d.ts +0 -24
- package/dist/spark-sdk/src/graphql/objects/CurrencyAmount.js +0 -30
- package/dist/spark-sdk/src/graphql/objects/CurrencyAmount.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/CurrencyUnit.d.ts +0 -29
- package/dist/spark-sdk/src/graphql/objects/CurrencyUnit.js +0 -32
- package/dist/spark-sdk/src/graphql/objects/CurrencyUnit.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/Entity.d.ts +0 -16
- package/dist/spark-sdk/src/graphql/objects/Entity.js +0 -169
- package/dist/spark-sdk/src/graphql/objects/Entity.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/GetChallengeInput.d.ts +0 -6
- package/dist/spark-sdk/src/graphql/objects/GetChallengeInput.js +0 -12
- package/dist/spark-sdk/src/graphql/objects/GetChallengeInput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/GetChallengeOutput.d.ts +0 -7
- package/dist/spark-sdk/src/graphql/objects/GetChallengeOutput.js +0 -17
- package/dist/spark-sdk/src/graphql/objects/GetChallengeOutput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/Invoice.d.ts +0 -15
- package/dist/spark-sdk/src/graphql/objects/Invoice.js +0 -45
- package/dist/spark-sdk/src/graphql/objects/Invoice.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/Leaf.d.ts +0 -11
- package/dist/spark-sdk/src/graphql/objects/Leaf.js +0 -29
- package/dist/spark-sdk/src/graphql/objects/Leaf.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/LeavesSwapFeeEstimateInput.d.ts +0 -6
- package/dist/spark-sdk/src/graphql/objects/LeavesSwapFeeEstimateInput.js +0 -12
- package/dist/spark-sdk/src/graphql/objects/LeavesSwapFeeEstimateInput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/LeavesSwapFeeEstimateOutput.d.ts +0 -8
- package/dist/spark-sdk/src/graphql/objects/LeavesSwapFeeEstimateOutput.js +0 -26
- package/dist/spark-sdk/src/graphql/objects/LeavesSwapFeeEstimateOutput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/LeavesSwapRequest.d.ts +0 -42
- package/dist/spark-sdk/src/graphql/objects/LeavesSwapRequest.js +0 -123
- package/dist/spark-sdk/src/graphql/objects/LeavesSwapRequest.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/LightningReceiveFeeEstimateInput.d.ts +0 -8
- package/dist/spark-sdk/src/graphql/objects/LightningReceiveFeeEstimateInput.js +0 -15
- package/dist/spark-sdk/src/graphql/objects/LightningReceiveFeeEstimateInput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/LightningReceiveFeeEstimateOutput.d.ts +0 -8
- package/dist/spark-sdk/src/graphql/objects/LightningReceiveFeeEstimateOutput.js +0 -26
- package/dist/spark-sdk/src/graphql/objects/LightningReceiveFeeEstimateOutput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/LightningReceiveRequest.d.ts +0 -34
- package/dist/spark-sdk/src/graphql/objects/LightningReceiveRequest.js +0 -97
- package/dist/spark-sdk/src/graphql/objects/LightningReceiveRequest.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/LightningReceiveRequestStatus.d.ts +0 -18
- package/dist/spark-sdk/src/graphql/objects/LightningReceiveRequestStatus.js +0 -21
- package/dist/spark-sdk/src/graphql/objects/LightningReceiveRequestStatus.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/LightningSendFeeEstimateInput.d.ts +0 -6
- package/dist/spark-sdk/src/graphql/objects/LightningSendFeeEstimateInput.js +0 -12
- package/dist/spark-sdk/src/graphql/objects/LightningSendFeeEstimateInput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/LightningSendFeeEstimateOutput.d.ts +0 -8
- package/dist/spark-sdk/src/graphql/objects/LightningSendFeeEstimateOutput.js +0 -26
- package/dist/spark-sdk/src/graphql/objects/LightningSendFeeEstimateOutput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/LightningSendRequest.d.ts +0 -35
- package/dist/spark-sdk/src/graphql/objects/LightningSendRequest.js +0 -82
- package/dist/spark-sdk/src/graphql/objects/LightningSendRequest.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/LightningSendRequestStatus.d.ts +0 -15
- package/dist/spark-sdk/src/graphql/objects/LightningSendRequestStatus.js +0 -18
- package/dist/spark-sdk/src/graphql/objects/LightningSendRequestStatus.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/NotifyReceiverTransferInput.d.ts +0 -7
- package/dist/spark-sdk/src/graphql/objects/NotifyReceiverTransferInput.js +0 -14
- package/dist/spark-sdk/src/graphql/objects/NotifyReceiverTransferInput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/PageInfo.d.ts +0 -11
- package/dist/spark-sdk/src/graphql/objects/PageInfo.js +0 -26
- package/dist/spark-sdk/src/graphql/objects/PageInfo.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/Provider.d.ts +0 -7
- package/dist/spark-sdk/src/graphql/objects/Provider.js +0 -14
- package/dist/spark-sdk/src/graphql/objects/Provider.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/RequestCoopExitInput.d.ts +0 -7
- package/dist/spark-sdk/src/graphql/objects/RequestCoopExitInput.js +0 -14
- package/dist/spark-sdk/src/graphql/objects/RequestCoopExitInput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/RequestCoopExitOutput.d.ts +0 -7
- package/dist/spark-sdk/src/graphql/objects/RequestCoopExitOutput.js +0 -19
- package/dist/spark-sdk/src/graphql/objects/RequestCoopExitOutput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/RequestLeavesSwapInput.d.ts +0 -11
- package/dist/spark-sdk/src/graphql/objects/RequestLeavesSwapInput.js +0 -22
- package/dist/spark-sdk/src/graphql/objects/RequestLeavesSwapInput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/RequestLeavesSwapOutput.d.ts +0 -7
- package/dist/spark-sdk/src/graphql/objects/RequestLeavesSwapOutput.js +0 -19
- package/dist/spark-sdk/src/graphql/objects/RequestLeavesSwapOutput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/RequestLightningReceiveInput.d.ts +0 -16
- package/dist/spark-sdk/src/graphql/objects/RequestLightningReceiveInput.js +0 -21
- package/dist/spark-sdk/src/graphql/objects/RequestLightningReceiveInput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/RequestLightningReceiveOutput.d.ts +0 -7
- package/dist/spark-sdk/src/graphql/objects/RequestLightningReceiveOutput.js +0 -19
- package/dist/spark-sdk/src/graphql/objects/RequestLightningReceiveOutput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/RequestLightningSendInput.d.ts +0 -7
- package/dist/spark-sdk/src/graphql/objects/RequestLightningSendInput.js +0 -14
- package/dist/spark-sdk/src/graphql/objects/RequestLightningSendInput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/RequestLightningSendOutput.d.ts +0 -7
- package/dist/spark-sdk/src/graphql/objects/RequestLightningSendOutput.js +0 -19
- package/dist/spark-sdk/src/graphql/objects/RequestLightningSendOutput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/SparkCoopExitRequestStatus.d.ts +0 -14
- package/dist/spark-sdk/src/graphql/objects/SparkCoopExitRequestStatus.js +0 -17
- package/dist/spark-sdk/src/graphql/objects/SparkCoopExitRequestStatus.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/SparkLeavesSwapRequestStatus.d.ts +0 -14
- package/dist/spark-sdk/src/graphql/objects/SparkLeavesSwapRequestStatus.js +0 -17
- package/dist/spark-sdk/src/graphql/objects/SparkLeavesSwapRequestStatus.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/SparkTransferToLeavesConnection.d.ts +0 -19
- package/dist/spark-sdk/src/graphql/objects/SparkTransferToLeavesConnection.js +0 -45
- package/dist/spark-sdk/src/graphql/objects/SparkTransferToLeavesConnection.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/SparkWalletUser.d.ts +0 -21
- package/dist/spark-sdk/src/graphql/objects/SparkWalletUser.js +0 -45
- package/dist/spark-sdk/src/graphql/objects/SparkWalletUser.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/StartSeedReleaseInput.d.ts +0 -6
- package/dist/spark-sdk/src/graphql/objects/StartSeedReleaseInput.js +0 -12
- package/dist/spark-sdk/src/graphql/objects/StartSeedReleaseInput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/SwapLeaf.d.ts +0 -9
- package/dist/spark-sdk/src/graphql/objects/SwapLeaf.js +0 -23
- package/dist/spark-sdk/src/graphql/objects/SwapLeaf.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/Transfer.d.ts +0 -24
- package/dist/spark-sdk/src/graphql/objects/Transfer.js +0 -82
- package/dist/spark-sdk/src/graphql/objects/Transfer.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/UserLeafInput.d.ts +0 -8
- package/dist/spark-sdk/src/graphql/objects/UserLeafInput.js +0 -16
- package/dist/spark-sdk/src/graphql/objects/UserLeafInput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/UserRequest.d.ts +0 -22
- package/dist/spark-sdk/src/graphql/objects/UserRequest.js +0 -310
- package/dist/spark-sdk/src/graphql/objects/UserRequest.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/VerifyChallengeInput.d.ts +0 -10
- package/dist/spark-sdk/src/graphql/objects/VerifyChallengeInput.js +0 -20
- package/dist/spark-sdk/src/graphql/objects/VerifyChallengeInput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/VerifyChallengeOutput.d.ts +0 -7
- package/dist/spark-sdk/src/graphql/objects/VerifyChallengeOutput.js +0 -17
- package/dist/spark-sdk/src/graphql/objects/VerifyChallengeOutput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/WalletUserIdentityPublicKeyInput.d.ts +0 -6
- package/dist/spark-sdk/src/graphql/objects/WalletUserIdentityPublicKeyInput.js +0 -12
- package/dist/spark-sdk/src/graphql/objects/WalletUserIdentityPublicKeyInput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/WalletUserIdentityPublicKeyOutput.d.ts +0 -7
- package/dist/spark-sdk/src/graphql/objects/WalletUserIdentityPublicKeyOutput.js +0 -17
- package/dist/spark-sdk/src/graphql/objects/WalletUserIdentityPublicKeyOutput.js.map +0 -1
- package/dist/spark-sdk/src/graphql/objects/index.d.ts +0 -53
- package/dist/spark-sdk/src/graphql/objects/index.js +0 -14
- package/dist/spark-sdk/src/graphql/objects/index.js.map +0 -1
- package/dist/spark-sdk/src/graphql/queries/CoopExitFeeEstimate.d.ts +0 -1
- package/dist/spark-sdk/src/graphql/queries/CoopExitFeeEstimate.js +0 -18
- package/dist/spark-sdk/src/graphql/queries/CoopExitFeeEstimate.js.map +0 -1
- package/dist/spark-sdk/src/graphql/queries/LeavesSwapFeeEstimate.d.ts +0 -1
- package/dist/spark-sdk/src/graphql/queries/LeavesSwapFeeEstimate.js +0 -16
- package/dist/spark-sdk/src/graphql/queries/LeavesSwapFeeEstimate.js.map +0 -1
- package/dist/spark-sdk/src/graphql/queries/LightningReceiveFeeEstimate.d.ts +0 -1
- package/dist/spark-sdk/src/graphql/queries/LightningReceiveFeeEstimate.js +0 -18
- package/dist/spark-sdk/src/graphql/queries/LightningReceiveFeeEstimate.js.map +0 -1
- package/dist/spark-sdk/src/graphql/queries/LightningSendFeeEstimate.d.ts +0 -1
- package/dist/spark-sdk/src/graphql/queries/LightningSendFeeEstimate.js +0 -16
- package/dist/spark-sdk/src/graphql/queries/LightningSendFeeEstimate.js.map +0 -1
- package/dist/spark-sdk/src/graphql/queries/UserRequest.d.ts +0 -1
- package/dist/spark-sdk/src/graphql/queries/UserRequest.js +0 -10
- package/dist/spark-sdk/src/graphql/queries/UserRequest.js.map +0 -1
- package/dist/spark-sdk/src/proto/common.d.ts +0 -58
- package/dist/spark-sdk/src/proto/common.js +0 -350
- package/dist/spark-sdk/src/proto/common.js.map +0 -1
- package/dist/spark-sdk/src/proto/google/protobuf/empty.d.ts +0 -33
- package/dist/spark-sdk/src/proto/google/protobuf/empty.js +0 -46
- package/dist/spark-sdk/src/proto/google/protobuf/empty.js.map +0 -1
- package/dist/spark-sdk/src/proto/google/protobuf/timestamp.d.ts +0 -128
- package/dist/spark-sdk/src/proto/google/protobuf/timestamp.js +0 -90
- package/dist/spark-sdk/src/proto/google/protobuf/timestamp.js.map +0 -1
- package/dist/spark-sdk/src/proto/mock.d.ts +0 -48
- package/dist/spark-sdk/src/proto/mock.js +0 -103
- package/dist/spark-sdk/src/proto/mock.js.map +0 -1
- package/dist/spark-sdk/src/proto/spark.d.ts +0 -1209
- package/dist/spark-sdk/src/proto/spark.js +0 -10516
- package/dist/spark-sdk/src/proto/spark.js.map +0 -1
- package/dist/spark-sdk/src/proto/spark_authn.d.ts +0 -111
- package/dist/spark-sdk/src/proto/spark_authn.js +0 -517
- package/dist/spark-sdk/src/proto/spark_authn.js.map +0 -1
- package/dist/spark-sdk/src/services/config.d.ts +0 -17
- package/dist/spark-sdk/src/services/config.js +0 -54
- package/dist/spark-sdk/src/services/config.js.map +0 -1
- package/dist/spark-sdk/src/services/connection.d.ts +0 -22
- package/dist/spark-sdk/src/services/connection.js +0 -180
- package/dist/spark-sdk/src/services/connection.js.map +0 -1
- package/dist/spark-sdk/src/services/coop-exit.d.ts +0 -20
- package/dist/spark-sdk/src/services/coop-exit.js +0 -101
- package/dist/spark-sdk/src/services/coop-exit.js.map +0 -1
- package/dist/spark-sdk/src/services/deposit.d.ts +0 -21
- package/dist/spark-sdk/src/services/deposit.js +0 -214
- package/dist/spark-sdk/src/services/deposit.js.map +0 -1
- package/dist/spark-sdk/src/services/lightning.d.ts +0 -32
- package/dist/spark-sdk/src/services/lightning.js +0 -210
- package/dist/spark-sdk/src/services/lightning.js.map +0 -1
- package/dist/spark-sdk/src/services/lrc20.d.ts +0 -5
- package/dist/spark-sdk/src/services/lrc20.js +0 -27
- package/dist/spark-sdk/src/services/lrc20.js.map +0 -1
- package/dist/spark-sdk/src/services/token-transactions.d.ts +0 -16
- package/dist/spark-sdk/src/services/token-transactions.js +0 -299
- package/dist/spark-sdk/src/services/token-transactions.js.map +0 -1
- package/dist/spark-sdk/src/services/transfer.d.ts +0 -66
- package/dist/spark-sdk/src/services/transfer.js +0 -791
- package/dist/spark-sdk/src/services/transfer.js.map +0 -1
- package/dist/spark-sdk/src/services/tree-creation.d.ts +0 -29
- package/dist/spark-sdk/src/services/tree-creation.js +0 -399
- package/dist/spark-sdk/src/services/tree-creation.js.map +0 -1
- package/dist/spark-sdk/src/services/wallet-config.d.ts +0 -23
- package/dist/spark-sdk/src/services/wallet-config.js +0 -107
- package/dist/spark-sdk/src/services/wallet-config.js.map +0 -1
- package/dist/spark-sdk/src/signer/signer.d.ts +0 -106
- package/dist/spark-sdk/src/signer/signer.js +0 -275
- package/dist/spark-sdk/src/signer/signer.js.map +0 -1
- package/dist/spark-sdk/src/spark-sdk.d.ts +0 -414
- package/dist/spark-sdk/src/spark-sdk.js +0 -1285
- package/dist/spark-sdk/src/spark-sdk.js.map +0 -1
- package/dist/spark-sdk/src/tests/utils/test-faucet.d.ts +0 -24
- package/dist/spark-sdk/src/tests/utils/test-faucet.js +0 -182
- package/dist/spark-sdk/src/tests/utils/test-faucet.js.map +0 -1
- package/dist/spark-sdk/src/types/grpc.d.ts +0 -6
- package/dist/spark-sdk/src/types/grpc.js +0 -2
- package/dist/spark-sdk/src/types/grpc.js.map +0 -1
- package/dist/spark-sdk/src/types/index.d.ts +0 -3
- package/dist/spark-sdk/src/types/index.js +0 -4
- package/dist/spark-sdk/src/types/index.js.map +0 -1
- package/dist/spark-sdk/src/utils/adaptor-signature.d.ts +0 -7
- package/dist/spark-sdk/src/utils/adaptor-signature.js +0 -114
- package/dist/spark-sdk/src/utils/adaptor-signature.js.map +0 -1
- package/dist/spark-sdk/src/utils/bitcoin.d.ts +0 -12
- package/dist/spark-sdk/src/utils/bitcoin.js +0 -87
- package/dist/spark-sdk/src/utils/bitcoin.js.map +0 -1
- package/dist/spark-sdk/src/utils/crypto.d.ts +0 -1
- package/dist/spark-sdk/src/utils/crypto.js +0 -14
- package/dist/spark-sdk/src/utils/crypto.js.map +0 -1
- package/dist/spark-sdk/src/utils/index.d.ts +0 -12
- package/dist/spark-sdk/src/utils/index.js +0 -13
- package/dist/spark-sdk/src/utils/index.js.map +0 -1
- package/dist/spark-sdk/src/utils/keys.d.ts +0 -9
- package/dist/spark-sdk/src/utils/keys.js +0 -73
- package/dist/spark-sdk/src/utils/keys.js.map +0 -1
- package/dist/spark-sdk/src/utils/mempool.d.ts +0 -1
- package/dist/spark-sdk/src/utils/mempool.js +0 -29
- package/dist/spark-sdk/src/utils/mempool.js.map +0 -1
- package/dist/spark-sdk/src/utils/network.d.ts +0 -36
- package/dist/spark-sdk/src/utils/network.js +0 -65
- package/dist/spark-sdk/src/utils/network.js.map +0 -1
- package/dist/spark-sdk/src/utils/proof.d.ts +0 -1
- package/dist/spark-sdk/src/utils/proof.js +0 -12
- package/dist/spark-sdk/src/utils/proof.js.map +0 -1
- package/dist/spark-sdk/src/utils/response-validation.d.ts +0 -1
- package/dist/spark-sdk/src/utils/response-validation.js +0 -16
- package/dist/spark-sdk/src/utils/response-validation.js.map +0 -1
- package/dist/spark-sdk/src/utils/secret-sharing.d.ts +0 -26
- package/dist/spark-sdk/src/utils/secret-sharing.js +0 -174
- package/dist/spark-sdk/src/utils/secret-sharing.js.map +0 -1
- package/dist/spark-sdk/src/utils/signing.d.ts +0 -12
- package/dist/spark-sdk/src/utils/signing.js +0 -67
- package/dist/spark-sdk/src/utils/signing.js.map +0 -1
- package/dist/spark-sdk/src/utils/token-hashing.d.ts +0 -3
- package/dist/spark-sdk/src/utils/token-hashing.js +0 -116
- package/dist/spark-sdk/src/utils/token-hashing.js.map +0 -1
- package/dist/spark-sdk/src/utils/token-keyshares.d.ts +0 -5
- package/dist/spark-sdk/src/utils/token-keyshares.js +0 -17
- package/dist/spark-sdk/src/utils/token-keyshares.js.map +0 -1
- package/dist/spark-sdk/src/utils/token-transactions.d.ts +0 -5
- package/dist/spark-sdk/src/utils/token-transactions.js +0 -40
- package/dist/spark-sdk/src/utils/token-transactions.js.map +0 -1
- package/dist/spark-sdk/src/utils/transaction.d.ts +0 -9
- package/dist/spark-sdk/src/utils/transaction.js +0 -35
- package/dist/spark-sdk/src/utils/transaction.js.map +0 -1
- package/dist/spark-sdk/src/utils/wasm-wrapper.d.ts +0 -2
- package/dist/spark-sdk/src/utils/wasm-wrapper.js +0 -46
- package/dist/spark-sdk/src/utils/wasm-wrapper.js.map +0 -1
- package/dist/spark-sdk/src/utils/wasm.d.ts +0 -54
- package/dist/spark-sdk/src/utils/wasm.js +0 -26
- package/dist/spark-sdk/src/utils/wasm.js.map +0 -1
|
@@ -1,1285 +0,0 @@
|
|
|
1
|
-
import { bytesToHex, bytesToNumberBE, hexToBytes, } from "@noble/curves/abstract/utils";
|
|
2
|
-
import { secp256k1 } from "@noble/curves/secp256k1";
|
|
3
|
-
import { Address, OutScript } from "@scure/btc-signer";
|
|
4
|
-
import { sha256 } from "@scure/btc-signer/utils";
|
|
5
|
-
import { decode } from "light-bolt11-decoder";
|
|
6
|
-
import SspClient from "./graphql/client.js";
|
|
7
|
-
import { BitcoinNetwork, } from "./graphql/objects/index.js";
|
|
8
|
-
import { TransferStatus, } from "./proto/spark.js";
|
|
9
|
-
import { WalletConfigService } from "./services/config.js";
|
|
10
|
-
import { ConnectionManager } from "./services/connection.js";
|
|
11
|
-
import { CoopExitService } from "./services/coop-exit.js";
|
|
12
|
-
import { DepositService } from "./services/deposit.js";
|
|
13
|
-
import { LightningService } from "./services/lightning.js";
|
|
14
|
-
import { TokenTransactionService } from "./services/token-transactions.js";
|
|
15
|
-
import { TransferService } from "./services/transfer.js";
|
|
16
|
-
import { createLrc20ConnectionManager, } from "@buildonspark/lrc20-sdk/grpc";
|
|
17
|
-
import { validateMnemonic } from "@scure/bip39";
|
|
18
|
-
import { wordlist } from "@scure/bip39/wordlists/english";
|
|
19
|
-
import { Mutex } from "async-mutex";
|
|
20
|
-
import { TreeCreationService, } from "./services/tree-creation.js";
|
|
21
|
-
import { applyAdaptorToSignature, generateAdaptorFromSignature, generateSignatureFromExistingAdaptor, } from "./utils/adaptor-signature.js";
|
|
22
|
-
import { computeTaprootKeyNoScript, getSigHashFromTx, getTxFromRawTxBytes, getTxFromRawTxHex, getTxId, } from "./utils/bitcoin.js";
|
|
23
|
-
import { getNetwork, LRC_WALLET_NETWORK, LRC_WALLET_NETWORK_TYPE, Network, } from "./utils/network.js";
|
|
24
|
-
import { calculateAvailableTokenAmount, checkIfSelectedLeavesAreAvailable, } from "./utils/token-transactions.js";
|
|
25
|
-
import { getNextTransactionSequence } from "./utils/transaction.js";
|
|
26
|
-
import { initWasm } from "./utils/wasm-wrapper.js";
|
|
27
|
-
import { LRCWallet } from "@buildonspark/lrc20-sdk";
|
|
28
|
-
import { broadcastL1Withdrawal } from "./services/lrc20.js";
|
|
29
|
-
import { getMasterHDKeyFromSeed } from "./utils/index.js";
|
|
30
|
-
// Add this constant at the file level
|
|
31
|
-
const MAX_TOKEN_LEAVES = 100;
|
|
32
|
-
/**
|
|
33
|
-
* The SparkWallet class is the primary interface for interacting with the Spark network.
|
|
34
|
-
* It provides methods for creating and managing wallets, handling deposits, executing transfers,
|
|
35
|
-
* and interacting with the Lightning Network.
|
|
36
|
-
*/
|
|
37
|
-
export class SparkWallet {
|
|
38
|
-
config;
|
|
39
|
-
connectionManager;
|
|
40
|
-
lrc20ConnectionManager;
|
|
41
|
-
lrc20Wallet;
|
|
42
|
-
depositService;
|
|
43
|
-
transferService;
|
|
44
|
-
treeCreationService;
|
|
45
|
-
lightningService;
|
|
46
|
-
coopExitService;
|
|
47
|
-
tokenTransactionService;
|
|
48
|
-
claimTransferMutex = new Mutex();
|
|
49
|
-
leavesMutex = new Mutex();
|
|
50
|
-
optimizationInProgress = false;
|
|
51
|
-
sspClient = null;
|
|
52
|
-
wasmModule = null;
|
|
53
|
-
mutexes = new Map();
|
|
54
|
-
pendingWithdrawnLeafIds = [];
|
|
55
|
-
leaves = [];
|
|
56
|
-
tokenLeaves = new Map();
|
|
57
|
-
constructor(options, signer) {
|
|
58
|
-
this.config = new WalletConfigService(options, signer);
|
|
59
|
-
this.connectionManager = new ConnectionManager(this.config);
|
|
60
|
-
this.lrc20ConnectionManager = createLrc20ConnectionManager(this.config.getLrc20Address());
|
|
61
|
-
this.depositService = new DepositService(this.config, this.connectionManager);
|
|
62
|
-
this.transferService = new TransferService(this.config, this.connectionManager);
|
|
63
|
-
this.treeCreationService = new TreeCreationService(this.config, this.connectionManager);
|
|
64
|
-
this.tokenTransactionService = new TokenTransactionService(this.config, this.connectionManager);
|
|
65
|
-
this.lightningService = new LightningService(this.config, this.connectionManager);
|
|
66
|
-
this.coopExitService = new CoopExitService(this.config, this.connectionManager);
|
|
67
|
-
}
|
|
68
|
-
static async initialize({ mnemonicOrSeed, signer, options, }) {
|
|
69
|
-
const wallet = new SparkWallet(options, signer);
|
|
70
|
-
const initResponse = await wallet.initWallet(mnemonicOrSeed);
|
|
71
|
-
return {
|
|
72
|
-
wallet,
|
|
73
|
-
...initResponse,
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
async initWasm() {
|
|
77
|
-
try {
|
|
78
|
-
this.wasmModule = await initWasm();
|
|
79
|
-
}
|
|
80
|
-
catch (e) {
|
|
81
|
-
console.error("Failed to initialize Wasm module", e);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
async initializeWallet(identityPublicKey) {
|
|
85
|
-
this.sspClient = new SspClient(identityPublicKey);
|
|
86
|
-
await this.connectionManager.createClients();
|
|
87
|
-
await this.initWasm();
|
|
88
|
-
await this.syncWallet();
|
|
89
|
-
}
|
|
90
|
-
async getLeaves() {
|
|
91
|
-
const sparkClient = await this.connectionManager.createSparkClient(this.config.getCoordinatorAddress());
|
|
92
|
-
const leaves = await sparkClient.query_nodes({
|
|
93
|
-
source: {
|
|
94
|
-
$case: "ownerIdentityPubkey",
|
|
95
|
-
ownerIdentityPubkey: await this.config.signer.getIdentityPublicKey(),
|
|
96
|
-
},
|
|
97
|
-
includeParents: false,
|
|
98
|
-
network: this.config.getNetworkProto(),
|
|
99
|
-
});
|
|
100
|
-
return Object.entries(leaves.nodes)
|
|
101
|
-
.filter(([_, node]) => node.status === "AVAILABLE")
|
|
102
|
-
.map(([_, node]) => node);
|
|
103
|
-
}
|
|
104
|
-
async selectLeaves(targetAmount) {
|
|
105
|
-
if (targetAmount <= 0) {
|
|
106
|
-
throw new Error("Target amount must be positive");
|
|
107
|
-
}
|
|
108
|
-
const leaves = await this.getLeaves();
|
|
109
|
-
if (leaves.length === 0) {
|
|
110
|
-
throw new Error("No owned leaves found");
|
|
111
|
-
}
|
|
112
|
-
leaves.sort((a, b) => b.value - a.value);
|
|
113
|
-
let amount = 0;
|
|
114
|
-
let nodes = [];
|
|
115
|
-
for (const leaf of leaves) {
|
|
116
|
-
if (targetAmount - amount >= leaf.value) {
|
|
117
|
-
amount += leaf.value;
|
|
118
|
-
nodes.push(leaf);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
if (amount !== targetAmount) {
|
|
122
|
-
await this.requestLeavesSwap({ targetAmount });
|
|
123
|
-
amount = 0;
|
|
124
|
-
nodes = [];
|
|
125
|
-
const newLeaves = await this.getLeaves();
|
|
126
|
-
newLeaves.sort((a, b) => b.value - a.value);
|
|
127
|
-
for (const leaf of newLeaves) {
|
|
128
|
-
if (targetAmount - amount >= leaf.value) {
|
|
129
|
-
amount += leaf.value;
|
|
130
|
-
nodes.push(leaf);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
return nodes;
|
|
135
|
-
}
|
|
136
|
-
async selectLeavesForSwap(targetAmount) {
|
|
137
|
-
if (targetAmount == 0) {
|
|
138
|
-
throw new Error("Target amount needs to > 0");
|
|
139
|
-
}
|
|
140
|
-
const leaves = await this.getLeaves();
|
|
141
|
-
leaves.sort((a, b) => a.value - b.value);
|
|
142
|
-
let amount = 0;
|
|
143
|
-
const nodes = [];
|
|
144
|
-
for (const leaf of leaves) {
|
|
145
|
-
if (amount < targetAmount) {
|
|
146
|
-
amount += leaf.value;
|
|
147
|
-
nodes.push(leaf);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
if (amount < targetAmount) {
|
|
151
|
-
throw new Error("Not enough leaves to swap for the target amount");
|
|
152
|
-
}
|
|
153
|
-
return nodes;
|
|
154
|
-
}
|
|
155
|
-
areLeavesInefficient() {
|
|
156
|
-
const totalAmount = this.leaves.reduce((acc, leaf) => acc + leaf.value, 0);
|
|
157
|
-
if (this.leaves.length <= 1) {
|
|
158
|
-
return false;
|
|
159
|
-
}
|
|
160
|
-
const nextLowerPowerOfTwo = 31 - Math.clz32(totalAmount);
|
|
161
|
-
let remainingAmount = totalAmount;
|
|
162
|
-
let optimalLeavesLength = 0;
|
|
163
|
-
for (let i = nextLowerPowerOfTwo; i >= 0; i--) {
|
|
164
|
-
const denomination = 2 ** i;
|
|
165
|
-
while (remainingAmount >= denomination) {
|
|
166
|
-
remainingAmount -= denomination;
|
|
167
|
-
optimalLeavesLength++;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
return this.leaves.length > optimalLeavesLength * 5;
|
|
171
|
-
}
|
|
172
|
-
async optimizeLeaves() {
|
|
173
|
-
if (this.optimizationInProgress || !this.areLeavesInefficient()) {
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
await this.withLeaves(async () => {
|
|
177
|
-
this.optimizationInProgress = true;
|
|
178
|
-
try {
|
|
179
|
-
if (this.leaves.length > 0) {
|
|
180
|
-
await this.requestLeavesSwap({ leaves: this.leaves });
|
|
181
|
-
}
|
|
182
|
-
this.leaves = await this.getLeaves();
|
|
183
|
-
}
|
|
184
|
-
finally {
|
|
185
|
-
this.optimizationInProgress = false;
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
async syncWallet() {
|
|
190
|
-
await this.syncTokenLeaves();
|
|
191
|
-
this.leaves = await this.getLeaves();
|
|
192
|
-
await this.config.signer.restoreSigningKeysFromLeafs(this.leaves);
|
|
193
|
-
await this.refreshTimelockNodes();
|
|
194
|
-
await this.extendTimeLockNodes();
|
|
195
|
-
this.optimizeLeaves().catch((e) => {
|
|
196
|
-
console.error("Failed to optimize leaves", e);
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
async withLeaves(operation) {
|
|
200
|
-
const release = await this.leavesMutex.acquire();
|
|
201
|
-
try {
|
|
202
|
-
return await operation();
|
|
203
|
-
}
|
|
204
|
-
finally {
|
|
205
|
-
release();
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
/**
|
|
209
|
-
* Gets the identity public key of the wallet.
|
|
210
|
-
*
|
|
211
|
-
* @returns {Promise<string>} The identity public key as a hex string.
|
|
212
|
-
*/
|
|
213
|
-
async getIdentityPublicKey() {
|
|
214
|
-
return bytesToHex(await this.config.signer.getIdentityPublicKey());
|
|
215
|
-
}
|
|
216
|
-
/**
|
|
217
|
-
* Gets the Spark address of the wallet.
|
|
218
|
-
*
|
|
219
|
-
* @returns {Promise<string>} The Spark address as a hex string.
|
|
220
|
-
*/
|
|
221
|
-
async getSparkAddress() {
|
|
222
|
-
return bytesToHex(await this.config.signer.getIdentityPublicKey());
|
|
223
|
-
}
|
|
224
|
-
/**
|
|
225
|
-
* Initializes the wallet using either a mnemonic phrase or a raw seed.
|
|
226
|
-
* initWallet will also claim any pending incoming lightning payment, spark transfer,
|
|
227
|
-
* or bitcoin deposit.
|
|
228
|
-
*
|
|
229
|
-
* @param {Uint8Array | string} [mnemonicOrSeed] - (Optional) Either:
|
|
230
|
-
* - A BIP-39 mnemonic phrase as string
|
|
231
|
-
* - A raw seed as Uint8Array or hex string
|
|
232
|
-
* If not provided, generates a new mnemonic and uses it to create a new wallet
|
|
233
|
-
*
|
|
234
|
-
* @returns {Promise<Object>} Object containing:
|
|
235
|
-
* - mnemonic: The mnemonic if one was generated (undefined for raw seed)
|
|
236
|
-
* - balance: The wallet's initial balance in satoshis
|
|
237
|
-
* - tokenBalance: Map of token balances and leaf counts
|
|
238
|
-
* @private
|
|
239
|
-
*/
|
|
240
|
-
async initWallet(mnemonicOrSeed) {
|
|
241
|
-
const returnMnemonic = !mnemonicOrSeed;
|
|
242
|
-
let mnemonic;
|
|
243
|
-
if (!mnemonicOrSeed) {
|
|
244
|
-
mnemonic = await this.config.signer.generateMnemonic();
|
|
245
|
-
mnemonicOrSeed = mnemonic;
|
|
246
|
-
}
|
|
247
|
-
let seed;
|
|
248
|
-
if (typeof mnemonicOrSeed !== "string") {
|
|
249
|
-
seed = mnemonicOrSeed;
|
|
250
|
-
}
|
|
251
|
-
else {
|
|
252
|
-
if (validateMnemonic(mnemonicOrSeed, wordlist)) {
|
|
253
|
-
seed = await this.config.signer.mnemonicToSeed(mnemonicOrSeed);
|
|
254
|
-
}
|
|
255
|
-
else {
|
|
256
|
-
seed = hexToBytes(mnemonicOrSeed);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
await this.initWalletFromSeed(seed);
|
|
260
|
-
const network = this.config.getNetwork();
|
|
261
|
-
// TODO: remove this once we move it back to the signer
|
|
262
|
-
const masterPrivateKey = getMasterHDKeyFromSeed(seed).privateKey;
|
|
263
|
-
this.lrc20Wallet = new LRCWallet(bytesToHex(masterPrivateKey), LRC_WALLET_NETWORK[network], LRC_WALLET_NETWORK_TYPE[network]);
|
|
264
|
-
if (returnMnemonic) {
|
|
265
|
-
return {
|
|
266
|
-
mnemonic,
|
|
267
|
-
};
|
|
268
|
-
}
|
|
269
|
-
return;
|
|
270
|
-
}
|
|
271
|
-
/**
|
|
272
|
-
* Initializes a wallet from a seed.
|
|
273
|
-
*
|
|
274
|
-
* @param {Uint8Array | string} seed - The seed to initialize the wallet from
|
|
275
|
-
* @returns {Promise<string>} The identity public key
|
|
276
|
-
* @private
|
|
277
|
-
*/
|
|
278
|
-
async initWalletFromSeed(seed) {
|
|
279
|
-
const identityPublicKey = await this.config.signer.createSparkWalletFromSeed(seed, this.config.getNetwork());
|
|
280
|
-
await this.initializeWallet(identityPublicKey);
|
|
281
|
-
return identityPublicKey;
|
|
282
|
-
}
|
|
283
|
-
/**
|
|
284
|
-
* Gets the estimated fee for a swap of leaves.
|
|
285
|
-
*
|
|
286
|
-
* @param amountSats - The amount of sats to swap
|
|
287
|
-
* @returns {Promise<LeavesSwapFeeEstimateOutput>} The estimated fee for the swap
|
|
288
|
-
*/
|
|
289
|
-
async getSwapFeeEstimate(amountSats) {
|
|
290
|
-
if (!this.sspClient) {
|
|
291
|
-
throw new Error("SSP client not initialized");
|
|
292
|
-
}
|
|
293
|
-
const feeEstimate = await this.sspClient.getSwapFeeEstimate(amountSats);
|
|
294
|
-
if (!feeEstimate) {
|
|
295
|
-
throw new Error("Failed to get swap fee estimate");
|
|
296
|
-
}
|
|
297
|
-
return feeEstimate;
|
|
298
|
-
}
|
|
299
|
-
/**
|
|
300
|
-
* Requests a swap of leaves to optimize wallet structure.
|
|
301
|
-
*
|
|
302
|
-
* @param {Object} params - Parameters for the leaves swap
|
|
303
|
-
* @param {number} [params.targetAmount] - Target amount for the swap
|
|
304
|
-
* @param {TreeNode[]} [params.leaves] - Specific leaves to swap
|
|
305
|
-
* @returns {Promise<Object>} The completed swap response
|
|
306
|
-
*/
|
|
307
|
-
async requestLeavesSwap({ targetAmount, leaves, }) {
|
|
308
|
-
if (targetAmount && targetAmount <= 0) {
|
|
309
|
-
throw new Error("targetAmount must be positive");
|
|
310
|
-
}
|
|
311
|
-
await this.claimTransfers();
|
|
312
|
-
let leavesToSwap;
|
|
313
|
-
if (targetAmount && leaves && leaves.length > 0) {
|
|
314
|
-
if (targetAmount < leaves.reduce((acc, leaf) => acc + leaf.value, 0)) {
|
|
315
|
-
throw new Error("targetAmount is less than the sum of leaves");
|
|
316
|
-
}
|
|
317
|
-
leavesToSwap = leaves;
|
|
318
|
-
}
|
|
319
|
-
else if (targetAmount) {
|
|
320
|
-
leavesToSwap = await this.selectLeavesForSwap(targetAmount);
|
|
321
|
-
}
|
|
322
|
-
else if (leaves && leaves.length > 0) {
|
|
323
|
-
leavesToSwap = leaves;
|
|
324
|
-
}
|
|
325
|
-
else {
|
|
326
|
-
throw new Error("targetAmount or leaves must be provided");
|
|
327
|
-
}
|
|
328
|
-
const leafKeyTweaks = await Promise.all(leavesToSwap.map(async (leaf) => ({
|
|
329
|
-
leaf,
|
|
330
|
-
signingPubKey: await this.config.signer.generatePublicKey(sha256(leaf.id)),
|
|
331
|
-
newSigningPubKey: await this.config.signer.generatePublicKey(),
|
|
332
|
-
})));
|
|
333
|
-
const { transfer, signatureMap } = await this.transferService.sendTransferSignRefund(leafKeyTweaks, await this.config.signer.getSspIdentityPublicKey(this.config.getNetwork()), new Date(Date.now() + 2 * 60 * 1000));
|
|
334
|
-
try {
|
|
335
|
-
if (!transfer.leaves[0]?.leaf) {
|
|
336
|
-
throw new Error("Failed to get leaf");
|
|
337
|
-
}
|
|
338
|
-
const refundSignature = signatureMap.get(transfer.leaves[0].leaf.id);
|
|
339
|
-
if (!refundSignature) {
|
|
340
|
-
throw new Error("Failed to get refund signature");
|
|
341
|
-
}
|
|
342
|
-
const { adaptorPrivateKey, adaptorSignature } = generateAdaptorFromSignature(refundSignature);
|
|
343
|
-
if (!transfer.leaves[0].leaf) {
|
|
344
|
-
throw new Error("Failed to get leaf");
|
|
345
|
-
}
|
|
346
|
-
const userLeaves = [];
|
|
347
|
-
userLeaves.push({
|
|
348
|
-
leaf_id: transfer.leaves[0].leaf.id,
|
|
349
|
-
raw_unsigned_refund_transaction: bytesToHex(transfer.leaves[0].intermediateRefundTx),
|
|
350
|
-
adaptor_added_signature: bytesToHex(adaptorSignature),
|
|
351
|
-
});
|
|
352
|
-
for (let i = 1; i < transfer.leaves.length; i++) {
|
|
353
|
-
const leaf = transfer.leaves[i];
|
|
354
|
-
if (!leaf?.leaf) {
|
|
355
|
-
throw new Error("Failed to get leaf");
|
|
356
|
-
}
|
|
357
|
-
const refundSignature = signatureMap.get(leaf.leaf.id);
|
|
358
|
-
if (!refundSignature) {
|
|
359
|
-
throw new Error("Failed to get refund signature");
|
|
360
|
-
}
|
|
361
|
-
const signature = generateSignatureFromExistingAdaptor(refundSignature, adaptorPrivateKey);
|
|
362
|
-
userLeaves.push({
|
|
363
|
-
leaf_id: leaf.leaf.id,
|
|
364
|
-
raw_unsigned_refund_transaction: bytesToHex(leaf.intermediateRefundTx),
|
|
365
|
-
adaptor_added_signature: bytesToHex(signature),
|
|
366
|
-
});
|
|
367
|
-
}
|
|
368
|
-
const adaptorPubkey = bytesToHex(secp256k1.getPublicKey(adaptorPrivateKey));
|
|
369
|
-
let request = null;
|
|
370
|
-
request = await this.sspClient?.requestLeaveSwap({
|
|
371
|
-
userLeaves,
|
|
372
|
-
adaptorPubkey,
|
|
373
|
-
targetAmountSats: targetAmount ||
|
|
374
|
-
leavesToSwap.reduce((acc, leaf) => acc + leaf.value, 0),
|
|
375
|
-
totalAmountSats: leavesToSwap.reduce((acc, leaf) => acc + leaf.value, 0),
|
|
376
|
-
// TODO: Request fee from SSP
|
|
377
|
-
feeSats: 0,
|
|
378
|
-
});
|
|
379
|
-
if (!request) {
|
|
380
|
-
throw new Error("Failed to request leaves swap. No response returned.");
|
|
381
|
-
}
|
|
382
|
-
const sparkClient = await this.connectionManager.createSparkClient(this.config.getCoordinatorAddress());
|
|
383
|
-
const nodes = await sparkClient.query_nodes({
|
|
384
|
-
source: {
|
|
385
|
-
$case: "nodeIds",
|
|
386
|
-
nodeIds: {
|
|
387
|
-
nodeIds: request.swapLeaves.map((leaf) => leaf.leafId),
|
|
388
|
-
},
|
|
389
|
-
},
|
|
390
|
-
includeParents: false,
|
|
391
|
-
network: this.config.getNetworkProto(),
|
|
392
|
-
});
|
|
393
|
-
if (Object.values(nodes.nodes).length !== request.swapLeaves.length) {
|
|
394
|
-
throw new Error("Expected same number of nodes as swapLeaves");
|
|
395
|
-
}
|
|
396
|
-
for (const [nodeId, node] of Object.entries(nodes.nodes)) {
|
|
397
|
-
if (!node.nodeTx) {
|
|
398
|
-
throw new Error(`Node tx not found for leaf ${nodeId}`);
|
|
399
|
-
}
|
|
400
|
-
if (!node.verifyingPublicKey) {
|
|
401
|
-
throw new Error(`Node public key not found for leaf ${nodeId}`);
|
|
402
|
-
}
|
|
403
|
-
const leaf = request.swapLeaves.find((leaf) => leaf.leafId === nodeId);
|
|
404
|
-
if (!leaf) {
|
|
405
|
-
throw new Error(`Leaf not found for node ${nodeId}`);
|
|
406
|
-
}
|
|
407
|
-
// @ts-ignore - We do a null check above
|
|
408
|
-
const nodeTx = getTxFromRawTxBytes(node.nodeTx);
|
|
409
|
-
const refundTxBytes = hexToBytes(leaf.rawUnsignedRefundTransaction);
|
|
410
|
-
const refundTx = getTxFromRawTxBytes(refundTxBytes);
|
|
411
|
-
const sighash = getSigHashFromTx(refundTx, 0, nodeTx.getOutput(0));
|
|
412
|
-
const nodePublicKey = node.verifyingPublicKey;
|
|
413
|
-
const taprootKey = computeTaprootKeyNoScript(nodePublicKey.slice(1));
|
|
414
|
-
const adaptorSignatureBytes = hexToBytes(leaf.adaptorSignedSignature);
|
|
415
|
-
applyAdaptorToSignature(taprootKey.slice(1), sighash, adaptorSignatureBytes, adaptorPrivateKey);
|
|
416
|
-
}
|
|
417
|
-
await this.transferService.sendTransferTweakKey(transfer, leafKeyTweaks, signatureMap);
|
|
418
|
-
const completeResponse = await this.sspClient?.completeLeaveSwap({
|
|
419
|
-
adaptorSecretKey: bytesToHex(adaptorPrivateKey),
|
|
420
|
-
userOutboundTransferExternalId: transfer.id,
|
|
421
|
-
leavesSwapRequestId: request.id,
|
|
422
|
-
});
|
|
423
|
-
if (!completeResponse) {
|
|
424
|
-
throw new Error("Failed to complete leaves swap");
|
|
425
|
-
}
|
|
426
|
-
await this.claimTransfers();
|
|
427
|
-
return completeResponse;
|
|
428
|
-
}
|
|
429
|
-
catch (e) {
|
|
430
|
-
await this.cancelAllSenderInitiatedTransfers();
|
|
431
|
-
throw new Error(`Failed to request leaves swap: ${e}`);
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
/**
|
|
435
|
-
* Gets all transfers for the wallet.
|
|
436
|
-
*
|
|
437
|
-
* @param {number} [limit=20] - Maximum number of transfers to return
|
|
438
|
-
* @param {number} [offset=0] - Offset for pagination
|
|
439
|
-
* @returns {Promise<QueryAllTransfersResponse>} Response containing the list of transfers
|
|
440
|
-
*/
|
|
441
|
-
async getTransfers(limit = 20, offset = 0) {
|
|
442
|
-
return await this.transferService.queryAllTransfers(limit, offset);
|
|
443
|
-
}
|
|
444
|
-
async getTokenInfo() {
|
|
445
|
-
await this.syncTokenLeaves();
|
|
446
|
-
const lrc20Client = await this.lrc20ConnectionManager.createLrc20Client();
|
|
447
|
-
const { balance, tokenBalances } = await this.getBalance();
|
|
448
|
-
const tokenInfo = await lrc20Client.getTokenPubkeyInfo({
|
|
449
|
-
publicKeys: Array.from(tokenBalances.keys()).map(hexToBytes)
|
|
450
|
-
});
|
|
451
|
-
return tokenInfo.tokenPubkeyInfos.map((info) => ({
|
|
452
|
-
tokenPublicKey: bytesToHex(info.announcement.publicKey.publicKey),
|
|
453
|
-
tokenName: info.announcement.name,
|
|
454
|
-
tokenSymbol: info.announcement.symbol,
|
|
455
|
-
tokenDecimals: Number(bytesToNumberBE(info.announcement.decimal)),
|
|
456
|
-
tokenSupply: bytesToNumberBE(info.totalSupply),
|
|
457
|
-
}));
|
|
458
|
-
}
|
|
459
|
-
/**
|
|
460
|
-
* Gets the current balance of the wallet.
|
|
461
|
-
* You can use the forceRefetch option to synchronize your wallet and claim any
|
|
462
|
-
* pending incoming lightning payment, spark transfer, or bitcoin deposit before returning the balance.
|
|
463
|
-
*
|
|
464
|
-
* @returns {Promise<Object>} Object containing:
|
|
465
|
-
* - balance: The wallet's current balance in satoshis
|
|
466
|
-
* - tokenBalances: Map of token balances and leaf counts
|
|
467
|
-
*/
|
|
468
|
-
async getBalance() {
|
|
469
|
-
this.leaves = await this.getLeaves();
|
|
470
|
-
await this.syncTokenLeaves();
|
|
471
|
-
const tokenBalances = new Map();
|
|
472
|
-
for (const [tokenPublicKey, leaves] of this.tokenLeaves.entries()) {
|
|
473
|
-
tokenBalances.set(tokenPublicKey, {
|
|
474
|
-
balance: calculateAvailableTokenAmount(leaves),
|
|
475
|
-
});
|
|
476
|
-
}
|
|
477
|
-
return {
|
|
478
|
-
balance: this.leaves.reduce((acc, leaf) => acc + BigInt(leaf.value), 0n),
|
|
479
|
-
tokenBalances,
|
|
480
|
-
};
|
|
481
|
-
}
|
|
482
|
-
// ***** Deposit Flow *****
|
|
483
|
-
/**
|
|
484
|
-
* Generates a new deposit address for receiving bitcoin funds.
|
|
485
|
-
* Note that this function returns a bitcoin address, not a spark address.
|
|
486
|
-
* For Layer 1 Bitcoin deposits, Spark generates Pay to Taproot (P2TR) addresses.
|
|
487
|
-
* These addresses start with "bc1p" and can be used to receive Bitcoin from any wallet.
|
|
488
|
-
*
|
|
489
|
-
* @returns {Promise<string>} A Bitcoin address for depositing funds
|
|
490
|
-
*/
|
|
491
|
-
async getDepositAddress() {
|
|
492
|
-
return await this.generateDepositAddress();
|
|
493
|
-
}
|
|
494
|
-
/**
|
|
495
|
-
* Generates a deposit address for receiving funds.
|
|
496
|
-
*
|
|
497
|
-
* @returns {Promise<string>} A deposit address
|
|
498
|
-
* @private
|
|
499
|
-
*/
|
|
500
|
-
async generateDepositAddress() {
|
|
501
|
-
const signingPubkey = await this.config.signer.getDepositSigningKey();
|
|
502
|
-
const address = await this.depositService.generateDepositAddress({
|
|
503
|
-
signingPubkey,
|
|
504
|
-
});
|
|
505
|
-
if (!address.depositAddress) {
|
|
506
|
-
throw new Error("Failed to generate deposit address");
|
|
507
|
-
}
|
|
508
|
-
return address.depositAddress.address;
|
|
509
|
-
}
|
|
510
|
-
/**
|
|
511
|
-
* Finalizes a deposit to the wallet.
|
|
512
|
-
*
|
|
513
|
-
* @param {DepositParams} params - Parameters for finalizing the deposit
|
|
514
|
-
* @returns {Promise<TreeNode[] | undefined>} The nodes created from the deposit
|
|
515
|
-
* @private
|
|
516
|
-
*/
|
|
517
|
-
async finalizeDeposit({ signingPubKey, verifyingKey, depositTx, vout, }) {
|
|
518
|
-
const response = await this.depositService.createTreeRoot({
|
|
519
|
-
signingPubKey,
|
|
520
|
-
verifyingKey,
|
|
521
|
-
depositTx,
|
|
522
|
-
vout,
|
|
523
|
-
});
|
|
524
|
-
return await this.transferDepositToSelf(response.nodes, signingPubKey);
|
|
525
|
-
}
|
|
526
|
-
/**
|
|
527
|
-
* Gets all unused deposit addresses for the wallet.
|
|
528
|
-
*
|
|
529
|
-
* @returns {Promise<string[]>} The unused deposit addresses
|
|
530
|
-
*/
|
|
531
|
-
async getUnusedDepositAddresses() {
|
|
532
|
-
const sparkClient = await this.connectionManager.createSparkClient(this.config.getCoordinatorAddress());
|
|
533
|
-
return (await sparkClient.query_unused_deposit_addresses({
|
|
534
|
-
identityPublicKey: await this.config.signer.getIdentityPublicKey(),
|
|
535
|
-
})).depositAddresses.map((addr) => addr.depositAddress);
|
|
536
|
-
}
|
|
537
|
-
/**
|
|
538
|
-
* Claims a deposit to the wallet.
|
|
539
|
-
*
|
|
540
|
-
* @param {string} txid - The transaction ID of the deposit
|
|
541
|
-
* @returns {Promise<TreeNode[] | undefined>} The nodes resulting from the deposit
|
|
542
|
-
*/
|
|
543
|
-
async claimDeposit(txid) {
|
|
544
|
-
let mutex = this.mutexes.get(txid);
|
|
545
|
-
if (!mutex) {
|
|
546
|
-
mutex = new Mutex();
|
|
547
|
-
this.mutexes.set(txid, mutex);
|
|
548
|
-
}
|
|
549
|
-
const nodes = await mutex.runExclusive(async () => {
|
|
550
|
-
const baseUrl = this.config.getNetwork() === Network.REGTEST
|
|
551
|
-
? "https://regtest-mempool.dev.dev.sparkinfra.net/api"
|
|
552
|
-
: "https://mempool.space/api";
|
|
553
|
-
const auth = btoa("spark-sdk:mCMk1JqlBNtetUNy");
|
|
554
|
-
const headers = {
|
|
555
|
-
"Content-Type": "application/json",
|
|
556
|
-
};
|
|
557
|
-
if (this.config.getNetwork() === Network.REGTEST) {
|
|
558
|
-
headers["Authorization"] = `Basic ${auth}`;
|
|
559
|
-
}
|
|
560
|
-
const response = await fetch(`${baseUrl}/tx/${txid}/hex`, {
|
|
561
|
-
headers,
|
|
562
|
-
});
|
|
563
|
-
const txHex = await response.text();
|
|
564
|
-
if (!/^[0-9A-Fa-f]+$/.test(txHex)) {
|
|
565
|
-
throw new Error("Transaction not found");
|
|
566
|
-
}
|
|
567
|
-
const depositTx = getTxFromRawTxHex(txHex);
|
|
568
|
-
const sparkClient = await this.connectionManager.createSparkClient(this.config.getCoordinatorAddress());
|
|
569
|
-
const unusedDepositAddresses = new Map((await sparkClient.query_unused_deposit_addresses({
|
|
570
|
-
identityPublicKey: await this.config.signer.getIdentityPublicKey(),
|
|
571
|
-
})).depositAddresses.map((addr) => [addr.depositAddress, addr]));
|
|
572
|
-
let depositAddress;
|
|
573
|
-
let vout = 0;
|
|
574
|
-
for (let i = 0; i < depositTx.outputsLength; i++) {
|
|
575
|
-
const output = depositTx.getOutput(i);
|
|
576
|
-
if (!output) {
|
|
577
|
-
continue;
|
|
578
|
-
}
|
|
579
|
-
const parsedScript = OutScript.decode(output.script);
|
|
580
|
-
const address = Address(getNetwork(this.config.getNetwork())).encode(parsedScript);
|
|
581
|
-
if (unusedDepositAddresses.has(address)) {
|
|
582
|
-
vout = i;
|
|
583
|
-
depositAddress = unusedDepositAddresses.get(address);
|
|
584
|
-
break;
|
|
585
|
-
}
|
|
586
|
-
}
|
|
587
|
-
if (!depositAddress) {
|
|
588
|
-
return [];
|
|
589
|
-
}
|
|
590
|
-
const nodes = await this.finalizeDeposit({
|
|
591
|
-
signingPubKey: depositAddress.userSigningPublicKey,
|
|
592
|
-
verifyingKey: depositAddress.verifyingPublicKey,
|
|
593
|
-
depositTx,
|
|
594
|
-
vout,
|
|
595
|
-
});
|
|
596
|
-
return nodes;
|
|
597
|
-
});
|
|
598
|
-
this.mutexes.delete(txid);
|
|
599
|
-
return nodes;
|
|
600
|
-
}
|
|
601
|
-
/**
|
|
602
|
-
* Transfers deposit to self to claim ownership.
|
|
603
|
-
*
|
|
604
|
-
* @param {TreeNode[]} leaves - The leaves to transfer
|
|
605
|
-
* @param {Uint8Array} signingPubKey - The signing public key
|
|
606
|
-
* @returns {Promise<TreeNode[] | undefined>} The nodes resulting from the transfer
|
|
607
|
-
* @private
|
|
608
|
-
*/
|
|
609
|
-
async transferDepositToSelf(leaves, signingPubKey) {
|
|
610
|
-
const leafKeyTweaks = await Promise.all(leaves.map(async (leaf) => ({
|
|
611
|
-
leaf,
|
|
612
|
-
signingPubKey,
|
|
613
|
-
newSigningPubKey: await this.config.signer.generatePublicKey(),
|
|
614
|
-
})));
|
|
615
|
-
const transfer = await this.transferService.sendTransfer(leafKeyTweaks, await this.config.signer.getIdentityPublicKey());
|
|
616
|
-
return await this.claimTransfer(transfer);
|
|
617
|
-
}
|
|
618
|
-
// ***** Transfer Flow *****
|
|
619
|
-
/**
|
|
620
|
-
* Sends a transfer to another Spark user.
|
|
621
|
-
*
|
|
622
|
-
* @param {TransferParams} params - Parameters for the transfer
|
|
623
|
-
* @param {string} params.receiverSparkAddress - The recipient's Spark address
|
|
624
|
-
* @param {number} params.amountSats - Amount to send in satoshis
|
|
625
|
-
* @returns {Promise<Transfer>} The completed transfer details
|
|
626
|
-
*/
|
|
627
|
-
async transfer({ amountSats, receiverSparkAddress }) {
|
|
628
|
-
return await this.withLeaves(async () => {
|
|
629
|
-
const leavesToSend = await this.selectLeaves(amountSats);
|
|
630
|
-
await this.refreshTimelockNodes();
|
|
631
|
-
await this.extendTimeLockNodes();
|
|
632
|
-
const leafKeyTweaks = await Promise.all(leavesToSend.map(async (leaf) => ({
|
|
633
|
-
leaf,
|
|
634
|
-
signingPubKey: await this.config.signer.generatePublicKey(sha256(leaf.id)),
|
|
635
|
-
newSigningPubKey: await this.config.signer.generatePublicKey(),
|
|
636
|
-
})));
|
|
637
|
-
const transfer = await this.transferService.sendTransfer(leafKeyTweaks, hexToBytes(receiverSparkAddress));
|
|
638
|
-
const leavesToRemove = new Set(leavesToSend.map((leaf) => leaf.id));
|
|
639
|
-
this.leaves = this.leaves.filter((leaf) => !leavesToRemove.has(leaf.id));
|
|
640
|
-
return transfer;
|
|
641
|
-
});
|
|
642
|
-
}
|
|
643
|
-
async extendTimeLockNodes() {
|
|
644
|
-
const nodesToExtend = [];
|
|
645
|
-
const nodeIds = [];
|
|
646
|
-
for (const node of this.leaves) {
|
|
647
|
-
const nodeTx = getTxFromRawTxBytes(node.nodeTx);
|
|
648
|
-
const { nextSequence } = getNextTransactionSequence(nodeTx.getInput(0).sequence);
|
|
649
|
-
if (nextSequence <= 0) {
|
|
650
|
-
nodesToExtend.push(node);
|
|
651
|
-
nodeIds.push(node.id);
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
for (const node of nodesToExtend) {
|
|
655
|
-
await this.transferService.extendTimelock(node, await this.config.signer.generatePublicKey(sha256(node.id)));
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
/**
|
|
659
|
-
* Internal method to refresh timelock nodes.
|
|
660
|
-
*
|
|
661
|
-
* @param {string} nodeId - The optional ID of the node to refresh. If not provided, all nodes will be checked.
|
|
662
|
-
* @returns {Promise<void>}
|
|
663
|
-
* @private
|
|
664
|
-
*/
|
|
665
|
-
async refreshTimelockNodes(nodeId) {
|
|
666
|
-
const nodesToRefresh = [];
|
|
667
|
-
const nodeIds = [];
|
|
668
|
-
if (nodeId) {
|
|
669
|
-
for (const node of this.leaves) {
|
|
670
|
-
if (node.id === nodeId) {
|
|
671
|
-
nodesToRefresh.push(node);
|
|
672
|
-
nodeIds.push(node.id);
|
|
673
|
-
break;
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
if (nodesToRefresh.length === 0) {
|
|
677
|
-
throw new Error(`node ${nodeId} not found`);
|
|
678
|
-
}
|
|
679
|
-
}
|
|
680
|
-
else {
|
|
681
|
-
for (const node of this.leaves) {
|
|
682
|
-
const refundTx = getTxFromRawTxBytes(node.refundTx);
|
|
683
|
-
const { needRefresh } = getNextTransactionSequence(refundTx.getInput(0).sequence);
|
|
684
|
-
if (needRefresh) {
|
|
685
|
-
nodesToRefresh.push(node);
|
|
686
|
-
nodeIds.push(node.id);
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
}
|
|
690
|
-
if (nodesToRefresh.length === 0) {
|
|
691
|
-
return;
|
|
692
|
-
}
|
|
693
|
-
const sparkClient = await this.connectionManager.createSparkClient(this.config.getCoordinatorAddress());
|
|
694
|
-
const nodesResp = await sparkClient.query_nodes({
|
|
695
|
-
source: {
|
|
696
|
-
$case: "nodeIds",
|
|
697
|
-
nodeIds: {
|
|
698
|
-
nodeIds,
|
|
699
|
-
},
|
|
700
|
-
},
|
|
701
|
-
includeParents: true,
|
|
702
|
-
network: this.config.getNetworkProto(),
|
|
703
|
-
});
|
|
704
|
-
const nodesMap = new Map();
|
|
705
|
-
for (const node of Object.values(nodesResp.nodes)) {
|
|
706
|
-
nodesMap.set(node.id, node);
|
|
707
|
-
}
|
|
708
|
-
for (const node of nodesToRefresh) {
|
|
709
|
-
if (!node.parentNodeId) {
|
|
710
|
-
throw new Error(`node ${node.id} has no parent`);
|
|
711
|
-
}
|
|
712
|
-
const parentNode = nodesMap.get(node.parentNodeId);
|
|
713
|
-
if (!parentNode) {
|
|
714
|
-
throw new Error(`parent node ${node.parentNodeId} not found`);
|
|
715
|
-
}
|
|
716
|
-
const { nodes } = await this.transferService.refreshTimelockNodes([node], parentNode, await this.config.signer.generatePublicKey(sha256(node.id)));
|
|
717
|
-
if (nodes.length !== 1) {
|
|
718
|
-
throw new Error(`expected 1 node, got ${nodes.length}`);
|
|
719
|
-
}
|
|
720
|
-
const newNode = nodes[0];
|
|
721
|
-
if (!newNode) {
|
|
722
|
-
throw new Error("Failed to refresh timelock node");
|
|
723
|
-
}
|
|
724
|
-
this.leaves = this.leaves.filter((leaf) => leaf.id !== node.id);
|
|
725
|
-
this.leaves.push(newNode);
|
|
726
|
-
}
|
|
727
|
-
}
|
|
728
|
-
/**
|
|
729
|
-
* Gets all pending transfers.
|
|
730
|
-
*
|
|
731
|
-
* @returns {Promise<Transfer[]>} The pending transfers
|
|
732
|
-
*/
|
|
733
|
-
async getPendingTransfers() {
|
|
734
|
-
return (await this.transferService.queryPendingTransfers()).transfers;
|
|
735
|
-
}
|
|
736
|
-
/**
|
|
737
|
-
* Claims a specific transfer.
|
|
738
|
-
*
|
|
739
|
-
* @param {Transfer} transfer - The transfer to claim
|
|
740
|
-
* @returns {Promise<Object>} The claim result
|
|
741
|
-
*/
|
|
742
|
-
async claimTransfer(transfer) {
|
|
743
|
-
return await this.claimTransferMutex.runExclusive(async () => {
|
|
744
|
-
const leafPubKeyMap = await this.transferService.verifyPendingTransfer(transfer);
|
|
745
|
-
let leavesToClaim = [];
|
|
746
|
-
for (const leaf of transfer.leaves) {
|
|
747
|
-
if (leaf.leaf) {
|
|
748
|
-
const leafPubKey = leafPubKeyMap.get(leaf.leaf.id);
|
|
749
|
-
if (leafPubKey) {
|
|
750
|
-
leavesToClaim.push({
|
|
751
|
-
leaf: leaf.leaf,
|
|
752
|
-
signingPubKey: leafPubKey,
|
|
753
|
-
newSigningPubKey: await this.config.signer.generatePublicKey(sha256(leaf.leaf.id)),
|
|
754
|
-
});
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
const response = await this.transferService.claimTransfer(transfer, leavesToClaim);
|
|
759
|
-
this.leaves.push(...response.nodes);
|
|
760
|
-
await this.refreshTimelockNodes();
|
|
761
|
-
await this.extendTimeLockNodes();
|
|
762
|
-
return response.nodes;
|
|
763
|
-
});
|
|
764
|
-
}
|
|
765
|
-
/**
|
|
766
|
-
* Claims all pending transfers.
|
|
767
|
-
*
|
|
768
|
-
* @returns {Promise<boolean>} True if any transfers were claimed
|
|
769
|
-
*/
|
|
770
|
-
async claimTransfers() {
|
|
771
|
-
const transfers = await this.transferService.queryPendingTransfers();
|
|
772
|
-
let claimed = false;
|
|
773
|
-
for (const transfer of transfers.transfers) {
|
|
774
|
-
if (transfer.status !== TransferStatus.TRANSFER_STATUS_SENDER_KEY_TWEAKED &&
|
|
775
|
-
transfer.status !==
|
|
776
|
-
TransferStatus.TRANSFER_STATUS_RECEIVER_KEY_TWEAKED &&
|
|
777
|
-
transfer.status !==
|
|
778
|
-
TransferStatus.TRANSFER_STATUSR_RECEIVER_REFUND_SIGNED) {
|
|
779
|
-
continue;
|
|
780
|
-
}
|
|
781
|
-
await this.claimTransfer(transfer);
|
|
782
|
-
claimed = true;
|
|
783
|
-
}
|
|
784
|
-
return claimed;
|
|
785
|
-
}
|
|
786
|
-
/**
|
|
787
|
-
* Cancels all sender-initiated transfers.
|
|
788
|
-
*
|
|
789
|
-
* @returns {Promise<void>}
|
|
790
|
-
* @private
|
|
791
|
-
*/
|
|
792
|
-
async cancelAllSenderInitiatedTransfers() {
|
|
793
|
-
for (const operator of Object.values(this.config.getSigningOperators())) {
|
|
794
|
-
const transfers = await this.transferService.queryPendingTransfersBySender(operator.address);
|
|
795
|
-
for (const transfer of transfers.transfers) {
|
|
796
|
-
if (transfer.status === TransferStatus.TRANSFER_STATUS_SENDER_INITIATED) {
|
|
797
|
-
await this.transferService.cancelSendTransfer(transfer, operator.address);
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
// ***** Lightning Flow *****
|
|
803
|
-
/**
|
|
804
|
-
* Creates a Lightning invoice for receiving payments.
|
|
805
|
-
*
|
|
806
|
-
* @param {Object} params - Parameters for the lightning invoice
|
|
807
|
-
* @param {number} params.amountSats - Amount in satoshis
|
|
808
|
-
* @param {string} params.memo - Description for the invoice
|
|
809
|
-
* @param {number} [params.expirySeconds] - Optional expiry time in seconds
|
|
810
|
-
* @returns {Promise<LightningReceiveRequest>} BOLT11 encoded invoice
|
|
811
|
-
*/
|
|
812
|
-
async createLightningInvoice({ amountSats, memo, expirySeconds = 60 * 60 * 24 * 30, }) {
|
|
813
|
-
if (!this.sspClient) {
|
|
814
|
-
throw new Error("SSP client not initialized");
|
|
815
|
-
}
|
|
816
|
-
const requestLightningInvoice = async (amountSats, paymentHash, memo) => {
|
|
817
|
-
const network = this.config.getNetwork();
|
|
818
|
-
let bitcoinNetwork = BitcoinNetwork.REGTEST;
|
|
819
|
-
if (network === Network.MAINNET) {
|
|
820
|
-
bitcoinNetwork = BitcoinNetwork.MAINNET;
|
|
821
|
-
}
|
|
822
|
-
else if (network === Network.REGTEST) {
|
|
823
|
-
bitcoinNetwork = BitcoinNetwork.REGTEST;
|
|
824
|
-
}
|
|
825
|
-
const invoice = await this.sspClient.requestLightningReceive({
|
|
826
|
-
amountSats,
|
|
827
|
-
network: bitcoinNetwork,
|
|
828
|
-
paymentHash: bytesToHex(paymentHash),
|
|
829
|
-
expirySecs: expirySeconds,
|
|
830
|
-
memo,
|
|
831
|
-
});
|
|
832
|
-
return invoice;
|
|
833
|
-
};
|
|
834
|
-
const invoice = await this.lightningService.createLightningInvoice({
|
|
835
|
-
amountSats,
|
|
836
|
-
memo,
|
|
837
|
-
invoiceCreator: requestLightningInvoice,
|
|
838
|
-
});
|
|
839
|
-
return invoice;
|
|
840
|
-
}
|
|
841
|
-
/**
|
|
842
|
-
* Pays a Lightning invoice.
|
|
843
|
-
*
|
|
844
|
-
* @param {Object} params - Parameters for paying the invoice
|
|
845
|
-
* @param {string} params.invoice - The BOLT11-encoded Lightning invoice to pay
|
|
846
|
-
* @returns {Promise<LightningSendRequest>} The Lightning payment request details
|
|
847
|
-
*/
|
|
848
|
-
async payLightningInvoice({ invoice }) {
|
|
849
|
-
return await this.withLeaves(async () => {
|
|
850
|
-
if (!this.sspClient) {
|
|
851
|
-
throw new Error("SSP client not initialized");
|
|
852
|
-
}
|
|
853
|
-
// TODO: Get fee
|
|
854
|
-
const decodedInvoice = decode(invoice);
|
|
855
|
-
const amountSats = Number(decodedInvoice.sections.find((section) => section.name === "amount")
|
|
856
|
-
?.value) / 1000;
|
|
857
|
-
if (isNaN(amountSats) || amountSats <= 0) {
|
|
858
|
-
throw new Error("Invalid amount");
|
|
859
|
-
}
|
|
860
|
-
const paymentHash = decodedInvoice.sections.find((section) => section.name === "payment_hash")?.value;
|
|
861
|
-
if (!paymentHash) {
|
|
862
|
-
throw new Error("No payment hash found in invoice");
|
|
863
|
-
}
|
|
864
|
-
const leaves = await this.selectLeaves(amountSats);
|
|
865
|
-
await this.refreshTimelockNodes();
|
|
866
|
-
await this.extendTimeLockNodes();
|
|
867
|
-
const leavesToSend = await Promise.all(leaves.map(async (leaf) => ({
|
|
868
|
-
leaf,
|
|
869
|
-
signingPubKey: await this.config.signer.generatePublicKey(sha256(leaf.id)),
|
|
870
|
-
newSigningPubKey: await this.config.signer.generatePublicKey(),
|
|
871
|
-
})));
|
|
872
|
-
const swapResponse = await this.lightningService.swapNodesForPreimage({
|
|
873
|
-
leaves: leavesToSend,
|
|
874
|
-
receiverIdentityPubkey: await this.config.signer.getSspIdentityPublicKey(this.config.getNetwork()),
|
|
875
|
-
paymentHash: hexToBytes(paymentHash),
|
|
876
|
-
isInboundPayment: false,
|
|
877
|
-
invoiceString: invoice,
|
|
878
|
-
});
|
|
879
|
-
if (!swapResponse.transfer) {
|
|
880
|
-
throw new Error("Failed to swap nodes for preimage");
|
|
881
|
-
}
|
|
882
|
-
const transfer = await this.transferService.sendTransferTweakKey(swapResponse.transfer, leavesToSend, new Map());
|
|
883
|
-
const sspResponse = await this.sspClient.requestLightningSend({
|
|
884
|
-
encodedInvoice: invoice,
|
|
885
|
-
idempotencyKey: paymentHash,
|
|
886
|
-
});
|
|
887
|
-
if (!sspResponse) {
|
|
888
|
-
throw new Error("Failed to contact SSP");
|
|
889
|
-
}
|
|
890
|
-
const leavesToRemove = new Set(leavesToSend.map((leaf) => leaf.leaf.id));
|
|
891
|
-
this.leaves = this.leaves.filter((leaf) => !leavesToRemove.has(leaf.id));
|
|
892
|
-
return sspResponse;
|
|
893
|
-
});
|
|
894
|
-
}
|
|
895
|
-
/**
|
|
896
|
-
* Gets fee estimate for receiving Lightning payments.
|
|
897
|
-
*
|
|
898
|
-
* @param {LightningReceiveFeeEstimateInput} params - Input parameters for fee estimation
|
|
899
|
-
* @returns {Promise<LightningReceiveFeeEstimateOutput | null>} Fee estimate for receiving Lightning payments
|
|
900
|
-
*/
|
|
901
|
-
async getLightningReceiveFeeEstimate({ amountSats, network, }) {
|
|
902
|
-
if (!this.sspClient) {
|
|
903
|
-
throw new Error("SSP client not initialized");
|
|
904
|
-
}
|
|
905
|
-
const feeEstimate = await this.sspClient.getLightningReceiveFeeEstimate(amountSats, network);
|
|
906
|
-
if (!feeEstimate) {
|
|
907
|
-
throw new Error("Failed to get lightning receive fee estimate");
|
|
908
|
-
}
|
|
909
|
-
return feeEstimate;
|
|
910
|
-
}
|
|
911
|
-
/**
|
|
912
|
-
* Gets fee estimate for sending Lightning payments.
|
|
913
|
-
*
|
|
914
|
-
* @param {LightningSendFeeEstimateInput} params - Input parameters for fee estimation
|
|
915
|
-
* @returns {Promise<LightningSendFeeEstimateOutput | null>} Fee estimate for sending Lightning payments
|
|
916
|
-
*/
|
|
917
|
-
async getLightningSendFeeEstimate({ encodedInvoice, }) {
|
|
918
|
-
if (!this.sspClient) {
|
|
919
|
-
throw new Error("SSP client not initialized");
|
|
920
|
-
}
|
|
921
|
-
const feeEstimate = await this.sspClient.getLightningSendFeeEstimate(encodedInvoice);
|
|
922
|
-
if (!feeEstimate) {
|
|
923
|
-
throw new Error("Failed to get lightning send fee estimate");
|
|
924
|
-
}
|
|
925
|
-
return feeEstimate;
|
|
926
|
-
}
|
|
927
|
-
// ***** Tree Creation Flow *****
|
|
928
|
-
/**
|
|
929
|
-
* Generates a deposit address for a tree.
|
|
930
|
-
*
|
|
931
|
-
* @param {number} vout - The vout index
|
|
932
|
-
* @param {Uint8Array} parentSigningPubKey - The parent signing public key
|
|
933
|
-
* @param {Transaction} [parentTx] - Optional parent transaction
|
|
934
|
-
* @param {TreeNode} [parentNode] - Optional parent node
|
|
935
|
-
* @returns {Promise<Object>} Deposit address information
|
|
936
|
-
* @private
|
|
937
|
-
*/
|
|
938
|
-
async generateDepositAddressForTree(vout, parentSigningPubKey, parentTx, parentNode) {
|
|
939
|
-
return await this.treeCreationService.generateDepositAddressForTree(vout, parentSigningPubKey, parentTx, parentNode);
|
|
940
|
-
}
|
|
941
|
-
/**
|
|
942
|
-
* Creates a tree structure.
|
|
943
|
-
*
|
|
944
|
-
* @param {number} vout - The vout index
|
|
945
|
-
* @param {DepositAddressTree} root - The root of the tree
|
|
946
|
-
* @param {boolean} createLeaves - Whether to create leaves
|
|
947
|
-
* @param {Transaction} [parentTx] - Optional parent transaction
|
|
948
|
-
* @param {TreeNode} [parentNode] - Optional parent node
|
|
949
|
-
* @returns {Promise<Object>} The created tree
|
|
950
|
-
* @private
|
|
951
|
-
*/
|
|
952
|
-
async createTree(vout, root, createLeaves, parentTx, parentNode) {
|
|
953
|
-
return await this.treeCreationService.createTree(vout, root, createLeaves, parentTx, parentNode);
|
|
954
|
-
}
|
|
955
|
-
// ***** Cooperative Exit Flow *****
|
|
956
|
-
/**
|
|
957
|
-
* Initiates a withdrawal to move funds from the Spark network to an on-chain Bitcoin address.
|
|
958
|
-
*
|
|
959
|
-
* @param {Object} params - Parameters for the withdrawal
|
|
960
|
-
* @param {string} params.onchainAddress - The Bitcoin address where the funds should be sent
|
|
961
|
-
* @param {number} [params.amountSats] - The amount in satoshis to withdraw. If not specified, attempts to withdraw all available funds
|
|
962
|
-
* @returns {Promise<CoopExitRequest | null | undefined>} The withdrawal request details, or null/undefined if the request cannot be completed
|
|
963
|
-
*/
|
|
964
|
-
async withdraw({ onchainAddress, amountSats, }) {
|
|
965
|
-
if (amountSats && amountSats < 10000) {
|
|
966
|
-
throw new Error("The minimum amount for a withdrawal is 10000 sats");
|
|
967
|
-
}
|
|
968
|
-
return await this.withLeaves(async () => {
|
|
969
|
-
return await this.coopExit(onchainAddress, amountSats);
|
|
970
|
-
});
|
|
971
|
-
}
|
|
972
|
-
/**
|
|
973
|
-
* Internal method to perform a cooperative exit (withdrawal).
|
|
974
|
-
*
|
|
975
|
-
* @param {string} onchainAddress - The Bitcoin address where the funds should be sent
|
|
976
|
-
* @param {number} [targetAmountSats] - The amount in satoshis to withdraw
|
|
977
|
-
* @returns {Promise<Object | null | undefined>} The exit request details
|
|
978
|
-
* @private
|
|
979
|
-
*/
|
|
980
|
-
async coopExit(onchainAddress, targetAmountSats) {
|
|
981
|
-
let leavesToSend = [];
|
|
982
|
-
if (targetAmountSats) {
|
|
983
|
-
leavesToSend = await this.selectLeaves(targetAmountSats);
|
|
984
|
-
}
|
|
985
|
-
else {
|
|
986
|
-
leavesToSend = this.leaves.map((leaf) => ({
|
|
987
|
-
...leaf,
|
|
988
|
-
}));
|
|
989
|
-
}
|
|
990
|
-
if (leavesToSend.reduce((acc, leaf) => acc + leaf.value, 0) < 10000) {
|
|
991
|
-
throw new Error("The minimum amount for a withdrawal is 10000 sats");
|
|
992
|
-
}
|
|
993
|
-
const leafKeyTweaks = await Promise.all(leavesToSend.map(async (leaf) => ({
|
|
994
|
-
leaf,
|
|
995
|
-
signingPubKey: await this.config.signer.generatePublicKey(sha256(leaf.id)),
|
|
996
|
-
newSigningPubKey: await this.config.signer.generatePublicKey(),
|
|
997
|
-
})));
|
|
998
|
-
const coopExitRequest = await this.sspClient?.requestCoopExit({
|
|
999
|
-
leafExternalIds: leavesToSend.map((leaf) => leaf.id),
|
|
1000
|
-
withdrawalAddress: onchainAddress,
|
|
1001
|
-
});
|
|
1002
|
-
if (!coopExitRequest?.rawConnectorTransaction) {
|
|
1003
|
-
throw new Error("Failed to request coop exit");
|
|
1004
|
-
}
|
|
1005
|
-
const connectorTx = getTxFromRawTxHex(coopExitRequest.rawConnectorTransaction);
|
|
1006
|
-
const coopExitTxId = connectorTx.getInput(0).txid;
|
|
1007
|
-
const connectorTxId = getTxId(connectorTx);
|
|
1008
|
-
if (!coopExitTxId) {
|
|
1009
|
-
throw new Error("Failed to get coop exit tx id");
|
|
1010
|
-
}
|
|
1011
|
-
const connectorOutputs = [];
|
|
1012
|
-
for (let i = 0; i < connectorTx.outputsLength - 1; i++) {
|
|
1013
|
-
connectorOutputs.push({
|
|
1014
|
-
txid: hexToBytes(connectorTxId),
|
|
1015
|
-
index: i,
|
|
1016
|
-
});
|
|
1017
|
-
}
|
|
1018
|
-
const sspPubIdentityKey = await this.config.signer.getSspIdentityPublicKey(this.config.getNetwork());
|
|
1019
|
-
const transfer = await this.coopExitService.getConnectorRefundSignatures({
|
|
1020
|
-
leaves: leafKeyTweaks,
|
|
1021
|
-
exitTxId: coopExitTxId,
|
|
1022
|
-
connectorOutputs,
|
|
1023
|
-
receiverPubKey: sspPubIdentityKey,
|
|
1024
|
-
});
|
|
1025
|
-
const completeResponse = await this.sspClient?.completeCoopExit({
|
|
1026
|
-
userOutboundTransferExternalId: transfer.transfer.id,
|
|
1027
|
-
coopExitRequestId: coopExitRequest.id,
|
|
1028
|
-
});
|
|
1029
|
-
return completeResponse;
|
|
1030
|
-
}
|
|
1031
|
-
/**
|
|
1032
|
-
* Gets fee estimate for cooperative exit (on-chain withdrawal).
|
|
1033
|
-
*
|
|
1034
|
-
* @param {Object} params - Input parameters for fee estimation
|
|
1035
|
-
* @param {number} params.amountSats - The amount in satoshis to withdraw
|
|
1036
|
-
* @param {string} params.withdrawalAddress - The Bitcoin address where the funds should be sent
|
|
1037
|
-
* @returns {Promise<CoopExitFeeEstimateOutput | null>} Fee estimate for the withdrawal
|
|
1038
|
-
*/
|
|
1039
|
-
async getCoopExitFeeEstimate({ amountSats, withdrawalAddress, }) {
|
|
1040
|
-
if (!this.sspClient) {
|
|
1041
|
-
throw new Error("SSP client not initialized");
|
|
1042
|
-
}
|
|
1043
|
-
if (amountSats < 10000) {
|
|
1044
|
-
throw new Error("The minimum amount for a withdrawal is 10000 sats");
|
|
1045
|
-
}
|
|
1046
|
-
const leaves = await this.selectLeaves(amountSats);
|
|
1047
|
-
return await this.sspClient.getCoopExitFeeEstimate({
|
|
1048
|
-
leafExternalIds: leaves.map((leaf) => leaf.id),
|
|
1049
|
-
withdrawalAddress,
|
|
1050
|
-
});
|
|
1051
|
-
}
|
|
1052
|
-
// ***** Token Flow *****
|
|
1053
|
-
/**
|
|
1054
|
-
* Synchronizes token leaves for the wallet.
|
|
1055
|
-
*
|
|
1056
|
-
* @returns {Promise<void>}
|
|
1057
|
-
* @private
|
|
1058
|
-
*/
|
|
1059
|
-
async syncTokenLeaves() {
|
|
1060
|
-
this.tokenLeaves.clear();
|
|
1061
|
-
const trackedPublicKeys = await this.config.signer.getTrackedPublicKeys();
|
|
1062
|
-
const unsortedTokenLeaves = await this.tokenTransactionService.fetchOwnedTokenLeaves([...trackedPublicKeys, await this.config.signer.getIdentityPublicKey()], []);
|
|
1063
|
-
const filteredTokenLeaves = unsortedTokenLeaves.filter((leaf) => !this.pendingWithdrawnLeafIds.includes(leaf.leaf?.id || ""));
|
|
1064
|
-
const fetchedLeafIds = new Set(unsortedTokenLeaves.map((leaf) => leaf.leaf?.id).filter(Boolean));
|
|
1065
|
-
this.pendingWithdrawnLeafIds = this.pendingWithdrawnLeafIds.filter((id) => fetchedLeafIds.has(id));
|
|
1066
|
-
// Group leaves by token key
|
|
1067
|
-
const groupedLeaves = new Map();
|
|
1068
|
-
filteredTokenLeaves.forEach((leaf) => {
|
|
1069
|
-
const tokenKey = bytesToHex(leaf.leaf.tokenPublicKey);
|
|
1070
|
-
const index = leaf.previousTransactionVout;
|
|
1071
|
-
if (!groupedLeaves.has(tokenKey)) {
|
|
1072
|
-
groupedLeaves.set(tokenKey, []);
|
|
1073
|
-
}
|
|
1074
|
-
groupedLeaves.get(tokenKey).push({
|
|
1075
|
-
...leaf,
|
|
1076
|
-
previousTransactionVout: index,
|
|
1077
|
-
});
|
|
1078
|
-
});
|
|
1079
|
-
this.tokenLeaves = groupedLeaves;
|
|
1080
|
-
}
|
|
1081
|
-
/**
|
|
1082
|
-
* Gets all token balances.
|
|
1083
|
-
*
|
|
1084
|
-
* @returns {Promise<Map<string, { balance: bigint }>>} Map of token balances and leaf counts
|
|
1085
|
-
* @private
|
|
1086
|
-
*/
|
|
1087
|
-
async getAllTokenBalances() {
|
|
1088
|
-
await this.syncTokenLeaves();
|
|
1089
|
-
const balances = new Map();
|
|
1090
|
-
for (const [tokenPublicKey, leaves] of this.tokenLeaves.entries()) {
|
|
1091
|
-
balances.set(tokenPublicKey, {
|
|
1092
|
-
balance: calculateAvailableTokenAmount(leaves),
|
|
1093
|
-
});
|
|
1094
|
-
}
|
|
1095
|
-
return balances;
|
|
1096
|
-
}
|
|
1097
|
-
/**
|
|
1098
|
-
* Transfers tokens to another user.
|
|
1099
|
-
*
|
|
1100
|
-
* @param {Object} params - Parameters for the token transfer
|
|
1101
|
-
* @param {string} params.tokenPublicKey - The public key of the token to transfer
|
|
1102
|
-
* @param {bigint} params.tokenAmount - The amount of tokens to transfer
|
|
1103
|
-
* @param {string} params.receiverSparkAddress - The recipient's public key
|
|
1104
|
-
* @param {LeafWithPreviousTransactionData[]} [params.selectedLeaves] - Optional specific leaves to use for the transfer
|
|
1105
|
-
* @returns {Promise<string>} The transaction ID of the token transfer
|
|
1106
|
-
*/
|
|
1107
|
-
async transferTokens({ tokenPublicKey, tokenAmount, receiverSparkAddress, selectedLeaves, }) {
|
|
1108
|
-
await this.syncTokenLeaves();
|
|
1109
|
-
if (!this.tokenLeaves.has(tokenPublicKey)) {
|
|
1110
|
-
throw new Error("No token leaves with the given tokenPublicKey");
|
|
1111
|
-
}
|
|
1112
|
-
const tokenPublicKeyBytes = hexToBytes(tokenPublicKey);
|
|
1113
|
-
const receiverSparkAddressBytes = hexToBytes(receiverSparkAddress);
|
|
1114
|
-
if (selectedLeaves) {
|
|
1115
|
-
if (!checkIfSelectedLeavesAreAvailable(selectedLeaves, this.tokenLeaves, tokenPublicKeyBytes)) {
|
|
1116
|
-
throw new Error("One or more selected leaves are not available");
|
|
1117
|
-
}
|
|
1118
|
-
}
|
|
1119
|
-
else {
|
|
1120
|
-
selectedLeaves = this.selectTokenLeaves(tokenPublicKey, tokenAmount);
|
|
1121
|
-
}
|
|
1122
|
-
if (selectedLeaves.length > MAX_TOKEN_LEAVES) {
|
|
1123
|
-
throw new Error("Too many leaves selected");
|
|
1124
|
-
}
|
|
1125
|
-
const tokenTransaction = await this.tokenTransactionService.constructTransferTokenTransaction(selectedLeaves, receiverSparkAddressBytes, tokenPublicKeyBytes, tokenAmount);
|
|
1126
|
-
return await this.tokenTransactionService.broadcastTokenTransaction(tokenTransaction, selectedLeaves.map((leaf) => leaf.leaf.ownerPublicKey), selectedLeaves.map((leaf) => leaf.leaf.revocationPublicKey));
|
|
1127
|
-
}
|
|
1128
|
-
async getTokenTransactions(tokenPublicKeys, tokenTransactionHashes) {
|
|
1129
|
-
const sparkClient = await this.connectionManager.createSparkClient(this.config.getCoordinatorAddress());
|
|
1130
|
-
let queryParams;
|
|
1131
|
-
if (tokenTransactionHashes?.length) {
|
|
1132
|
-
queryParams = {
|
|
1133
|
-
tokenPublicKeys: tokenPublicKeys?.map(hexToBytes),
|
|
1134
|
-
ownerPublicKeys: [hexToBytes(await this.getIdentityPublicKey())],
|
|
1135
|
-
tokenTransactionHashes: tokenTransactionHashes.map(hexToBytes),
|
|
1136
|
-
};
|
|
1137
|
-
}
|
|
1138
|
-
else {
|
|
1139
|
-
queryParams = {
|
|
1140
|
-
tokenPublicKeys: tokenPublicKeys?.map(hexToBytes),
|
|
1141
|
-
ownerPublicKeys: [hexToBytes(await this.getIdentityPublicKey())],
|
|
1142
|
-
};
|
|
1143
|
-
}
|
|
1144
|
-
const response = await sparkClient.query_token_transactions(queryParams);
|
|
1145
|
-
return response.tokenTransactionsWithStatus;
|
|
1146
|
-
}
|
|
1147
|
-
getTokenL1Address() {
|
|
1148
|
-
if (!this.lrc20Wallet) {
|
|
1149
|
-
throw new Error("L1 Wallet not initialized");
|
|
1150
|
-
}
|
|
1151
|
-
return this.lrc20Wallet.p2wpkhAddress;
|
|
1152
|
-
}
|
|
1153
|
-
/**
|
|
1154
|
-
* Selects token leaves for a transfer.
|
|
1155
|
-
*
|
|
1156
|
-
* @param {string} tokenPublicKey - The public key of the token
|
|
1157
|
-
* @param {bigint} tokenAmount - The amount of tokens to select leaves for
|
|
1158
|
-
* @returns {LeafWithPreviousTransactionData[]} The selected leaves
|
|
1159
|
-
* @private
|
|
1160
|
-
*/
|
|
1161
|
-
selectTokenLeaves(tokenPublicKey, tokenAmount) {
|
|
1162
|
-
return this.tokenTransactionService.selectTokenLeaves(this.tokenLeaves.get(tokenPublicKey), tokenAmount);
|
|
1163
|
-
}
|
|
1164
|
-
/**
|
|
1165
|
-
* Withdraws tokens to an on-chain address.
|
|
1166
|
-
*
|
|
1167
|
-
* @param {string} tokenPublicKey - The public key of the token to withdraw
|
|
1168
|
-
* @param {bigint} [tokenAmount] - Optional amount of tokens to withdraw. If not specified, withdraws all tokens.
|
|
1169
|
-
* @returns {Promise<{ txid: string } | undefined>} The transaction ID of the withdrawal
|
|
1170
|
-
*/
|
|
1171
|
-
async withdrawTokens(tokenPublicKey, tokenAmount) {
|
|
1172
|
-
if (!this.lrc20Wallet) {
|
|
1173
|
-
throw new Error("LRC20 wallet not initialized");
|
|
1174
|
-
}
|
|
1175
|
-
await this.syncTokenLeaves();
|
|
1176
|
-
let tokenLeaves = this.tokenLeaves.get(tokenPublicKey);
|
|
1177
|
-
if (!tokenLeaves || tokenLeaves.length === 0) {
|
|
1178
|
-
throw new Error("No leaves to exit");
|
|
1179
|
-
}
|
|
1180
|
-
let leafToExit;
|
|
1181
|
-
const totalAvailable = calculateAvailableTokenAmount(tokenLeaves);
|
|
1182
|
-
// If tokenAmount is not provided, use the total available amount
|
|
1183
|
-
const amountToWithdraw = tokenAmount || totalAvailable;
|
|
1184
|
-
if (amountToWithdraw > totalAvailable) {
|
|
1185
|
-
throw new Error(`Insufficient tokens: have ${totalAvailable}, requested ${amountToWithdraw}`);
|
|
1186
|
-
}
|
|
1187
|
-
// Check if we have a leaf that exactly matches the token amount
|
|
1188
|
-
leafToExit = tokenLeaves.find(({ leaf }) => bytesToNumberBE(leaf.tokenAmount) === amountToWithdraw);
|
|
1189
|
-
// If we don't have an exact match, perform consolidation to create a leaf
|
|
1190
|
-
// that matches to the exact amount.
|
|
1191
|
-
if (!leafToExit) {
|
|
1192
|
-
// Get our own spark address for self-transfer
|
|
1193
|
-
const selfAddress = await this.getSparkAddress();
|
|
1194
|
-
// Transfer tokens to self to consolidate (which ensures we have a single leaf with tokenAmount)
|
|
1195
|
-
const txid = await this.transferTokens({
|
|
1196
|
-
tokenPublicKey,
|
|
1197
|
-
tokenAmount: amountToWithdraw,
|
|
1198
|
-
receiverSparkAddress: selfAddress,
|
|
1199
|
-
});
|
|
1200
|
-
// Wait for the consolidation transaction to be processed
|
|
1201
|
-
console.log(`Consolidating token leaves with transaction: ${txid}`);
|
|
1202
|
-
// Wait a moment and refresh token leaves
|
|
1203
|
-
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
1204
|
-
await this.syncTokenLeaves();
|
|
1205
|
-
// Get the updated leaves after consolidation
|
|
1206
|
-
const consolidatedLeaves = this.tokenLeaves.get(tokenPublicKey) || [];
|
|
1207
|
-
if (consolidatedLeaves.length === 0) {
|
|
1208
|
-
throw new Error("Failed to find leaves after consolidation");
|
|
1209
|
-
}
|
|
1210
|
-
// Find the leaf with the exact amount we requested
|
|
1211
|
-
leafToExit = consolidatedLeaves.find(({ leaf }) => bytesToNumberBE(leaf.tokenAmount) === amountToWithdraw);
|
|
1212
|
-
if (!leafToExit) {
|
|
1213
|
-
throw new Error("Failed to find consolidated leaf after transfer");
|
|
1214
|
-
}
|
|
1215
|
-
}
|
|
1216
|
-
try {
|
|
1217
|
-
// Mark this leaf as pending withdrawal to prevent double-spending.
|
|
1218
|
-
if (leafToExit.leaf?.id) {
|
|
1219
|
-
this.pendingWithdrawnLeafIds.push(leafToExit.leaf.id);
|
|
1220
|
-
}
|
|
1221
|
-
return await broadcastL1Withdrawal(this.lrc20Wallet, [leafToExit], await this.getIdentityPublicKey());
|
|
1222
|
-
}
|
|
1223
|
-
catch (err) {
|
|
1224
|
-
// Remove from pending if the withdrawal fails
|
|
1225
|
-
if (leafToExit.leaf?.id) {
|
|
1226
|
-
this.pendingWithdrawnLeafIds = this.pendingWithdrawnLeafIds.filter((id) => id !== leafToExit.leaf.id);
|
|
1227
|
-
}
|
|
1228
|
-
if (err.message === "Not enough UTXOs") {
|
|
1229
|
-
console.error("Error: No L1 UTXOs available to cover exit fees. Please send sats to the address associated with your Wallet:", this.lrc20Wallet.p2wpkhAddress);
|
|
1230
|
-
}
|
|
1231
|
-
else {
|
|
1232
|
-
console.error("Unexpected error:", err);
|
|
1233
|
-
}
|
|
1234
|
-
return;
|
|
1235
|
-
}
|
|
1236
|
-
}
|
|
1237
|
-
/**
|
|
1238
|
-
* Signs a message with the identity key.
|
|
1239
|
-
*
|
|
1240
|
-
* @param {string} message - Unhashed message to sign
|
|
1241
|
-
* @param {boolean} [compact] - Whether to use compact encoding. If false, the message will be encoded as DER.
|
|
1242
|
-
* @returns {Promise<string>} The signed message
|
|
1243
|
-
*/
|
|
1244
|
-
async signMessage(message, compact) {
|
|
1245
|
-
const hash = sha256(message);
|
|
1246
|
-
return bytesToHex(await this.config.signer.signMessageWithIdentityKey(hash, compact));
|
|
1247
|
-
}
|
|
1248
|
-
/**
|
|
1249
|
-
* Get a Lightning receive request by ID.
|
|
1250
|
-
*
|
|
1251
|
-
* @param {string} id - The ID of the Lightning receive request
|
|
1252
|
-
* @returns {Promise<LightningReceiveRequest | null>} The Lightning receive request
|
|
1253
|
-
*/
|
|
1254
|
-
async getLightningReceiveRequest(id) {
|
|
1255
|
-
if (!this.sspClient) {
|
|
1256
|
-
throw new Error("SSP client not initialized");
|
|
1257
|
-
}
|
|
1258
|
-
return await this.sspClient.getLightningReceiveRequest(id);
|
|
1259
|
-
}
|
|
1260
|
-
/**
|
|
1261
|
-
* Get a Lightning send request by ID.
|
|
1262
|
-
*
|
|
1263
|
-
* @param {string} id - The ID of the Lightning send request
|
|
1264
|
-
* @returns {Promise<LightningSendRequest | null>} The Lightning send request
|
|
1265
|
-
*/
|
|
1266
|
-
async getLightningSendRequest(id) {
|
|
1267
|
-
if (!this.sspClient) {
|
|
1268
|
-
throw new Error("SSP client not initialized");
|
|
1269
|
-
}
|
|
1270
|
-
return await this.sspClient.getLightningSendRequest(id);
|
|
1271
|
-
}
|
|
1272
|
-
/**
|
|
1273
|
-
* Get a coop exit request by ID.
|
|
1274
|
-
*
|
|
1275
|
-
* @param {string} id - The ID of the coop exit request
|
|
1276
|
-
* @returns {Promise<CoopExitRequest | null>} The coop exit request
|
|
1277
|
-
*/
|
|
1278
|
-
async getCoopExitRequest(id) {
|
|
1279
|
-
if (!this.sspClient) {
|
|
1280
|
-
throw new Error("SSP client not initialized");
|
|
1281
|
-
}
|
|
1282
|
-
return await this.sspClient.getCoopExitRequest(id);
|
|
1283
|
-
}
|
|
1284
|
-
}
|
|
1285
|
-
//# sourceMappingURL=spark-sdk.js.map
|