Paid-sale workflow
This commit is contained in:
@@ -11,6 +11,7 @@ import { applySaleBlock, initialSaleState, saleContext, saleDecision, saleId, sa
|
||||
type SaleState, type CandidateTransaction } from '../server/testnet/sale-candidate.ts';
|
||||
import { address, transactionSchema, CHAIN_ID } from '../server/testnet/consensus.ts';
|
||||
import { CustodyMarket } from '../server/market/custody.ts';
|
||||
import { ADDITIONAL_MARKET_FEE } from '../shared/market.ts';
|
||||
import { CUSTODY_POLICY, custodyMessage, type CustodyCommand, type CustodyAction, type CustodyOrder, type CustodyListing } from '../shared/custody.ts';
|
||||
|
||||
function identity() {
|
||||
@@ -99,6 +100,18 @@ test('host cannot redirect delivery or alter signed reservation evidence, and co
|
||||
assert.equal(saleDecision(at(done, 14), f.terms, context, 'settled').action, 'none');
|
||||
});
|
||||
|
||||
test('candidate host recipient extension is signed and omission preserves historical terms bytes', () => {
|
||||
const legacy = fixture(), t = legacy.terms;
|
||||
assert.equal(saleTermsMessage(t), JSON.stringify([SALE_CANDIDATE, 'terms', t.network, t.chainId, t.policyDigest,
|
||||
t.custodianId, t.orderId, t.cardHash, t.sequence, t.seller, t.buyer, t.host, 'XMR', t.priceAtomicXmr,
|
||||
t.feeBps, ADDITIONAL_MARKET_FEE.bps, ADDITIONAL_MARKET_FEE.address, t.lockUntilHeight, t.expiresHeight]));
|
||||
const custom = fixture({ hostFeeAddress: '8'.repeat(95) }); // Syntax-only candidate, no wallet/RPC claim.
|
||||
assert.notEqual(saleId(custom.terms), saleId({ ...custom.terms, hostFeeAddress: undefined }));
|
||||
assert.equal(apply(custom.state, [custom.lock]).sales[saleId(custom.terms)].terms.hostFeeAddress, '8'.repeat(95));
|
||||
assert.throws(() => apply(custom.state, [{ ...custom.lock, terms: { ...custom.terms, hostFeeAddress: ADDITIONAL_MARKET_FEE.address } }]), /both trader/);
|
||||
assert.throws(() => apply(custom.state, [{ ...custom.lock, terms: { ...custom.terms, hostFeeAddress: undefined } }]), /both trader/);
|
||||
});
|
||||
|
||||
test('locked cards cannot escape through free transfers or any leg of an atomic trade', () => {
|
||||
const f = fixture(), locked = apply(f.state, [f.lock]);
|
||||
assert.throws(() => apply(locked, [gift(1)]), /locked/);
|
||||
@@ -206,7 +219,7 @@ test('candidate drafts from real sandbox reservations without signing, changing
|
||||
assert.equal(market.info().nftSettlement, false);
|
||||
assert.throws(() => termsForCustodyOrder({ ...order, authorAtomicXmr: '1' }, context, options), /allocations/);
|
||||
assert.throws(() => termsForCustodyOrder({ ...order, status: 'cancelled' }, context, options), /awaiting-lock/);
|
||||
assert.throws(() => termsForCustodyOrder({ ...order, hostFeeAddress: 'different-recipient' }, context, options), /terms extension/);
|
||||
assert.throws(() => termsForCustodyOrder({ ...order, hostFeeAddress: 'different-recipient' }, context, options));
|
||||
});
|
||||
|
||||
test('enumerated adversarial histories preserve exclusivity and deterministic replay across snapshot restores', () => {
|
||||
|
||||
Reference in New Issue
Block a user