diff --git a/modules/ecash-agora/src/agora.ts b/modules/ecash-agora/src/agora.ts
--- a/modules/ecash-agora/src/agora.ts
+++ b/modules/ecash-agora/src/agora.ts
@@ -140,9 +140,12 @@
         dustAmount?: number;
         /** Fee per kB to use when building the tx. */
         feePerKb?: number;
+        /**  Allow accepting an offer such that the remaining quantity is unacceptable */
+        allowUnspendable?: boolean;
     }): Tx {
         const dustAmount = params.dustAmount ?? DEFAULT_DUST_LIMIT;
         const feePerKb = params.feePerKb ?? DEFAULT_FEE_PER_KB;
+        const allowUnspendable = params.allowUnspendable ?? false;
         const txBuild = this._acceptTxBuilder({
             covenantSk: params.covenantSk,
             covenantPk: params.covenantPk,
@@ -155,6 +158,7 @@
                 params.recipientScript,
             ],
             acceptedTokens: params.acceptedTokens,
+            allowUnspendable,
         });
         return txBuild.sign(params.ecc, feePerKb, dustAmount);
     }
@@ -197,6 +201,7 @@
         fuelInputs: TxBuilderInput[];
         extraOutputs: TxBuilderOutput[];
         acceptedTokens?: bigint;
+        allowUnspendable?: boolean;
     }): TxBuilder {
         switch (this.variant.type) {
             case 'ONESHOT':
@@ -232,6 +237,48 @@
                         `Must acceptedTokens must be a multiple of ${truncFactor}`,
                     );
                 }
+                // Validation to avoid creating an unspendable offer
+                //
+                // 1 - confirm the remaining offer amount is more than the
+                //     min accept amount for this agora partial
+                //
+                // 2 - Confirm the cost of accepting the (full) remainder is
+                //     at least dust. This is already confirmed...for offers
+                //     created by this lib... as minAcceptedTokens() must
+                //     cost more than dust
+                //
+                //
+                // If these condtions are not met, an AgoraOffer would be created
+                // that is impossible to accept; can only be canceld by its maker
+
+                // Get the token qty that would remain after this accept
+                const offeredTokens = BigInt(this.token.amount);
+                if (
+                    typeof params.allowUnspendable !== 'undefined' &&
+                    params.allowUnspendable === false
+                ) {
+                    const remainingTokens =
+                        offeredTokens - params.acceptedTokens;
+                    if (remainingTokens > 0n) {
+                        // Full accepts are always ok
+
+                        const minAcceptedTokens =
+                            agoraPartial.minAcceptedTokens();
+                        const priceOfRemainingTokens =
+                            agoraPartial.askedSats(remainingTokens);
+                        if (remainingTokens < minAcceptedTokens) {
+                            throw new Error(
+                                `Accepting ${params.acceptedTokens} token satoshis would leave an amount lower than the min acceptable by the terms of this contract, and hence unacceptable. Accept fewer tokens or the full offer.`,
+                            );
+                        }
+                        if (priceOfRemainingTokens < agoraPartial.dustAmount) {
+                            throw new Error(
+                                `Accepting ${params.acceptedTokens} token satoshis would leave an amount priced lower than dust. Accept fewer tokens or the full offer.`,
+                            );
+                        }
+                    }
+                }
+
                 txBuild.inputs.push({
                     input: this.txBuilderInput,
                     signatory: AgoraPartialSignatory(
@@ -243,7 +290,7 @@
                 });
                 txBuild.inputs.push(...params.fuelInputs);
                 const sendAmounts: Amount[] = [0];
-                const offeredTokens = BigInt(this.token.amount);
+
                 if (offeredTokens > params.acceptedTokens) {
                     sendAmounts.push(offeredTokens - params.acceptedTokens);
                 }
diff --git a/modules/ecash-agora/tests/partial-helper-alp.ts b/modules/ecash-agora/tests/partial-helper-alp.ts
--- a/modules/ecash-agora/tests/partial-helper-alp.ts
+++ b/modules/ecash-agora/tests/partial-helper-alp.ts
@@ -132,6 +132,7 @@
     takerSk: Uint8Array;
     takerInput: TxBuilderInput;
     acceptedTokens: bigint;
+    allowUnspendable?: boolean;
 }) {
     const takerSk = params.takerSk;
     const takerPk = params.ecc.derivePubkey(takerSk);
@@ -144,6 +145,7 @@
         fuelInputs: [params.takerInput],
         recipientScript: takerP2pkh,
         acceptedTokens: params.acceptedTokens,
+        allowUnspendable: params.allowUnspendable,
     });
     const acceptTxid = (await params.chronik.broadcastTx(acceptTx.ser())).txid;
     return acceptTxid;
diff --git a/modules/ecash-agora/tests/partial-helper-slp.ts b/modules/ecash-agora/tests/partial-helper-slp.ts
--- a/modules/ecash-agora/tests/partial-helper-slp.ts
+++ b/modules/ecash-agora/tests/partial-helper-slp.ts
@@ -136,6 +136,7 @@
     takerSk: Uint8Array;
     takerInput: TxBuilderInput;
     acceptedTokens: bigint;
