Skip to main content

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: [{
        instrument_id: 'US09311A1007',
        quantity: '12000000',
        direction: 'deliver',
        chain_id: 11155111,
      }],
      templateSlug: 'dvp-bilateral',
      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

The submit function accepts a SubmitInstructionInput:
PropertyTypeRequiredDescription
rolestringYesYour role: "seller" or "buyer".
partyInstructionPartyInputYesYour party details.
legsInstructionLegInput[]YesWhat you’re delivering.
templateSlugstringYesThe settlement template to use.
timeoutAtstringYesISO 8601 datetime for settlement timeout.
tradeReferencestringNoExisting trade reference to match. Omit for new trade.
feeMode"seller_pays" | "buyer_pays" | "split"NoFee mode override.

InstructionPartyInput

PropertyTypeRequiredDescription
external_referencestringYesYour internal account or entity ID.
namestringNoDisplay name for the party.
wallet_addressstringYesOn-chain wallet address (for compliance screening).
chain_idnumberNoBlockchain network for the wallet.

InstructionLegInput

PropertyTypeRequiredDescription
instrument_idstringYesToken address, ISIN, or currency code.
quantitystringYesAmount to deliver (as string for precision).
direction"deliver" | "receive"YesUsually "deliver" (what you’re sending).
leg_typestringNoDefaults to "asset_delivery".
chain_idnumberNoBlockchain network for this leg.
token_standardstringNoe.g., "ERC-20", "ERC-3643".

Return Type

interface UseSubmitInstructionResult {
  submit: (input: SubmitInstructionInput) => Promise<InstructionResult>;
  result: InstructionResult | null;
  isSubmitting: boolean;
  error: string | null;
  reset: () => void;
}
PropertyTypeDescription
submitfunctionSubmit the instruction. Returns the result and throws on error.
resultInstructionResult | nullResult of the last submission.
isSubmittingbooleantrue while the submission is in progress.
errorstring | nullError message from the last submission.
reset() => voidClear result and error for a new submission.

InstructionResult

PropertyTypeDescription
idstringThe instruction UUID.
tradeReferencestringThe trade reference (generated if not provided).
statusstring"pending_match" or "matched".
settlementIdstring | nullSettlement ID if matched, null if pending.
rolestringThe role you submitted as.
createdAtstringISO 8601 creation timestamp.

Bilateral Flow

The bilateral settlement flow works in two steps:
  1. First party submits - Gets status: "pending_match" and a trade reference
  2. 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-...'