@atomiqlabs/sdk
Version:
atomiq labs SDK for cross-chain swaps between smart chains and bitcoin
98 lines (95 loc) • 4.05 kB
text/typescript
import {
SwapExecutionAction,
SwapExecutionActionSendToAddress,
SwapExecutionActionSignPSBT,
SwapExecutionActionSignSmartChainTx,
SwapExecutionActionWait
} from "../types/SwapExecutionAction";
import {ApiAmount, toApiAmount} from "./ApiTypes";
/**
* Strips non-serializable fields (functions, complex objects) from SwapExecutionAction types.
* Uses key-remapping to truly omit function keys from the resulting type.
*
* - SignSmartChainTransaction: functions removed, txs → string[]
* - SignPSBT: functions removed, txs[].psbt (Transaction object) omitted
* - SendToAddress: functions removed, txs[].amount (TokenAmount) → ApiAmount
* - Wait: functions removed, data fields kept as-is
*
* @category API
*/
export type SerializedAction<T extends SwapExecutionAction> =
T["type"] extends "SignSmartChainTransaction" ? {
[K in keyof T as T[K] extends Function ? never : K]:
K extends "txs" ? string[] : T[K]
} :
T["type"] extends "SignPSBT" ? {
[K in keyof T as T[K] extends Function ? never : K]:
K extends "txs" ? (T extends { txs: (infer U)[] }
? Omit<U, "psbt">[] : never) : T[K]
} :
T["type"] extends "SendToAddress" ? {
[K in keyof T as T[K] extends Function ? never : K]:
K extends "txs" ? (T extends { txs: (infer U)[] }
? (Omit<U, "amount"> & { amount: ApiAmount })[] : never) : T[K]
} : {
[K in keyof T as T[K] extends Function ? never : K]: T[K]
};
/**
* Runtime serializer that strips non-serializable fields from a SwapExecutionAction.
* Matches the compile-time SerializedAction<T> type.
*
* @param action The swap execution action to serialize
* @param txSerializer Optional chain-specific transaction serializer for SignSmartChainTransaction actions.
* Accepts the chain identifier and raw transaction, returns the serialized string.
* Falls back to JSON.stringify if not provided.
*
* @category API
*/
export async function serializeAction(
action: SwapExecutionAction,
txSerializer?: (chainId: string, tx: any) => Promise<string>
): Promise<SerializedAction<SwapExecutionAction>> {
switch (action.type) {
case "SendToAddress": {
const {waitForTransactions, ...rest} = action as SwapExecutionActionSendToAddress<boolean>;
return {
...rest,
txs: rest.txs.map(tx => ({
type: tx.type,
address: tx.address,
hyperlink: tx.hyperlink,
amount: toApiAmount(tx.amount)
}))
} as unknown as SerializedAction<SwapExecutionAction>;
}
case "SignPSBT": {
const {submitPsbt, txs, ...rest} = action as SwapExecutionActionSignPSBT<"FUNDED_PSBT" | "RAW_PSBT">;
return {
...rest,
txs: txs.map(tx => {
const {psbt, ...txRest} = tx;
return txRest;
})
} as unknown as SerializedAction<SwapExecutionAction>;
}
case "SignSmartChainTransaction": {
const {submitTransactions, ...rest} = action as SwapExecutionActionSignSmartChainTx;
return {
...rest,
txs: await Promise.all(rest.txs.map(tx =>
txSerializer != null
? txSerializer(rest.chain, tx)
: Promise.resolve(JSON.stringify(tx))
))
} as unknown as SerializedAction<SwapExecutionAction>;
}
case "Wait": {
const {wait, ...rest} = action as SwapExecutionActionWait;
return rest as unknown as SerializedAction<SwapExecutionAction>;
}
default: {
const _exhaustive: never = action;
throw new Error(`Unknown action type: ${(_exhaustive as any).type}`);
}
}
}