Import
import { useSubmitInstruction } from '@keystoneos/react';
Usage
function TradeForm() {
const { submit, result, isSubmitting, error, reset } = useSubmitInstruction();
const handleSubmit = async () => {
const instruction = await submit({
role: 'seller',
party: {
external_reference: 'KSFI-II-4401',
name: 'Securitize Fund I',
wallet_address: '0x1234...abcd',
},
legs: [
{
leg_type: 'asset_delivery',
instrument_id: '0x6B17...5678', // token contract address
quantity: '12000000',
direction: 'deliver', // seller delivers asset
chain_id: 11155111,
},
{
leg_type: 'payment',
instrument_id: '0xA0b8...6EB48', // USDC contract address
quantity: '12120000000000',
direction: 'receive', // seller receives payment
chain_id: 11155111,
},
],
templateSlug: 'cross_platform_dvp',
timeoutAt: new Date(Date.now() + 86400000).toISOString(),
});
if (instruction.status === 'matched') {
router.push(`/settlements/${instruction.settlementId}`);
}
};
if (result?.status === 'pending_match') {
return (
<div>
<p>Waiting for counterparty.</p>
<p>Trade reference: <code>{result.tradeReference}</code></p>
<button onClick={reset}>Submit Another</button>
</div>
);
}
return (
<form onSubmit={handleSubmit}>
{/* Your form fields */}
<button type="submit" disabled={isSubmitting}>
{isSubmitting ? 'Submitting...' : 'Submit Instruction'}
</button>
{error && <p className="error">{error}</p>}
</form>
);
}
Parameters
Thesubmit function accepts a SubmitInstructionInput:
| Property | Type | Required | Description |
|---|---|---|---|
role | string | Yes | Your role: "seller" or "buyer". |
party | InstructionPartyInput | Yes | Your party details. |
legs | InstructionLegInput[] | Yes | What you’re delivering. |
templateSlug | string | Yes | The settlement template to use. |
timeoutAt | string | Yes | ISO 8601 datetime for settlement timeout. |
tradeReference | string | No | Existing trade reference to match. Omit for new trade. |
feeMode | "seller_pays" | "buyer_pays" | "split" | No | Fee mode override. |
InstructionPartyInput
| Property | Type | Required | Description |
|---|---|---|---|
external_reference | string | Yes | Your internal account or entity ID. |
name | string | No | Display name for the party. |
wallet_address | string | Yes | On-chain wallet address (for compliance screening). |
InstructionLegInput
Each DvP instruction should include two legs:asset_delivery and payment. The direction is derived from your role - sellers deliver assets and receive payment, buyers deliver payment and receive assets.
| Property | Type | Required | Description |
|---|---|---|---|
leg_type | string | Yes | "asset_delivery" or "payment". |
instrument_id | string | Yes | Token contract address (e.g., 0x...). |
quantity | string | Yes | Amount to deliver (as string for precision). |
direction | "deliver" | "receive" | Yes | Derived from role: seller delivers assets, buyer delivers payment. |
chain_id | number | No | Blockchain network for this leg. |
token_standard | string | No | e.g., "ERC-20", "ERC-3643". |
Return Type
interface UseSubmitInstructionResult {
submit: (input: SubmitInstructionInput) => Promise<InstructionResult>;
result: InstructionResult | null;
isSubmitting: boolean;
error: string | null;
reset: () => void;
}
| Property | Type | Description |
|---|---|---|
submit | function | Submit the instruction. Returns the result and throws on error. |
result | InstructionResult | null | Result of the last submission. |
isSubmitting | boolean | true while the submission is in progress. |
error | string | null | Error message from the last submission. |
reset | () => void | Clear result and error for a new submission. |
InstructionResult
| Property | Type | Description |
|---|---|---|
id | string | The instruction UUID. |
tradeReference | string | The trade reference (generated if not provided). |
status | string | "pending_match" or "matched". |
settlementId | string | null | Settlement ID if matched, null if pending. |
role | string | The role you submitted as. |
createdAt | string | ISO 8601 creation timestamp. |
Bilateral Flow
The bilateral settlement flow works in two steps:- First party submits - Gets
status: "pending_match"and a trade reference - Second party submits with same trade reference - Gets
status: "matched"and a settlement ID
// Seller submits first (no trade reference)
const sellerResult = await submit({ role: 'seller', ... });
// sellerResult.status === 'pending_match'
// sellerResult.tradeReference === 'KS-abc12345'
// Share tradeReference with buyer out-of-band...
// Buyer submits with the same trade reference
const buyerResult = await submit({
role: 'buyer',
tradeReference: 'KS-abc12345',
...
});
// buyerResult.status === 'matched'
// buyerResult.settlementId === '550e8400-...'