There is no official SDK for the Message Bus API yet. However, the intents-sdk can be used to create and sign intents.
This page shows how to respond to quote requests as a market maker using TypeScript.
Overview
When you receive a quote request from the Message Bus, you need to:
- Calculate your proposed amount
- Generate a valid nonce
- Build and sign a
token_diff intent
- Send the response back to the Message Bus
Generating nonces
Nonces must include the current contract salt and be unique. Learn more about nonce structure.
import { VersionedNonceBuilder } from "@defuse-protocol/intents-sdk";
const generateNonce = async (deadline: Date): Promise<string> => {
// Get your NEAR account instance
const account = await getAccount();
// Fetch the current salt from the contract
const salt_hex = await account.viewFunction({
contractId: "intents.near",
methodName: "current_salt",
});
const salt_bytes = Uint8Array.from(Buffer.from(salt_hex, "hex"));
const versionedNonce = VersionedNonceBuilder.encodeNonce(salt_bytes, deadline);
// Optional: verify nonce hasn't been used
if (await isNonceUsed(versionedNonce)) {
return generateNonce(deadline);
}
return versionedNonce;
};
const isNonceUsed = async (nonce: string): Promise<boolean> => {
const account = await getAccount();
return await account.viewFunction({
contractId: "intents.near",
methodName: "is_nonce_used",
args: {
account_id: account.accountId,
nonce,
},
});
};
Building the intent payload
The params object matches what you receive from the relay in the "quote" event:
interface QuoteParams {
defuse_asset_identifier_in: string;
defuse_asset_identifier_out: string;
exact_amount_in: string | undefined;
exact_amount_out: string | undefined;
min_deadline_ms: number;
}
Build the intent payload:
const getIntentPayload = async (
sdk: IntentsSDK,
deadline: Date,
params: QuoteParams,
amount: string
) => {
const nonce = await generateNonce(deadline);
return await sdk
.intentBuilder()
.setDeadline(deadline)
.setNonce(nonce)
.addIntent({
intent: "token_diff",
diff: {
// Token you're receiving (positive = incoming)
[params.defuse_asset_identifier_in]: params.exact_amount_in
? params.exact_amount_in
: amount,
// Token you're giving (negative = outgoing)
[params.defuse_asset_identifier_out]: `-${
params.exact_amount_out ? params.exact_amount_out : amount
}`,
},
})
.build();
};
Complete example
Putting it all together to respond to a quote request:
import { IntentsSDK, createIntentSignerNearKeyPair } from "@defuse-protocol/intents-sdk";
import bs58 from "bs58";
// Initialize the SDK with your signer
const intentSigner = createIntentSignerNearKeyPair({
signer, // Your NEAR signer
accountId, // Your NEAR account ID
});
const sdk = new IntentsSDK({
env: "production",
referral: "your_referral",
intentSigner: intentSigner,
});
// When you receive a quote request...
const handleQuoteRequest = async (
quote_id: string,
params: QuoteParams
) => {
// 1. Calculate your proposed amount based on your pricing logic
const amount = calculateAmount(params);
// 2. Set deadline (e.g., 5 minutes from now)
const deadline = new Date(Date.now() + 5 * 60 * 1000);
// 3. Build the intent payload
const payload = await getIntentPayload(sdk, deadline, params, amount);
// 4. Sign the payload
const signedPayload = await intentSigner.signIntent(payload);
// 5. Build the response
const response = {
quote_id,
quote_output: params.exact_amount_in
? { amount_out: amount }
: { amount_in: amount },
signed_data: signedPayload,
};
// 6. Send via WebSocket
ws.send(JSON.stringify({
jsonrpc: "2.0",
id: Date.now(),
method: "quote_response",
params: [response],
}));
};
WebSocket connection example
const ws = new WebSocket("wss://solver-relay-v2.chaindefuser.com/ws");
ws.onopen = () => {
// Subscribe to quote requests
ws.send(JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "subscribe",
params: ["quote"],
}));
// Subscribe to quote status updates
ws.send(JSON.stringify({
jsonrpc: "2.0",
id: 2,
method: "subscribe",
params: ["quote_status"],
}));
};
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.params?.quote_id) {
// Handle quote request
handleQuoteRequest(data.params.quote_id, data.params);
} else if (data.params?.tx_hash) {
// Handle settlement notification
console.log(`Quote ${data.params.quote_hash} settled: ${data.params.tx_hash}`);
}
};
TokenDiff intent structure
The token_diff intent expresses what tokens you’re willing to give and receive:
{
intent: "token_diff",
diff: {
// Positive values = tokens you receive
"nep141:usdc.near": "1000",
// Negative values = tokens you give
"nep141:usdt.near": "-1000",
}
}
Ensure your account has sufficient balance in the Verifier contract for the tokens you’re offering. The intent will fail if you don’t have enough tokens.