|
| 1 | +/** |
| 2 | + * @prettier |
| 3 | + */ |
| 4 | +import * as t from 'io-ts'; |
| 5 | +import { EIP1559Params, MemoParams, TokenEnablement } from '../v2/sendmany'; |
| 6 | + |
| 7 | +/** |
| 8 | + * Recipient entry accepted by the sendMany / sendCoins / consolidateAccount |
| 9 | + * flows that feed `createTSSSendParams`. |
| 10 | + */ |
| 11 | +const Recipient = t.intersection([ |
| 12 | + t.type({ |
| 13 | + address: t.string, |
| 14 | + amount: t.union([t.number, t.string]), |
| 15 | + }), |
| 16 | + t.partial({ |
| 17 | + feeLimit: t.string, |
| 18 | + tokenName: t.string, |
| 19 | + // `data` and `tokenData` are passed through to wallet.send*; their strict |
| 20 | + // shapes live in the route-level codecs. We accept `any` here to mirror |
| 21 | + // that precedent and preserve existing behaviour. |
| 22 | + data: t.any, |
| 23 | + tokenData: t.any, |
| 24 | + memo: t.union([t.string, MemoParams]), |
| 25 | + }), |
| 26 | +]); |
| 27 | + |
| 28 | +/** |
| 29 | + * Request body accepted by `createTSSSendParams` in clientRoutes. |
| 30 | + * |
| 31 | + * The helper is called from three route handlers, all of which already |
| 32 | + * validate their own request bodies at the route layer: |
| 33 | + * - express.wallet.signtxtss (walletTxSignTSS) |
| 34 | + * - express.wallet.consolidateaccount (consolidateAccount) |
| 35 | + * - express.wallet.sendmany / express.wallet.sendcoins (sendmany / sendCoins) |
| 36 | + * |
| 37 | + * This codec is the helper's own contract: the union of fields any of those |
| 38 | + * callers may place into `req.body` before it is spread into the TSS signing |
| 39 | + * params. Every field is optional because each caller only uses a subset. |
| 40 | + * |
| 41 | + * Unknown fields are preserved by io-ts `t.partial` decoding, so extra |
| 42 | + * coin-specific or forward-compatible fields flow through unchanged. |
| 43 | + */ |
| 44 | +export const CreateTSSSendParamsBody = t.partial({ |
| 45 | + // Auth / signing material |
| 46 | + walletPassphrase: t.string, |
| 47 | + xprv: t.string, |
| 48 | + prv: t.string, |
| 49 | + pubs: t.array(t.string), |
| 50 | + cosignerPub: t.string, |
| 51 | + isLastSignature: t.boolean, |
| 52 | + otp: t.string, |
| 53 | + derivationSeed: t.string, |
| 54 | + |
| 55 | + // TSS / transaction request / prebuild |
| 56 | + txRequestId: t.string, |
| 57 | + // `txPrebuild` / `prebuildTx` / verification blobs are passed through to the |
| 58 | + // wallet SDK, which owns their strict shapes. Mirrors the route-level |
| 59 | + // codecs (see sendmany / consolidateAccount) which also use `t.any`. |
| 60 | + txPrebuild: t.any, |
| 61 | + prebuildTx: t.union([t.string, t.any]), |
| 62 | + apiVersion: t.string, |
| 63 | + multisigTypeVersion: t.literal('MPCv2'), |
| 64 | + signingStep: t.union([t.literal('signerNonce'), t.literal('signerSignature'), t.literal('cosignerNonce')]), |
| 65 | + |
| 66 | + // Recipients / addresses / amounts |
| 67 | + recipients: t.array(Recipient), |
| 68 | + address: t.string, |
| 69 | + amount: t.union([t.number, t.string]), |
| 70 | + messages: t.array( |
| 71 | + t.type({ |
| 72 | + address: t.string, |
| 73 | + message: t.string, |
| 74 | + }) |
| 75 | + ), |
| 76 | + senderAddress: t.string, |
| 77 | + senderWalletId: t.string, |
| 78 | + receiveAddress: t.string, |
| 79 | + changeAddress: t.string, |
| 80 | + closeRemainderTo: t.string, |
| 81 | + consolidateAddresses: t.array(t.string), |
| 82 | + |
| 83 | + // Fees / gas |
| 84 | + feeRate: t.union([t.number, t.string]), |
| 85 | + feeLimit: t.string, |
| 86 | + feeMultiplier: t.number, |
| 87 | + maxFeeRate: t.number, |
| 88 | + numBlocks: t.number, |
| 89 | + gasLimit: t.union([t.string, t.number]), |
| 90 | + gasPrice: t.union([t.string, t.number]), |
| 91 | + eip1559: EIP1559Params, |
| 92 | + |
| 93 | + // Unspents / confirmation policy |
| 94 | + minConfirms: t.number, |
| 95 | + enforceMinConfirmsForChange: t.boolean, |
| 96 | + targetWalletUnspents: t.number, |
| 97 | + minValue: t.union([t.number, t.string]), |
| 98 | + maxValue: t.union([t.number, t.string]), |
| 99 | + noSplitChange: t.boolean, |
| 100 | + unspents: t.array(t.string), |
| 101 | + allowExternalChangeAddress: t.boolean, |
| 102 | + allowNonSegwitSigningWithoutPrevTx: t.boolean, |
| 103 | + |
| 104 | + // Metadata / tracking |
| 105 | + sequenceId: t.union([t.string, t.number]), |
| 106 | + comment: t.string, |
| 107 | + message: t.string, |
| 108 | + memo: MemoParams, |
| 109 | + transferId: t.number, |
| 110 | + custodianTransactionId: t.string, |
| 111 | + tokenName: t.string, |
| 112 | + type: t.string, |
| 113 | + addressType: t.string, |
| 114 | + changeAddressType: t.string, |
| 115 | + txFormat: t.union([t.literal('legacy'), t.literal('psbt'), t.literal('psbt-lite')]), |
| 116 | + keepAlive: t.boolean, |
| 117 | + instant: t.boolean, |
| 118 | + hop: t.boolean, |
| 119 | + isTss: t.boolean, |
| 120 | + isTestTransaction: t.boolean, |
| 121 | + isEvmBasedCrossChainRecovery: t.boolean, |
| 122 | + preview: t.boolean, |
| 123 | + offlineVerification: t.boolean, |
| 124 | + data: t.string, |
| 125 | + expireTime: t.number, |
| 126 | + |
| 127 | + // Ledger / block validity windows |
| 128 | + lastLedgerSequence: t.number, |
| 129 | + ledgerSequenceDelta: t.number, |
| 130 | + validFromBlock: t.number, |
| 131 | + validToBlock: t.number, |
| 132 | + |
| 133 | + // Token / NFT / enablement |
| 134 | + nftCollectionId: t.string, |
| 135 | + nftId: t.string, |
| 136 | + enableTokens: t.array(TokenEnablement), |
| 137 | + |
| 138 | + // Misc account-based / enterprise fields |
| 139 | + nonce: t.string, |
| 140 | + nonParticipation: t.boolean, |
| 141 | + walletContractAddress: t.string, |
| 142 | + idfSignedTimestamp: t.string, |
| 143 | + idfUserId: t.string, |
| 144 | + idfVersion: t.number, |
| 145 | + lowFeeTxid: t.string, |
| 146 | + reservation: t.partial({ |
| 147 | + expireTime: t.string, |
| 148 | + pendingApprovalId: t.string, |
| 149 | + }), |
| 150 | + |
| 151 | + // Verification |
| 152 | + verifyTxParams: t.any, |
| 153 | + verification: t.any, |
| 154 | + |
| 155 | + // Chain-specific opaque blobs (validated at the route layer when present) |
| 156 | + solInstructions: t.any, |
| 157 | + solVersionedTransactionData: t.any, |
| 158 | + aptosCustomTransactionParams: t.any, |
| 159 | +}); |
| 160 | + |
| 161 | +export type CreateTSSSendParamsBody = t.TypeOf<typeof CreateTSSSendParamsBody>; |
0 commit comments