From d21109b3f42bdee33f1c8e3ecf274ca04735f8f5 Mon Sep 17 00:00:00 2001 From: solidsnakedev Date: Thu, 15 Jan 2026 10:41:51 -0700 Subject: [PATCH 1/4] feat(evolution): add sendAll() API for draining wallet assets --- .changeset/nine-frogs-argue.md | 19 ++++ .../docs/modules/SingleHostAddr.ts.md | 2 +- .../docs/modules/SingleHostName.ts.md | 2 +- .../docs/modules/StakeReference.ts.md | 2 +- packages/evolution/docs/modules/TSchema.ts.md | 2 +- packages/evolution/docs/modules/Text.ts.md | 2 +- packages/evolution/docs/modules/Text128.ts.md | 2 +- .../evolution/docs/modules/Time/Slot.ts.md | 2 +- .../docs/modules/Time/SlotConfig.ts.md | 2 +- .../docs/modules/Time/UnixTime.ts.md | 2 +- .../evolution/docs/modules/Transaction.ts.md | 2 +- .../docs/modules/TransactionBody.ts.md | 2 +- .../docs/modules/TransactionHash.ts.md | 2 +- .../docs/modules/TransactionIndex.ts.md | 2 +- .../docs/modules/TransactionInput.ts.md | 2 +- .../docs/modules/TransactionMetadatum.ts.md | 2 +- .../modules/TransactionMetadatumLabels.ts.md | 2 +- .../docs/modules/TransactionOutput.ts.md | 2 +- .../docs/modules/TransactionWitnessSet.ts.md | 2 +- packages/evolution/docs/modules/TxOut.ts.md | 2 +- packages/evolution/docs/modules/UTxO.ts.md | 2 +- .../evolution/docs/modules/UnitInterval.ts.md | 2 +- packages/evolution/docs/modules/Url.ts.md | 2 +- packages/evolution/docs/modules/VKey.ts.md | 2 +- packages/evolution/docs/modules/Value.ts.md | 2 +- .../docs/modules/VotingProcedures.ts.md | 2 +- packages/evolution/docs/modules/VrfCert.ts.md | 2 +- .../evolution/docs/modules/VrfKeyHash.ts.md | 2 +- packages/evolution/docs/modules/VrfVkey.ts.md | 2 +- .../evolution/docs/modules/Withdrawals.ts.md | 2 +- .../docs/modules/sdk/EvalRedeemer.ts.md | 2 +- .../evolution/docs/modules/sdk/Type.ts.md | 2 +- .../sdk/builders/RedeemerBuilder.ts.md | 2 +- .../modules/sdk/builders/SignBuilder.ts.md | 2 +- .../sdk/builders/SignBuilderImpl.ts.md | 2 +- .../modules/sdk/builders/SubmitBuilder.ts.md | 2 +- .../sdk/builders/SubmitBuilderImpl.ts.md | 2 +- .../sdk/builders/TransactionBuilder.ts.md | 36 +++++- .../sdk/builders/TransactionResult.ts.md | 2 +- .../modules/sdk/builders/TxBuilderImpl.ts.md | 2 +- .../docs/modules/sdk/builders/Unfrack.ts.md | 2 +- .../sdk/builders/operations/Operations.ts.md | 26 +++++ .../sdk/builders/operations/SendAll.ts.md | 61 +++++++++++ .../sdk/builders/operations/Stake.ts.md | 2 +- .../sdk/builders/operations/Validity.ts.md | 2 +- .../sdk/builders/operations/Vote.ts.md | 2 +- .../modules/sdk/builders/phases/Balance.ts.md | 2 +- .../sdk/builders/phases/ChangeCreation.ts.md | 2 +- .../sdk/builders/phases/Collateral.ts.md | 2 +- .../sdk/builders/phases/Evaluation.ts.md | 2 +- .../sdk/builders/phases/Fallback.ts.md | 2 +- .../sdk/builders/phases/FeeCalculation.ts.md | 2 +- .../modules/sdk/builders/phases/Phases.ts.md | 2 +- .../sdk/builders/phases/Selection.ts.md | 2 +- .../modules/sdk/builders/phases/utils.ts.md | 2 +- .../docs/modules/sdk/client/Client.ts.md | 2 +- .../docs/modules/sdk/client/ClientImpl.ts.md | 2 +- .../modules/sdk/provider/Blockfrost.ts.md | 2 +- .../docs/modules/sdk/provider/Koios.ts.md | 2 +- .../docs/modules/sdk/provider/Kupmios.ts.md | 2 +- .../docs/modules/sdk/provider/Maestro.ts.md | 2 +- .../docs/modules/sdk/provider/Provider.ts.md | 2 +- .../docs/modules/sdk/wallet/Derivation.ts.md | 2 +- .../docs/modules/sdk/wallet/WalletNew.ts.md | 2 +- .../evolution/docs/modules/uplc/UPLC.ts.md | 2 +- .../docs/modules/utils/FeeValidation.ts.md | 2 +- .../evolution/docs/modules/utils/Hash.ts.md | 2 +- .../docs/modules/utils/effect-runtime.ts.md | 2 +- .../src/sdk/builders/TransactionBuilder.ts | 43 ++++++++ .../src/sdk/builders/operations/Operations.ts | 21 ++++ .../src/sdk/builders/operations/SendAll.ts | 48 ++++++++ .../src/sdk/builders/operations/index.ts | 1 + .../src/sdk/builders/phases/ChangeCreation.ts | 50 +++++++++ .../src/sdk/builders/phases/Selection.ts | 103 ++++++++++++++++++ 74 files changed, 471 insertions(+), 65 deletions(-) create mode 100644 .changeset/nine-frogs-argue.md create mode 100644 packages/evolution/docs/modules/sdk/builders/operations/SendAll.ts.md create mode 100644 packages/evolution/src/sdk/builders/operations/SendAll.ts diff --git a/.changeset/nine-frogs-argue.md b/.changeset/nine-frogs-argue.md new file mode 100644 index 00000000..ec0515b4 --- /dev/null +++ b/.changeset/nine-frogs-argue.md @@ -0,0 +1,19 @@ +--- +"@evolution-sdk/evolution": minor +--- + +Add `sendAll()` API to TxBuilder for draining wallet assets to a single address. + +This new method simplifies the common use case of transferring all wallet assets: +- Automatically selects all wallet UTxOs as inputs +- Creates a single output with all assets minus the transaction fee +- Properly calculates minUTxO for the destination output +- Validates incompatibility with other operations (payToAddress, collectFrom, mint, staking, governance) + +Usage: +```typescript +const tx = await client + .newTx() + .sendAll({ to: recipientAddress }) + .build() +``` diff --git a/packages/evolution/docs/modules/SingleHostAddr.ts.md b/packages/evolution/docs/modules/SingleHostAddr.ts.md index 0ac1938f..e848b9cb 100644 --- a/packages/evolution/docs/modules/SingleHostAddr.ts.md +++ b/packages/evolution/docs/modules/SingleHostAddr.ts.md @@ -1,6 +1,6 @@ --- title: SingleHostAddr.ts -nav_order: 163 +nav_order: 164 parent: Modules --- diff --git a/packages/evolution/docs/modules/SingleHostName.ts.md b/packages/evolution/docs/modules/SingleHostName.ts.md index 0a1f83c8..cd06e214 100644 --- a/packages/evolution/docs/modules/SingleHostName.ts.md +++ b/packages/evolution/docs/modules/SingleHostName.ts.md @@ -1,6 +1,6 @@ --- title: SingleHostName.ts -nav_order: 164 +nav_order: 165 parent: Modules --- diff --git a/packages/evolution/docs/modules/StakeReference.ts.md b/packages/evolution/docs/modules/StakeReference.ts.md index 633455b2..326e77dd 100644 --- a/packages/evolution/docs/modules/StakeReference.ts.md +++ b/packages/evolution/docs/modules/StakeReference.ts.md @@ -1,6 +1,6 @@ --- title: StakeReference.ts -nav_order: 165 +nav_order: 166 parent: Modules --- diff --git a/packages/evolution/docs/modules/TSchema.ts.md b/packages/evolution/docs/modules/TSchema.ts.md index 7d39da47..57c6da05 100644 --- a/packages/evolution/docs/modules/TSchema.ts.md +++ b/packages/evolution/docs/modules/TSchema.ts.md @@ -1,6 +1,6 @@ --- title: TSchema.ts -nav_order: 180 +nav_order: 181 parent: Modules --- diff --git a/packages/evolution/docs/modules/Text.ts.md b/packages/evolution/docs/modules/Text.ts.md index 03dbed01..56f72a81 100644 --- a/packages/evolution/docs/modules/Text.ts.md +++ b/packages/evolution/docs/modules/Text.ts.md @@ -1,6 +1,6 @@ --- title: Text.ts -nav_order: 166 +nav_order: 167 parent: Modules --- diff --git a/packages/evolution/docs/modules/Text128.ts.md b/packages/evolution/docs/modules/Text128.ts.md index ebfc838c..74376949 100644 --- a/packages/evolution/docs/modules/Text128.ts.md +++ b/packages/evolution/docs/modules/Text128.ts.md @@ -1,6 +1,6 @@ --- title: Text128.ts -nav_order: 167 +nav_order: 168 parent: Modules --- diff --git a/packages/evolution/docs/modules/Time/Slot.ts.md b/packages/evolution/docs/modules/Time/Slot.ts.md index 23e3e3f0..7907f5ae 100644 --- a/packages/evolution/docs/modules/Time/Slot.ts.md +++ b/packages/evolution/docs/modules/Time/Slot.ts.md @@ -1,6 +1,6 @@ --- title: Time/Slot.ts -nav_order: 168 +nav_order: 169 parent: Modules --- diff --git a/packages/evolution/docs/modules/Time/SlotConfig.ts.md b/packages/evolution/docs/modules/Time/SlotConfig.ts.md index afcbc402..06a63609 100644 --- a/packages/evolution/docs/modules/Time/SlotConfig.ts.md +++ b/packages/evolution/docs/modules/Time/SlotConfig.ts.md @@ -1,6 +1,6 @@ --- title: Time/SlotConfig.ts -nav_order: 169 +nav_order: 170 parent: Modules --- diff --git a/packages/evolution/docs/modules/Time/UnixTime.ts.md b/packages/evolution/docs/modules/Time/UnixTime.ts.md index 7586b75c..6e6c90ae 100644 --- a/packages/evolution/docs/modules/Time/UnixTime.ts.md +++ b/packages/evolution/docs/modules/Time/UnixTime.ts.md @@ -1,6 +1,6 @@ --- title: Time/UnixTime.ts -nav_order: 170 +nav_order: 171 parent: Modules --- diff --git a/packages/evolution/docs/modules/Transaction.ts.md b/packages/evolution/docs/modules/Transaction.ts.md index f6e4da59..796ad00b 100644 --- a/packages/evolution/docs/modules/Transaction.ts.md +++ b/packages/evolution/docs/modules/Transaction.ts.md @@ -1,6 +1,6 @@ --- title: Transaction.ts -nav_order: 171 +nav_order: 172 parent: Modules --- diff --git a/packages/evolution/docs/modules/TransactionBody.ts.md b/packages/evolution/docs/modules/TransactionBody.ts.md index 5ef5f3b2..4b6fa74d 100644 --- a/packages/evolution/docs/modules/TransactionBody.ts.md +++ b/packages/evolution/docs/modules/TransactionBody.ts.md @@ -1,6 +1,6 @@ --- title: TransactionBody.ts -nav_order: 172 +nav_order: 173 parent: Modules --- diff --git a/packages/evolution/docs/modules/TransactionHash.ts.md b/packages/evolution/docs/modules/TransactionHash.ts.md index 1eb99833..5b6fae4f 100644 --- a/packages/evolution/docs/modules/TransactionHash.ts.md +++ b/packages/evolution/docs/modules/TransactionHash.ts.md @@ -1,6 +1,6 @@ --- title: TransactionHash.ts -nav_order: 173 +nav_order: 174 parent: Modules --- diff --git a/packages/evolution/docs/modules/TransactionIndex.ts.md b/packages/evolution/docs/modules/TransactionIndex.ts.md index 51f19c8e..ebb07f33 100644 --- a/packages/evolution/docs/modules/TransactionIndex.ts.md +++ b/packages/evolution/docs/modules/TransactionIndex.ts.md @@ -1,6 +1,6 @@ --- title: TransactionIndex.ts -nav_order: 174 +nav_order: 175 parent: Modules --- diff --git a/packages/evolution/docs/modules/TransactionInput.ts.md b/packages/evolution/docs/modules/TransactionInput.ts.md index ef03efa7..f24adb53 100644 --- a/packages/evolution/docs/modules/TransactionInput.ts.md +++ b/packages/evolution/docs/modules/TransactionInput.ts.md @@ -1,6 +1,6 @@ --- title: TransactionInput.ts -nav_order: 175 +nav_order: 176 parent: Modules --- diff --git a/packages/evolution/docs/modules/TransactionMetadatum.ts.md b/packages/evolution/docs/modules/TransactionMetadatum.ts.md index daa21b67..a9a0a8ce 100644 --- a/packages/evolution/docs/modules/TransactionMetadatum.ts.md +++ b/packages/evolution/docs/modules/TransactionMetadatum.ts.md @@ -1,6 +1,6 @@ --- title: TransactionMetadatum.ts -nav_order: 176 +nav_order: 177 parent: Modules --- diff --git a/packages/evolution/docs/modules/TransactionMetadatumLabels.ts.md b/packages/evolution/docs/modules/TransactionMetadatumLabels.ts.md index ffa6a675..1c6a8d44 100644 --- a/packages/evolution/docs/modules/TransactionMetadatumLabels.ts.md +++ b/packages/evolution/docs/modules/TransactionMetadatumLabels.ts.md @@ -1,6 +1,6 @@ --- title: TransactionMetadatumLabels.ts -nav_order: 177 +nav_order: 178 parent: Modules --- diff --git a/packages/evolution/docs/modules/TransactionOutput.ts.md b/packages/evolution/docs/modules/TransactionOutput.ts.md index 88d44a39..fe35b6b3 100644 --- a/packages/evolution/docs/modules/TransactionOutput.ts.md +++ b/packages/evolution/docs/modules/TransactionOutput.ts.md @@ -1,6 +1,6 @@ --- title: TransactionOutput.ts -nav_order: 178 +nav_order: 179 parent: Modules --- diff --git a/packages/evolution/docs/modules/TransactionWitnessSet.ts.md b/packages/evolution/docs/modules/TransactionWitnessSet.ts.md index 566fcdc8..c2638d29 100644 --- a/packages/evolution/docs/modules/TransactionWitnessSet.ts.md +++ b/packages/evolution/docs/modules/TransactionWitnessSet.ts.md @@ -1,6 +1,6 @@ --- title: TransactionWitnessSet.ts -nav_order: 179 +nav_order: 180 parent: Modules --- diff --git a/packages/evolution/docs/modules/TxOut.ts.md b/packages/evolution/docs/modules/TxOut.ts.md index 2f3d62db..a9555688 100644 --- a/packages/evolution/docs/modules/TxOut.ts.md +++ b/packages/evolution/docs/modules/TxOut.ts.md @@ -1,6 +1,6 @@ --- title: TxOut.ts -nav_order: 181 +nav_order: 182 parent: Modules --- diff --git a/packages/evolution/docs/modules/UTxO.ts.md b/packages/evolution/docs/modules/UTxO.ts.md index 771e0d0c..1bdb7fb2 100644 --- a/packages/evolution/docs/modules/UTxO.ts.md +++ b/packages/evolution/docs/modules/UTxO.ts.md @@ -1,6 +1,6 @@ --- title: UTxO.ts -nav_order: 188 +nav_order: 189 parent: Modules --- diff --git a/packages/evolution/docs/modules/UnitInterval.ts.md b/packages/evolution/docs/modules/UnitInterval.ts.md index 68dc412f..9807a38f 100644 --- a/packages/evolution/docs/modules/UnitInterval.ts.md +++ b/packages/evolution/docs/modules/UnitInterval.ts.md @@ -1,6 +1,6 @@ --- title: UnitInterval.ts -nav_order: 182 +nav_order: 183 parent: Modules --- diff --git a/packages/evolution/docs/modules/Url.ts.md b/packages/evolution/docs/modules/Url.ts.md index c8b7ab22..7444b869 100644 --- a/packages/evolution/docs/modules/Url.ts.md +++ b/packages/evolution/docs/modules/Url.ts.md @@ -1,6 +1,6 @@ --- title: Url.ts -nav_order: 184 +nav_order: 185 parent: Modules --- diff --git a/packages/evolution/docs/modules/VKey.ts.md b/packages/evolution/docs/modules/VKey.ts.md index 2bb622f1..2d75ccfd 100644 --- a/packages/evolution/docs/modules/VKey.ts.md +++ b/packages/evolution/docs/modules/VKey.ts.md @@ -1,6 +1,6 @@ --- title: VKey.ts -nav_order: 190 +nav_order: 191 parent: Modules --- diff --git a/packages/evolution/docs/modules/Value.ts.md b/packages/evolution/docs/modules/Value.ts.md index d7886385..5c98cdd3 100644 --- a/packages/evolution/docs/modules/Value.ts.md +++ b/packages/evolution/docs/modules/Value.ts.md @@ -1,6 +1,6 @@ --- title: Value.ts -nav_order: 189 +nav_order: 190 parent: Modules --- diff --git a/packages/evolution/docs/modules/VotingProcedures.ts.md b/packages/evolution/docs/modules/VotingProcedures.ts.md index 2130d1b9..a3c11947 100644 --- a/packages/evolution/docs/modules/VotingProcedures.ts.md +++ b/packages/evolution/docs/modules/VotingProcedures.ts.md @@ -1,6 +1,6 @@ --- title: VotingProcedures.ts -nav_order: 191 +nav_order: 192 parent: Modules --- diff --git a/packages/evolution/docs/modules/VrfCert.ts.md b/packages/evolution/docs/modules/VrfCert.ts.md index ac6d7351..cf20cebe 100644 --- a/packages/evolution/docs/modules/VrfCert.ts.md +++ b/packages/evolution/docs/modules/VrfCert.ts.md @@ -1,6 +1,6 @@ --- title: VrfCert.ts -nav_order: 192 +nav_order: 193 parent: Modules --- diff --git a/packages/evolution/docs/modules/VrfKeyHash.ts.md b/packages/evolution/docs/modules/VrfKeyHash.ts.md index af94e807..ecdc77ea 100644 --- a/packages/evolution/docs/modules/VrfKeyHash.ts.md +++ b/packages/evolution/docs/modules/VrfKeyHash.ts.md @@ -1,6 +1,6 @@ --- title: VrfKeyHash.ts -nav_order: 193 +nav_order: 194 parent: Modules --- diff --git a/packages/evolution/docs/modules/VrfVkey.ts.md b/packages/evolution/docs/modules/VrfVkey.ts.md index 4e041555..eeb552e9 100644 --- a/packages/evolution/docs/modules/VrfVkey.ts.md +++ b/packages/evolution/docs/modules/VrfVkey.ts.md @@ -1,6 +1,6 @@ --- title: VrfVkey.ts -nav_order: 194 +nav_order: 195 parent: Modules --- diff --git a/packages/evolution/docs/modules/Withdrawals.ts.md b/packages/evolution/docs/modules/Withdrawals.ts.md index d81f2c51..bad6dd36 100644 --- a/packages/evolution/docs/modules/Withdrawals.ts.md +++ b/packages/evolution/docs/modules/Withdrawals.ts.md @@ -1,6 +1,6 @@ --- title: Withdrawals.ts -nav_order: 195 +nav_order: 196 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/EvalRedeemer.ts.md b/packages/evolution/docs/modules/sdk/EvalRedeemer.ts.md index 64ad62ef..ca5821d1 100644 --- a/packages/evolution/docs/modules/sdk/EvalRedeemer.ts.md +++ b/packages/evolution/docs/modules/sdk/EvalRedeemer.ts.md @@ -1,6 +1,6 @@ --- title: sdk/EvalRedeemer.ts -nav_order: 154 +nav_order: 155 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/Type.ts.md b/packages/evolution/docs/modules/sdk/Type.ts.md index 341ce317..48b5de33 100644 --- a/packages/evolution/docs/modules/sdk/Type.ts.md +++ b/packages/evolution/docs/modules/sdk/Type.ts.md @@ -1,6 +1,6 @@ --- title: sdk/Type.ts -nav_order: 160 +nav_order: 161 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/builders/RedeemerBuilder.ts.md b/packages/evolution/docs/modules/sdk/builders/RedeemerBuilder.ts.md index 7634c19c..bd1137f0 100644 --- a/packages/evolution/docs/modules/sdk/builders/RedeemerBuilder.ts.md +++ b/packages/evolution/docs/modules/sdk/builders/RedeemerBuilder.ts.md @@ -1,6 +1,6 @@ --- title: sdk/builders/RedeemerBuilder.ts -nav_order: 143 +nav_order: 144 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/builders/SignBuilder.ts.md b/packages/evolution/docs/modules/sdk/builders/SignBuilder.ts.md index 20a75ab3..66083bb9 100644 --- a/packages/evolution/docs/modules/sdk/builders/SignBuilder.ts.md +++ b/packages/evolution/docs/modules/sdk/builders/SignBuilder.ts.md @@ -1,6 +1,6 @@ --- title: sdk/builders/SignBuilder.ts -nav_order: 144 +nav_order: 145 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/builders/SignBuilderImpl.ts.md b/packages/evolution/docs/modules/sdk/builders/SignBuilderImpl.ts.md index e5038e3a..a56275fb 100644 --- a/packages/evolution/docs/modules/sdk/builders/SignBuilderImpl.ts.md +++ b/packages/evolution/docs/modules/sdk/builders/SignBuilderImpl.ts.md @@ -1,6 +1,6 @@ --- title: sdk/builders/SignBuilderImpl.ts -nav_order: 145 +nav_order: 146 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/builders/SubmitBuilder.ts.md b/packages/evolution/docs/modules/sdk/builders/SubmitBuilder.ts.md index d65e8727..f7479644 100644 --- a/packages/evolution/docs/modules/sdk/builders/SubmitBuilder.ts.md +++ b/packages/evolution/docs/modules/sdk/builders/SubmitBuilder.ts.md @@ -1,6 +1,6 @@ --- title: sdk/builders/SubmitBuilder.ts -nav_order: 146 +nav_order: 147 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/builders/SubmitBuilderImpl.ts.md b/packages/evolution/docs/modules/sdk/builders/SubmitBuilderImpl.ts.md index 7a72fa6e..a7cac2b3 100644 --- a/packages/evolution/docs/modules/sdk/builders/SubmitBuilderImpl.ts.md +++ b/packages/evolution/docs/modules/sdk/builders/SubmitBuilderImpl.ts.md @@ -1,6 +1,6 @@ --- title: sdk/builders/SubmitBuilderImpl.ts -nav_order: 147 +nav_order: 148 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/builders/TransactionBuilder.ts.md b/packages/evolution/docs/modules/sdk/builders/TransactionBuilder.ts.md index a78cfa46..7e86d0c2 100644 --- a/packages/evolution/docs/modules/sdk/builders/TransactionBuilder.ts.md +++ b/packages/evolution/docs/modules/sdk/builders/TransactionBuilder.ts.md @@ -1,6 +1,6 @@ --- title: sdk/builders/TransactionBuilder.ts -nav_order: 148 +nav_order: 149 parent: Modules --- @@ -256,6 +256,39 @@ export interface TransactionBuilderBase { */ readonly collectFrom: (params: CollectFromParams) => this + /** + * Send all wallet assets to a recipient address. + * + * This operation collects all wallet UTxOs and creates a single output + * containing all assets minus the transaction fee. No change output is created. + * + * Use cases: + * - Draining a wallet completely + * - Consolidating all UTxOs into a single output + * - Migrating funds to a new address + * + * **Important**: This operation is mutually exclusive with `payToAddress` and `collectFrom`. + * When `sendAll` is used, all wallet UTxOs are automatically collected and the output + * is automatically created. Any existing outputs or inputs will cause an error. + * + * Queues a deferred operation that will be executed when build() is called. + * Returns the same builder for method chaining. + * + * @example + * ```typescript + * import { Address } from "@evolution-sdk/evolution" + * + * const tx = await client + * .newTx() + * .sendAll({ to: Address.fromBech32("addr1...") }) + * .build() + * ``` + * + * @since 2.0.0 + * @category builder-methods + */ + readonly sendAll: (params: SendAllParams) => this + /** * Attach a script to the transaction. * @@ -1439,6 +1472,7 @@ export interface TxBuilderState { } readonly requiredSigners: ReadonlyArray // Extra signers required (for script validation) readonly auxiliaryData?: AuxiliaryData.AuxiliaryData // Auxiliary data (metadata, scripts, etc.) + readonly sendAllTo?: CoreAddress.Address // Target address for sendAll operation } ``` diff --git a/packages/evolution/docs/modules/sdk/builders/TransactionResult.ts.md b/packages/evolution/docs/modules/sdk/builders/TransactionResult.ts.md index 725985bc..142047bc 100644 --- a/packages/evolution/docs/modules/sdk/builders/TransactionResult.ts.md +++ b/packages/evolution/docs/modules/sdk/builders/TransactionResult.ts.md @@ -1,6 +1,6 @@ --- title: sdk/builders/TransactionResult.ts -nav_order: 149 +nav_order: 150 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/builders/TxBuilderImpl.ts.md b/packages/evolution/docs/modules/sdk/builders/TxBuilderImpl.ts.md index e768027d..fb500d0c 100644 --- a/packages/evolution/docs/modules/sdk/builders/TxBuilderImpl.ts.md +++ b/packages/evolution/docs/modules/sdk/builders/TxBuilderImpl.ts.md @@ -1,6 +1,6 @@ --- title: sdk/builders/TxBuilderImpl.ts -nav_order: 150 +nav_order: 151 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/builders/Unfrack.ts.md b/packages/evolution/docs/modules/sdk/builders/Unfrack.ts.md index ce9a37e5..7fc3b8a9 100644 --- a/packages/evolution/docs/modules/sdk/builders/Unfrack.ts.md +++ b/packages/evolution/docs/modules/sdk/builders/Unfrack.ts.md @@ -1,6 +1,6 @@ --- title: sdk/builders/Unfrack.ts -nav_order: 151 +nav_order: 152 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/builders/operations/Operations.ts.md b/packages/evolution/docs/modules/sdk/builders/operations/Operations.ts.md index 7df5bb76..6da1c98b 100644 --- a/packages/evolution/docs/modules/sdk/builders/operations/Operations.ts.md +++ b/packages/evolution/docs/modules/sdk/builders/operations/Operations.ts.md @@ -20,6 +20,8 @@ parent: Modules - [VoteParams (interface)](#voteparams-interface) - [metadata](#metadata) - [AttachMetadataParams (interface)](#attachmetadataparams-interface) +- [payment](#payment) + - [SendAllParams (interface)](#sendallparams-interface) - [pool](#pool) - [RegisterPoolParams (interface)](#registerpoolparams-interface) - [RetirePoolParams (interface)](#retirepoolparams-interface) @@ -238,6 +240,30 @@ export interface AttachMetadataParams { Added in v2.0.0 +# payment + +## SendAllParams (interface) + +Parameters for sending all wallet assets to a recipient address. + +This operation collects all wallet UTxOs and creates a single output +containing all assets minus the transaction fee. It's commonly used for: + +- Draining a wallet completely +- Consolidating all UTxOs into a single output +- Migrating funds to a new address + +**Signature** + +```ts +export interface SendAllParams { + /** The recipient address to receive all assets */ + readonly to: CoreAddress.Address +} +``` + +Added in v2.0.0 + # pool ## RegisterPoolParams (interface) diff --git a/packages/evolution/docs/modules/sdk/builders/operations/SendAll.ts.md b/packages/evolution/docs/modules/sdk/builders/operations/SendAll.ts.md new file mode 100644 index 00000000..b80224a7 --- /dev/null +++ b/packages/evolution/docs/modules/sdk/builders/operations/SendAll.ts.md @@ -0,0 +1,61 @@ +--- +title: sdk/builders/operations/SendAll.ts +nav_order: 131 +parent: Modules +--- + +## SendAll overview + +SendAll operation - sends all wallet assets to a recipient address. + +This operation marks the transaction as a "send all" transaction, +which triggers special handling in the build phases: + +1. All wallet UTxOs are collected as inputs +2. A single output is created with all assets minus fee +3. No change output is created (everything goes to recipient) + +Added in v2.0.0 + +--- + +

Table of contents

+ +- [programs](#programs) + - [createSendAllProgram](#createsendallprogram) +- [types](#types) + - [SendAllTarget (type alias)](#sendalltarget-type-alias) + +--- + +# programs + +## createSendAllProgram + +Creates a ProgramStep for sendAll operation. + +This sets up the sendAll mode in the builder state, which is processed +during the build phases. The actual UTxO collection and output creation +happens during the build process when wallet UTxOs are available. + +**Signature** + +```ts +export declare const createSendAllProgram: (params: SendAllParams) => Effect.Effect +``` + +Added in v2.0.0 + +# types + +## SendAllTarget (type alias) + +Type representing the sendAll target address in builder state. + +**Signature** + +```ts +export type SendAllTarget = CoreAddress.Address +``` + +Added in v2.0.0 diff --git a/packages/evolution/docs/modules/sdk/builders/operations/Stake.ts.md b/packages/evolution/docs/modules/sdk/builders/operations/Stake.ts.md index 0f321370..7b30d15f 100644 --- a/packages/evolution/docs/modules/sdk/builders/operations/Stake.ts.md +++ b/packages/evolution/docs/modules/sdk/builders/operations/Stake.ts.md @@ -1,6 +1,6 @@ --- title: sdk/builders/operations/Stake.ts -nav_order: 131 +nav_order: 132 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/builders/operations/Validity.ts.md b/packages/evolution/docs/modules/sdk/builders/operations/Validity.ts.md index eab23593..6f7e4cff 100644 --- a/packages/evolution/docs/modules/sdk/builders/operations/Validity.ts.md +++ b/packages/evolution/docs/modules/sdk/builders/operations/Validity.ts.md @@ -1,6 +1,6 @@ --- title: sdk/builders/operations/Validity.ts -nav_order: 132 +nav_order: 133 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/builders/operations/Vote.ts.md b/packages/evolution/docs/modules/sdk/builders/operations/Vote.ts.md index 0072444e..1b211873 100644 --- a/packages/evolution/docs/modules/sdk/builders/operations/Vote.ts.md +++ b/packages/evolution/docs/modules/sdk/builders/operations/Vote.ts.md @@ -1,6 +1,6 @@ --- title: sdk/builders/operations/Vote.ts -nav_order: 133 +nav_order: 134 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/builders/phases/Balance.ts.md b/packages/evolution/docs/modules/sdk/builders/phases/Balance.ts.md index 1ba66089..b71cbade 100644 --- a/packages/evolution/docs/modules/sdk/builders/phases/Balance.ts.md +++ b/packages/evolution/docs/modules/sdk/builders/phases/Balance.ts.md @@ -1,6 +1,6 @@ --- title: sdk/builders/phases/Balance.ts -nav_order: 134 +nav_order: 135 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/builders/phases/ChangeCreation.ts.md b/packages/evolution/docs/modules/sdk/builders/phases/ChangeCreation.ts.md index aa9ba558..5e9efb07 100644 --- a/packages/evolution/docs/modules/sdk/builders/phases/ChangeCreation.ts.md +++ b/packages/evolution/docs/modules/sdk/builders/phases/ChangeCreation.ts.md @@ -1,6 +1,6 @@ --- title: sdk/builders/phases/ChangeCreation.ts -nav_order: 135 +nav_order: 136 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/builders/phases/Collateral.ts.md b/packages/evolution/docs/modules/sdk/builders/phases/Collateral.ts.md index 5c8dea67..fee962f2 100644 --- a/packages/evolution/docs/modules/sdk/builders/phases/Collateral.ts.md +++ b/packages/evolution/docs/modules/sdk/builders/phases/Collateral.ts.md @@ -1,6 +1,6 @@ --- title: sdk/builders/phases/Collateral.ts -nav_order: 136 +nav_order: 137 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/builders/phases/Evaluation.ts.md b/packages/evolution/docs/modules/sdk/builders/phases/Evaluation.ts.md index f6dee331..88054055 100644 --- a/packages/evolution/docs/modules/sdk/builders/phases/Evaluation.ts.md +++ b/packages/evolution/docs/modules/sdk/builders/phases/Evaluation.ts.md @@ -1,6 +1,6 @@ --- title: sdk/builders/phases/Evaluation.ts -nav_order: 137 +nav_order: 138 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/builders/phases/Fallback.ts.md b/packages/evolution/docs/modules/sdk/builders/phases/Fallback.ts.md index 3a369852..e0f9ca71 100644 --- a/packages/evolution/docs/modules/sdk/builders/phases/Fallback.ts.md +++ b/packages/evolution/docs/modules/sdk/builders/phases/Fallback.ts.md @@ -1,6 +1,6 @@ --- title: sdk/builders/phases/Fallback.ts -nav_order: 138 +nav_order: 139 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/builders/phases/FeeCalculation.ts.md b/packages/evolution/docs/modules/sdk/builders/phases/FeeCalculation.ts.md index a5433a33..cc1f1e71 100644 --- a/packages/evolution/docs/modules/sdk/builders/phases/FeeCalculation.ts.md +++ b/packages/evolution/docs/modules/sdk/builders/phases/FeeCalculation.ts.md @@ -1,6 +1,6 @@ --- title: sdk/builders/phases/FeeCalculation.ts -nav_order: 139 +nav_order: 140 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/builders/phases/Phases.ts.md b/packages/evolution/docs/modules/sdk/builders/phases/Phases.ts.md index a2b2e3dc..5f3e2333 100644 --- a/packages/evolution/docs/modules/sdk/builders/phases/Phases.ts.md +++ b/packages/evolution/docs/modules/sdk/builders/phases/Phases.ts.md @@ -1,6 +1,6 @@ --- title: sdk/builders/phases/Phases.ts -nav_order: 140 +nav_order: 141 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/builders/phases/Selection.ts.md b/packages/evolution/docs/modules/sdk/builders/phases/Selection.ts.md index 12df981d..d2d8978b 100644 --- a/packages/evolution/docs/modules/sdk/builders/phases/Selection.ts.md +++ b/packages/evolution/docs/modules/sdk/builders/phases/Selection.ts.md @@ -1,6 +1,6 @@ --- title: sdk/builders/phases/Selection.ts -nav_order: 141 +nav_order: 142 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/builders/phases/utils.ts.md b/packages/evolution/docs/modules/sdk/builders/phases/utils.ts.md index 4e6904a4..87bb1386 100644 --- a/packages/evolution/docs/modules/sdk/builders/phases/utils.ts.md +++ b/packages/evolution/docs/modules/sdk/builders/phases/utils.ts.md @@ -1,6 +1,6 @@ --- title: sdk/builders/phases/utils.ts -nav_order: 142 +nav_order: 143 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/client/Client.ts.md b/packages/evolution/docs/modules/sdk/client/Client.ts.md index 06d927b1..aa59ded6 100644 --- a/packages/evolution/docs/modules/sdk/client/Client.ts.md +++ b/packages/evolution/docs/modules/sdk/client/Client.ts.md @@ -1,6 +1,6 @@ --- title: sdk/client/Client.ts -nav_order: 152 +nav_order: 153 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/client/ClientImpl.ts.md b/packages/evolution/docs/modules/sdk/client/ClientImpl.ts.md index 50d352e9..4e7cd1bc 100644 --- a/packages/evolution/docs/modules/sdk/client/ClientImpl.ts.md +++ b/packages/evolution/docs/modules/sdk/client/ClientImpl.ts.md @@ -1,6 +1,6 @@ --- title: sdk/client/ClientImpl.ts -nav_order: 153 +nav_order: 154 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/provider/Blockfrost.ts.md b/packages/evolution/docs/modules/sdk/provider/Blockfrost.ts.md index 17483962..4f4f009b 100644 --- a/packages/evolution/docs/modules/sdk/provider/Blockfrost.ts.md +++ b/packages/evolution/docs/modules/sdk/provider/Blockfrost.ts.md @@ -1,6 +1,6 @@ --- title: sdk/provider/Blockfrost.ts -nav_order: 155 +nav_order: 156 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/provider/Koios.ts.md b/packages/evolution/docs/modules/sdk/provider/Koios.ts.md index 70046841..b4d286c5 100644 --- a/packages/evolution/docs/modules/sdk/provider/Koios.ts.md +++ b/packages/evolution/docs/modules/sdk/provider/Koios.ts.md @@ -1,6 +1,6 @@ --- title: sdk/provider/Koios.ts -nav_order: 156 +nav_order: 157 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/provider/Kupmios.ts.md b/packages/evolution/docs/modules/sdk/provider/Kupmios.ts.md index 9e132cc3..46357ba7 100644 --- a/packages/evolution/docs/modules/sdk/provider/Kupmios.ts.md +++ b/packages/evolution/docs/modules/sdk/provider/Kupmios.ts.md @@ -1,6 +1,6 @@ --- title: sdk/provider/Kupmios.ts -nav_order: 157 +nav_order: 158 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/provider/Maestro.ts.md b/packages/evolution/docs/modules/sdk/provider/Maestro.ts.md index 6ea7b9c3..a38d8b24 100644 --- a/packages/evolution/docs/modules/sdk/provider/Maestro.ts.md +++ b/packages/evolution/docs/modules/sdk/provider/Maestro.ts.md @@ -1,6 +1,6 @@ --- title: sdk/provider/Maestro.ts -nav_order: 158 +nav_order: 159 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/provider/Provider.ts.md b/packages/evolution/docs/modules/sdk/provider/Provider.ts.md index fbf51d0c..88b30035 100644 --- a/packages/evolution/docs/modules/sdk/provider/Provider.ts.md +++ b/packages/evolution/docs/modules/sdk/provider/Provider.ts.md @@ -1,6 +1,6 @@ --- title: sdk/provider/Provider.ts -nav_order: 159 +nav_order: 160 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/wallet/Derivation.ts.md b/packages/evolution/docs/modules/sdk/wallet/Derivation.ts.md index 33408eeb..7f4e02bb 100644 --- a/packages/evolution/docs/modules/sdk/wallet/Derivation.ts.md +++ b/packages/evolution/docs/modules/sdk/wallet/Derivation.ts.md @@ -1,6 +1,6 @@ --- title: sdk/wallet/Derivation.ts -nav_order: 161 +nav_order: 162 parent: Modules --- diff --git a/packages/evolution/docs/modules/sdk/wallet/WalletNew.ts.md b/packages/evolution/docs/modules/sdk/wallet/WalletNew.ts.md index e28b39f1..e6db77df 100644 --- a/packages/evolution/docs/modules/sdk/wallet/WalletNew.ts.md +++ b/packages/evolution/docs/modules/sdk/wallet/WalletNew.ts.md @@ -1,6 +1,6 @@ --- title: sdk/wallet/WalletNew.ts -nav_order: 162 +nav_order: 163 parent: Modules --- diff --git a/packages/evolution/docs/modules/uplc/UPLC.ts.md b/packages/evolution/docs/modules/uplc/UPLC.ts.md index e8e54aac..4e24ac39 100644 --- a/packages/evolution/docs/modules/uplc/UPLC.ts.md +++ b/packages/evolution/docs/modules/uplc/UPLC.ts.md @@ -1,6 +1,6 @@ --- title: uplc/UPLC.ts -nav_order: 183 +nav_order: 184 parent: Modules --- diff --git a/packages/evolution/docs/modules/utils/FeeValidation.ts.md b/packages/evolution/docs/modules/utils/FeeValidation.ts.md index 8ddb1f06..25973f4e 100644 --- a/packages/evolution/docs/modules/utils/FeeValidation.ts.md +++ b/packages/evolution/docs/modules/utils/FeeValidation.ts.md @@ -1,6 +1,6 @@ --- title: utils/FeeValidation.ts -nav_order: 186 +nav_order: 187 parent: Modules --- diff --git a/packages/evolution/docs/modules/utils/Hash.ts.md b/packages/evolution/docs/modules/utils/Hash.ts.md index 34ad8387..f4f98f92 100644 --- a/packages/evolution/docs/modules/utils/Hash.ts.md +++ b/packages/evolution/docs/modules/utils/Hash.ts.md @@ -1,6 +1,6 @@ --- title: utils/Hash.ts -nav_order: 187 +nav_order: 188 parent: Modules --- diff --git a/packages/evolution/docs/modules/utils/effect-runtime.ts.md b/packages/evolution/docs/modules/utils/effect-runtime.ts.md index 74ce2c2e..1967b2cf 100644 --- a/packages/evolution/docs/modules/utils/effect-runtime.ts.md +++ b/packages/evolution/docs/modules/utils/effect-runtime.ts.md @@ -1,6 +1,6 @@ --- title: utils/effect-runtime.ts -nav_order: 185 +nav_order: 186 parent: Modules --- diff --git a/packages/evolution/src/sdk/builders/TransactionBuilder.ts b/packages/evolution/src/sdk/builders/TransactionBuilder.ts index 5d21993a..8092d0cd 100644 --- a/packages/evolution/src/sdk/builders/TransactionBuilder.ts +++ b/packages/evolution/src/sdk/builders/TransactionBuilder.ts @@ -84,6 +84,7 @@ import type { RegisterStakeParams, ResignCommitteeColdParams, RetirePoolParams, + SendAllParams, UpdateDRepParams, ValidityParams, VoteParams, @@ -93,6 +94,7 @@ import { createPayToAddressProgram } from "./operations/Pay.js" import { createRegisterPoolProgram, createRetirePoolProgram } from "./operations/Pool.js" import { createProposeProgram } from "./operations/Propose.js" import { createReadFromProgram } from "./operations/ReadFrom.js" +import { createSendAllProgram } from "./operations/SendAll.js" import { createDelegateToDRepProgram, createDelegateToPoolAndDRepProgram, @@ -1345,6 +1347,7 @@ export interface TxBuilderState { } readonly requiredSigners: ReadonlyArray // Extra signers required (for script validation) readonly auxiliaryData?: AuxiliaryData.AuxiliaryData // Auxiliary data (metadata, scripts, etc.) + readonly sendAllTo?: CoreAddress.Address // Target address for sendAll operation } /** @@ -1600,6 +1603,39 @@ export interface TransactionBuilderBase { */ readonly collectFrom: (params: CollectFromParams) => this + /** + * Send all wallet assets to a recipient address. + * + * This operation collects all wallet UTxOs and creates a single output + * containing all assets minus the transaction fee. No change output is created. + * + * Use cases: + * - Draining a wallet completely + * - Consolidating all UTxOs into a single output + * - Migrating funds to a new address + * + * **Important**: This operation is mutually exclusive with `payToAddress` and `collectFrom`. + * When `sendAll` is used, all wallet UTxOs are automatically collected and the output + * is automatically created. Any existing outputs or inputs will cause an error. + * + * Queues a deferred operation that will be executed when build() is called. + * Returns the same builder for method chaining. + * + * @example + * ```typescript + * import { Address } from "@evolution-sdk/evolution" + * + * const tx = await client + * .newTx() + * .sendAll({ to: Address.fromBech32("addr1...") }) + * .build() + * ``` + * + * @since 2.0.0 + * @category builder-methods + */ + readonly sendAll: (params: SendAllParams) => this + /** * Attach a script to the transaction. * @@ -2458,6 +2494,13 @@ export function makeTxBuilder(config: TxBuilderConfig) { return txBuilder // Return same instance for chaining }, + sendAll: (params: SendAllParams) => { + // Create ProgramStep for deferred execution + const program = createSendAllProgram(params) + programs.push(program) + return txBuilder // Return same instance for chaining + }, + mintAssets: (params: MintTokensParams) => { // Create ProgramStep for deferred execution const program = createMintAssetsProgram(params) diff --git a/packages/evolution/src/sdk/builders/operations/Operations.ts b/packages/evolution/src/sdk/builders/operations/Operations.ts index 1fb51271..026aa94f 100644 --- a/packages/evolution/src/sdk/builders/operations/Operations.ts +++ b/packages/evolution/src/sdk/builders/operations/Operations.ts @@ -485,4 +485,25 @@ export interface ProposeParams { readonly rewardAccount: RewardAccount.RewardAccount /** Optional anchor with metadata URL and hash */ readonly anchor: Anchor.Anchor | null +} + +// ============================================================================ +// Send All Operation +// ============================================================================ + +/** + * Parameters for sending all wallet assets to a recipient address. + * + * This operation collects all wallet UTxOs and creates a single output + * containing all assets minus the transaction fee. It's commonly used for: + * - Draining a wallet completely + * - Consolidating all UTxOs into a single output + * - Migrating funds to a new address + * + * @since 2.0.0 + * @category payment + */ +export interface SendAllParams { + /** The recipient address to receive all assets */ + readonly to: CoreAddress.Address } \ No newline at end of file diff --git a/packages/evolution/src/sdk/builders/operations/SendAll.ts b/packages/evolution/src/sdk/builders/operations/SendAll.ts new file mode 100644 index 00000000..4de52cb2 --- /dev/null +++ b/packages/evolution/src/sdk/builders/operations/SendAll.ts @@ -0,0 +1,48 @@ +/** + * SendAll operation - sends all wallet assets to a recipient address. + * + * This operation marks the transaction as a "send all" transaction, + * which triggers special handling in the build phases: + * 1. All wallet UTxOs are collected as inputs + * 2. A single output is created with all assets minus fee + * 3. No change output is created (everything goes to recipient) + * + * @module operations/SendAll + * @since 2.0.0 + */ + +import { Effect, Ref } from "effect" + +import type * as CoreAddress from "../../../Address.js" +import { TxContext } from "../TransactionBuilder.js" +import type { SendAllParams } from "./Operations.js" + +/** + * Creates a ProgramStep for sendAll operation. + * + * This sets up the sendAll mode in the builder state, which is processed + * during the build phases. The actual UTxO collection and output creation + * happens during the build process when wallet UTxOs are available. + * + * @since 2.0.0 + * @category programs + */ +export const createSendAllProgram = (params: SendAllParams) => + Effect.gen(function* () { + const ctx = yield* TxContext + + yield* Ref.update(ctx, (state) => ({ + ...state, + sendAllTo: params.to + })) + + yield* Effect.logDebug(`[SendAll] Configured to send all assets to ${params.to}`) + }) + +/** + * Type representing the sendAll target address in builder state. + * + * @since 2.0.0 + * @category types + */ +export type SendAllTarget = CoreAddress.Address diff --git a/packages/evolution/src/sdk/builders/operations/index.ts b/packages/evolution/src/sdk/builders/operations/index.ts index 4beee1f0..44dab63e 100644 --- a/packages/evolution/src/sdk/builders/operations/index.ts +++ b/packages/evolution/src/sdk/builders/operations/index.ts @@ -9,6 +9,7 @@ export * from "./Pay.js" export * from "./Pool.js" export * from "./Propose.js" export * from "./ReadFrom.js" +export * from "./SendAll.js" export * from "./Stake.js" export * from "./Validity.js" export * from "./Vote.js" diff --git a/packages/evolution/src/sdk/builders/phases/ChangeCreation.ts b/packages/evolution/src/sdk/builders/phases/ChangeCreation.ts index f9607075..844a3512 100644 --- a/packages/evolution/src/sdk/builders/phases/ChangeCreation.ts +++ b/packages/evolution/src/sdk/builders/phases/ChangeCreation.ts @@ -197,6 +197,56 @@ export const executeChangeCreation = (): Effect.Effect< const rawLeftover = CoreAssets.subtractLovelace(leftoverBeforeFee, buildCtx.calculatedFee) const tentativeLeftover = CoreAssets.filter(rawLeftover, (_unit, amount) => amount > 0n) + // === SendAll Mode === + // If sendAllTo is set, create a single output with all remaining assets to the target address + if (state.sendAllTo !== undefined) { + yield* Effect.logDebug( + `[ChangeCreation] SendAll mode: Creating output to ${state.sendAllTo} with ` + + `${formatAssetsForLog(tentativeLeftover)}` + ) + + const leftoverLovelace = CoreAssets.lovelaceOf(tentativeLeftover) + + // Validate that we have enough for minUTxO + const protocolParams = yield* ProtocolParametersTag + const sendAllMinUtxo = yield* calculateMinimumUtxoLovelace({ + address: state.sendAllTo, + assets: tentativeLeftover, + coinsPerUtxoByte: protocolParams.coinsPerUtxoByte + }) + + if (leftoverLovelace < sendAllMinUtxo) { + return yield* Effect.fail( + new TransactionBuilderError({ + message: + `sendAll() failed: Insufficient funds to create valid output. ` + + `Available: ${leftoverLovelace} lovelace, Required: ${sendAllMinUtxo} lovelace (minUTxO). ` + + `The wallet balance after fees is too low to create a valid UTxO.` + }) + ) + } + + // Create the sendAll output using the txOutputToTransactionOutput helper + const sendAllOutput = yield* txOutputToTransactionOutput({ + address: state.sendAllTo, + assets: tentativeLeftover + }) + + // Store sendAll output as a change output (not in state.outputs) + // This ensures the phase loop doesn't double-count it in outputAssets + yield* Ref.update(buildCtxRef, (ctx) => ({ + ...ctx, + changeOutputs: [sendAllOutput] + })) + + yield* Effect.logDebug( + `[ChangeCreation] SendAll: Created output with ${formatAssetsForLog(tentativeLeftover)}` + ) + + return { next: "feeCalculation" as const } + } + + // === Normal Change Creation === // Step 3: Check if negative - return to selection immediately const leftoverLovelace = CoreAssets.lovelaceOf(tentativeLeftover) if (leftoverLovelace < 0n) { diff --git a/packages/evolution/src/sdk/builders/phases/Selection.ts b/packages/evolution/src/sdk/builders/phases/Selection.ts index 32868ae5..2227ea60 100644 --- a/packages/evolution/src/sdk/builders/phases/Selection.ts +++ b/packages/evolution/src/sdk/builders/phases/Selection.ts @@ -210,6 +210,109 @@ export const executeSelection = (): Effect.Effect 0) { + return yield* Effect.fail( + new TransactionBuilderError({ + message: + "sendAll() cannot be used with payToAddress(). " + + "sendAll automatically creates the output with all wallet assets." + }) + ) + } + + if (state.selectedUtxos.length > 0) { + return yield* Effect.fail( + new TransactionBuilderError({ + message: + "sendAll() cannot be used with collectFrom(). " + + "sendAll automatically collects all wallet UTxOs." + }) + ) + } + + if (state.mint !== undefined) { + return yield* Effect.fail( + new TransactionBuilderError({ + message: + "sendAll() cannot be used with mintAssets(). " + + "sendAll is designed for draining a wallet, not minting operations." + }) + ) + } + + if (state.certificates.length > 0) { + return yield* Effect.fail( + new TransactionBuilderError({ + message: + "sendAll() cannot be used with staking operations (registerStake, deregisterStake, delegateTo, etc.). " + + "sendAll is designed for simple wallet drain operations only." + }) + ) + } + + if (state.withdrawals.size > 0) { + return yield* Effect.fail( + new TransactionBuilderError({ + message: + "sendAll() cannot be used with withdraw(). " + + "sendAll is designed for simple wallet drain operations only." + }) + ) + } + + if (state.votingProcedures !== undefined || state.proposalProcedures !== undefined) { + return yield* Effect.fail( + new TransactionBuilderError({ + message: + "sendAll() cannot be used with governance operations (vote, propose). " + + "sendAll is designed for simple wallet drain operations only." + }) + ) + } + + // Get all available UTxOs + const allAvailableUtxos = yield* AvailableUtxosTag + + if (allAvailableUtxos.length === 0) { + return yield* Effect.fail( + new TransactionBuilderError({ + message: "sendAll() failed: Wallet has no UTxOs to send." + }) + ) + } + + // Select ALL UTxOs + yield* addUtxosToState(allAvailableUtxos) + + const stateAfterSelection = yield* Ref.get(ctx) + const totalInputAssets = stateAfterSelection.totalInputAssets + + yield* Effect.logDebug( + `[Selection] SendAll: Collected ${allAvailableUtxos.length} UTxO(s) with ` + + `${formatAssetsForLog(totalInputAssets)}` + ) + + // Update attempt counter + yield* Ref.update(buildCtxRef, (ctx) => ({ ...ctx, attempt: ctx.attempt + 1, shortfall: 0n })) + + // Check if this is a script transaction (has redeemers or deferred redeemers) + // If so, route to Collateral BEFORE ChangeCreation + if (stateAfterSelection.redeemers.size > 0 || stateAfterSelection.deferredRedeemers.size > 0) { + yield* Effect.logDebug("[Selection] Script transaction detected - routing to Collateral phase") + return { next: "collateral" as const } + } + + return { next: "changeCreation" as const } + } + + // === Normal Selection Mode === const inputAssets = state.totalInputAssets const outputAssets = state.totalOutputAssets From 684d8a30b6b7b3f94587598313537fd765ca6f26 Mon Sep 17 00:00:00 2001 From: solidsnakedev Date: Thu, 15 Jan 2026 10:59:16 -0700 Subject: [PATCH 2/4] fix: remove unreachable code path in sendAll selection --- .../evolution/src/sdk/builders/operations/SendAll.ts | 7 +++++-- .../evolution/src/sdk/builders/phases/ChangeCreation.ts | 5 +++-- packages/evolution/src/sdk/builders/phases/Selection.ts | 9 ++------- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/packages/evolution/src/sdk/builders/operations/SendAll.ts b/packages/evolution/src/sdk/builders/operations/SendAll.ts index 4de52cb2..19afbfc7 100644 --- a/packages/evolution/src/sdk/builders/operations/SendAll.ts +++ b/packages/evolution/src/sdk/builders/operations/SendAll.ts @@ -4,8 +4,11 @@ * This operation marks the transaction as a "send all" transaction, * which triggers special handling in the build phases: * 1. All wallet UTxOs are collected as inputs - * 2. A single output is created with all assets minus fee - * 3. No change output is created (everything goes to recipient) + * 2. A single output is created with all assets minus fee to the recipient + * + * Note: Internally the output is stored in `changeOutputs` (the standard mechanism + * for phase-created outputs), but semantically it represents the full transfer to + * the recipient - not traditional "change" that returns to the sender. * * @module operations/SendAll * @since 2.0.0 diff --git a/packages/evolution/src/sdk/builders/phases/ChangeCreation.ts b/packages/evolution/src/sdk/builders/phases/ChangeCreation.ts index 844a3512..5081d8d6 100644 --- a/packages/evolution/src/sdk/builders/phases/ChangeCreation.ts +++ b/packages/evolution/src/sdk/builders/phases/ChangeCreation.ts @@ -232,8 +232,9 @@ export const executeChangeCreation = (): Effect.Effect< assets: tentativeLeftover }) - // Store sendAll output as a change output (not in state.outputs) - // This ensures the phase loop doesn't double-count it in outputAssets + // Store sendAll output in changeOutputs (the standard pattern for outputs created during phases). + // This follows the same convention as normal change outputs - outputs created during the + // phase loop go in changeOutputs, while state.outputs contains user-specified outputs. yield* Ref.update(buildCtxRef, (ctx) => ({ ...ctx, changeOutputs: [sendAllOutput] diff --git a/packages/evolution/src/sdk/builders/phases/Selection.ts b/packages/evolution/src/sdk/builders/phases/Selection.ts index 2227ea60..b2084a8f 100644 --- a/packages/evolution/src/sdk/builders/phases/Selection.ts +++ b/packages/evolution/src/sdk/builders/phases/Selection.ts @@ -302,13 +302,8 @@ export const executeSelection = (): Effect.Effect ({ ...ctx, attempt: ctx.attempt + 1, shortfall: 0n })) - // Check if this is a script transaction (has redeemers or deferred redeemers) - // If so, route to Collateral BEFORE ChangeCreation - if (stateAfterSelection.redeemers.size > 0 || stateAfterSelection.deferredRedeemers.size > 0) { - yield* Effect.logDebug("[Selection] Script transaction detected - routing to Collateral phase") - return { next: "collateral" as const } - } - + // sendAll is always a simple payment transaction (no scripts) + // All script operations (collectFrom, mint, staking, governance) are blocked above return { next: "changeCreation" as const } } From e5a44a964618309ff0064bc7fb89423ae690f5a7 Mon Sep 17 00:00:00 2001 From: solidsnakedev Date: Thu, 15 Jan 2026 11:20:38 -0700 Subject: [PATCH 3/4] test: add unit tests for sendAll API --- .../evolution/test/TxBuilder.SendAll.test.ts | 227 ++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 packages/evolution/test/TxBuilder.SendAll.test.ts diff --git a/packages/evolution/test/TxBuilder.SendAll.test.ts b/packages/evolution/test/TxBuilder.SendAll.test.ts new file mode 100644 index 00000000..5241e7ca --- /dev/null +++ b/packages/evolution/test/TxBuilder.SendAll.test.ts @@ -0,0 +1,227 @@ +import { describe, expect, it } from "@effect/vitest" + +import * as Address from "../src/Address.js" +import * as CoreAssets from "../src/Assets/index.js" +import type { TxBuilderConfig } from "../src/sdk/builders/TransactionBuilder.js" +import { makeTxBuilder } from "../src/sdk/builders/TransactionBuilder.js" +import type * as CoreUTxO from "../src/UTxO.js" +import { createCoreTestUtxo } from "./utils/utxo-helpers.js" + +const PROTOCOL_PARAMS = { + minFeeCoefficient: 44n, + minFeeConstant: 155_381n, + coinsPerUtxoByte: 4_310n, + maxTxSize: 16_384 +} + +const SOURCE_ADDRESS = + "addr_test1qz2fxv2umyhttkxyxp8x0dlpdt3k6cwng5pxj3jhsydzer3n0d3vllmyqwsx5wktcd8cc3sq835lu7drv2xwl2wywfgs68faae" +const DESTINATION_ADDRESS = + "addr_test1qpw0djgj0x59ngrjvqthn7enhvruxnsavsw5th63la3mjel3tkc974sr23jmlzgq5zda4gtv8k9cy38756r9y3qgmkqqjz6aa7" + +// Policy IDs for test tokens (56 hex chars) +const FUNGIBLE_POLICY = "a".repeat(56) +const NFT_POLICY = "c".repeat(56) + +// Asset name in hex +const HOSKY_NAME_HEX = "484f534b59" // "HOSKY" in hex +const NFT_NAME_HEX = "4e4654303031" // "NFT001" in hex + +const baseConfig: TxBuilderConfig = {} + +describe("TxBuilder SendAll", () => { + describe("Basic SendAll Operation", () => { + it("should send all ADA from wallet to recipient", async () => { + const utxos: Array = [ + createCoreTestUtxo({ + transactionId: "a".repeat(64), + index: 0, + address: SOURCE_ADDRESS, + lovelace: 200_000_000n + }), + createCoreTestUtxo({ + transactionId: "b".repeat(64), + index: 0, + address: SOURCE_ADDRESS, + lovelace: 150_000_000n + }) + ] + const totalLovelace = 350_000_000n + + const signBuilder = await makeTxBuilder(baseConfig) + .sendAll({ to: Address.fromBech32(DESTINATION_ADDRESS) }) + .build({ + changeAddress: Address.fromBech32(SOURCE_ADDRESS), + availableUtxos: utxos, + protocolParameters: PROTOCOL_PARAMS + }) + + const tx = await signBuilder.toTransaction() + + // Should have all UTxOs as inputs + expect(tx.body.inputs.length).toBe(2) + + // Should have exactly one output (to recipient) + expect(tx.body.outputs.length).toBe(1) + expect(Address.toBech32(tx.body.outputs[0].address)).toBe(DESTINATION_ADDRESS) + + // Output should contain total ADA minus fee + const outputLovelace = tx.body.outputs[0].assets.lovelace + const fee = tx.body.fee + expect(outputLovelace + fee).toBe(totalLovelace) + }) + + it("should send all assets including tokens from multi-asset wallet", async () => { + // Unit format: policyId + assetNameHex (no separator) + const hoskyUnit = `${FUNGIBLE_POLICY}${HOSKY_NAME_HEX}` + const nftUnit = `${NFT_POLICY}${NFT_NAME_HEX}` + + const utxos: Array = [ + createCoreTestUtxo({ + transactionId: "1".repeat(64), + index: 0, + address: SOURCE_ADDRESS, + lovelace: 100_000_000n, + nativeAssets: { [hoskyUnit]: 500_000n } + }), + createCoreTestUtxo({ + transactionId: "2".repeat(64), + index: 0, + address: SOURCE_ADDRESS, + lovelace: 50_000_000n, + nativeAssets: { [nftUnit]: 1n } + }), + createCoreTestUtxo({ + transactionId: "3".repeat(64), + index: 0, + address: SOURCE_ADDRESS, + lovelace: 25_000_000n + }) + ] + const totalLovelace = 175_000_000n + + const signBuilder = await makeTxBuilder(baseConfig) + .sendAll({ to: Address.fromBech32(DESTINATION_ADDRESS) }) + .build({ + changeAddress: Address.fromBech32(SOURCE_ADDRESS), + availableUtxos: utxos, + protocolParameters: PROTOCOL_PARAMS + }) + + const tx = await signBuilder.toTransaction() + + // Should have all UTxOs as inputs + expect(tx.body.inputs.length).toBe(3) + + // Should have exactly one output + expect(tx.body.outputs.length).toBe(1) + + const output = tx.body.outputs[0] + expect(Address.toBech32(output.address)).toBe(DESTINATION_ADDRESS) + + // Output should contain all tokens + expect(CoreAssets.getByUnit(output.assets, hoskyUnit)).toBe(500_000n) + expect(CoreAssets.getByUnit(output.assets, nftUnit)).toBe(1n) + + // Output should contain total ADA minus fee + const outputLovelace = output.assets.lovelace + const fee = tx.body.fee + expect(outputLovelace + fee).toBe(totalLovelace) + }) + }) + + describe("Mutual Exclusivity Validation", () => { + it("should fail when used with payToAddress", async () => { + const utxos: Array = [ + createCoreTestUtxo({ + transactionId: "a".repeat(64), + index: 0, + address: SOURCE_ADDRESS, + lovelace: 100_000_000n + }) + ] + + await expect( + makeTxBuilder(baseConfig) + .payToAddress({ + address: Address.fromBech32(DESTINATION_ADDRESS), + assets: CoreAssets.fromLovelace(1_000_000n) + }) + .sendAll({ to: Address.fromBech32(DESTINATION_ADDRESS) }) + .build({ + changeAddress: Address.fromBech32(SOURCE_ADDRESS), + availableUtxos: utxos, + protocolParameters: PROTOCOL_PARAMS + }) + ).rejects.toThrow("sendAll() cannot be used with payToAddress()") + }) + + it("should fail when used with collectFrom", async () => { + const utxos: Array = [ + createCoreTestUtxo({ + transactionId: "a".repeat(64), + index: 0, + address: SOURCE_ADDRESS, + lovelace: 100_000_000n + }) + ] + + await expect( + makeTxBuilder(baseConfig) + .collectFrom({ inputs: [utxos[0]] }) + .sendAll({ to: Address.fromBech32(DESTINATION_ADDRESS) }) + .build({ + changeAddress: Address.fromBech32(SOURCE_ADDRESS), + availableUtxos: utxos, + protocolParameters: PROTOCOL_PARAMS + }) + ).rejects.toThrow("sendAll() cannot be used with collectFrom()") + }) + }) + + describe("Insufficient Funds Handling", () => { + it("should fail when wallet is empty", async () => { + await expect( + makeTxBuilder(baseConfig) + .sendAll({ to: Address.fromBech32(DESTINATION_ADDRESS) }) + .build({ + changeAddress: Address.fromBech32(SOURCE_ADDRESS), + availableUtxos: [], + protocolParameters: PROTOCOL_PARAMS + }) + ).rejects.toThrow("sendAll() failed: Wallet has no UTxOs to send.") + }) + }) + + describe("Fee Calculation", () => { + it("should calculate fee correctly based on transaction size", async () => { + const utxos: Array = [ + createCoreTestUtxo({ + transactionId: "a".repeat(64), + index: 0, + address: SOURCE_ADDRESS, + lovelace: 200_000_000n + }), + createCoreTestUtxo({ + transactionId: "b".repeat(64), + index: 0, + address: SOURCE_ADDRESS, + lovelace: 150_000_000n + }) + ] + + const signBuilder = await makeTxBuilder(baseConfig) + .sendAll({ to: Address.fromBech32(DESTINATION_ADDRESS) }) + .build({ + changeAddress: Address.fromBech32(SOURCE_ADDRESS), + availableUtxos: utxos, + protocolParameters: PROTOCOL_PARAMS + }) + + const tx = await signBuilder.toTransaction() + + // Fee is deterministic for a 2-input, 1-output transaction + expect(tx.body.fee).toBe(166_865n) + }) + }) +}) From 92344beaf61b9f7c269539944b328a38f56cac75 Mon Sep 17 00:00:00 2001 From: solidsnakedev Date: Thu, 15 Jan 2026 11:21:24 -0700 Subject: [PATCH 4/4] docs: add sendAll API documentation --- .../sdk/builders/operations/SendAll.mdx | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 docs/content/docs/modules/sdk/builders/operations/SendAll.mdx diff --git a/docs/content/docs/modules/sdk/builders/operations/SendAll.mdx b/docs/content/docs/modules/sdk/builders/operations/SendAll.mdx new file mode 100644 index 00000000..60dab2e7 --- /dev/null +++ b/docs/content/docs/modules/sdk/builders/operations/SendAll.mdx @@ -0,0 +1,61 @@ +--- +title: sdk/builders/operations/SendAll.ts +nav_order: 131 +parent: Modules +--- + +## SendAll overview + +SendAll operation - sends all wallet assets to a recipient address. + +This operation marks the transaction as a "send all" transaction, +which triggers special handling in the build phases: + +1. All wallet UTxOs are collected as inputs +2. A single output is created with all assets minus fee +3. No change output is created (everything goes to recipient) + +Added in v2.0.0 + +--- + +

Table of contents

+ +- [programs](#programs) + - [createSendAllProgram](#createsendallprogram) +- [types](#types) + - [SendAllTarget (type alias)](#sendalltarget-type-alias) + +--- + +# programs + +## createSendAllProgram + +Creates a ProgramStep for sendAll operation. + +This sets up the sendAll mode in the builder state, which is processed +during the build phases. The actual UTxO collection and output creation +happens during the build process when wallet UTxOs are available. + +**Signature** + +```ts +export declare const createSendAllProgram: (params: SendAllParams) => Effect.Effect +``` + +Added in v2.0.0 + +# types + +## SendAllTarget (type alias) + +Type representing the sendAll target address in builder state. + +**Signature** + +```ts +export type SendAllTarget = CoreAddress.Address +``` + +Added in v2.0.0