+    allowUnspendable?: boolean;
 }) {
     const takerSk = params.takerSk;
     const takerPk = params.ecc.derivePubkey(takerSk);
@@ -148,6 +149,7 @@
         fuelInputs: [params.takerInput],
         recipientScript: takerP2pkh,
         acceptedTokens: params.acceptedTokens,
+        allowUnspendable: params.allowUnspendable,
     });
     const acceptTxid = (await params.chronik.broadcastTx(acceptTx.ser())).txid;
     return acceptTxid;
diff --git a/modules/ecash-agora/tests/partial.alp.test.ts b/modules/ecash-agora/tests/partial.alp.test.ts
--- a/modules/ecash-agora/tests/partial.alp.test.ts
+++ b/modules/ecash-agora/tests/partial.alp.test.ts
@@ -2,7 +2,7 @@
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
-import { expect, use } from 'chai';
+import { expect, use, assert } from 'chai';
 import chaiAsPromised from 'chai-as-promised';
 import { ChronikClient } from 'chronik-client';
 import {
@@ -103,6 +103,7 @@
         priceNanoSatsPerToken: bigint;
         acceptedTokens: bigint;
         askedSats: number;
+        allowUnspendable?: boolean;
     }
     const TEST_CASES: TestCase[] = [
         {
@@ -118,6 +119,7 @@
             priceNanoSatsPerToken: 1000000000n,
             acceptedTokens: 546n,
             askedSats: 546,
+            allowUnspendable: true,
         },
         {
             offeredTokens: 1000n,
@@ -405,6 +407,7 @@
             priceNanoSatsPerToken: 1000n,
             acceptedTokens: 0x1e000000n,
             askedSats: 549,
+            allowUnspendable: true,
         },
         {
             offeredTokens: 0xffffffffffffn,
@@ -467,7 +470,24 @@
                 offer,
                 takerInput,
                 acceptedTokens: testCase.acceptedTokens,
+                allowUnspendable: testCase.allowUnspendable,
             });
+            if (testCase.allowUnspendable) {
+                // We get an error for test cases that would result in unspendable amounts
+                // if we do not pass allowUnspendable to agoraOffer.acceptTx
+                await assert.isRejected(
+                    takeAlpOffer({
+                        chronik,
+                        ecc,
+                        takerSk,
+                        offer,
+                        takerInput,
+                        acceptedTokens: testCase.acceptedTokens,
+                        allowUnspendable: false,
+                    }),
+                    `Accepting ${testCase.acceptedTokens} token satoshis would leave an amount lower than the min acceptable by the terms of this contract, and hence unacceptable. Accept fewer tokens or the full offer.`,
+                );
+            }
             const acceptTx = await chronik.tx(acceptTxid);
             const offeredTokens = agoraPartial.offeredTokens();
             if (testCase.acceptedTokens == offeredTokens) {
diff --git a/modules/ecash-agora/tests/partial.slp.test.ts b/modules/ecash-agora/tests/partial.slp.test.ts
--- a/modules/ecash-agora/tests/partial.slp.test.ts
+++ b/modules/ecash-agora/tests/partial.slp.test.ts
@@ -2,7 +2,7 @@
 // Distributed under the MIT software license, see the accompanying
 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
 
-import { expect, use } from 'chai';
+import { expect, use, assert } from 'chai';
 import chaiAsPromised from 'chai-as-promised';
 import { ChronikClient } from 'chronik-client';
 import {
@@ -102,6 +102,7 @@
         priceNanoSatsPerToken: bigint;
         acceptedTokens: bigint;
         askedSats: number;
+        allowUnspendable?: boolean;
     }
     const TEST_CASES: TestCase[] = [
         {
@@ -117,6 +118,7 @@
             priceNanoSatsPerToken: 1000000000n,
             acceptedTokens: 546n,
             askedSats: 546,
+            allowUnspendable: true,
         },
         {
             offeredTokens: 1000n,
@@ -194,6 +196,7 @@
             priceNanoSatsPerToken: 1000000000n,
             acceptedTokens: 546n,
             askedSats: 546,
+            allowUnspendable: true,
         },
         {
             offeredTokens: 1000000n,
@@ -522,7 +525,24 @@
                 offer,
                 takerInput,
                 acceptedTokens: testCase.acceptedTokens,
+                allowUnspendable: testCase.allowUnspendable,
             });
+            if (testCase.allowUnspendable) {
+                // We get an error for test cases that would result in unspendable amounts
+                // if we do not pass allowUnspendable to agoraOffer.acceptTx
+                await assert.isRejected(
+                    takeSlpOffer({
+                        chronik,
+                        ecc,
+                        takerSk,
+                        offer,
+                        takerInput,
+                        acceptedTokens: testCase.acceptedTokens,
+                        allowUnspendable: false,
+                    }),
+                    `Accepting ${testCase.acceptedTokens} token satoshis would leave an amount lower than the min acceptable by the terms of this contract, and hence unacceptable. Accept fewer tokens or the full offer.`,
+                );
+            }
             const acceptTx = await chronik.tx(acceptTxid);
             const offeredTokens = agoraPartial.offeredTokens();
             if (testCase.acceptedTokens == offeredTokens) {