Webhook
Before you begin
We recommend reading the Webhook Configuration page first.
Overview
Multi-party computation (MPC) operations involve communication between several participants. This collaboration occurs over multiple rounds of communication, creating an asynchronous process.
To facilitate this communication, your system needs to expose the POST /api/webhook
REST API endpoint to receive webhook notifications generated by Fireblocks. Each notification carries essential data to the Software Development Kit (SDK), which handles the asynchronous process.
Webhook Controller
The POST /api/webhook
endpoint is controlled by the /src/controllers/webhook.controller.ts/WebhookController
controller:
async handle(req: Request, res: Response, next: NextFunction) {
try {
const { type, timestamp } = req.body;
console.log(
`received webhook, type: ${type} timestamp: ${timestamp} body: ${JSON.stringify(
req.body,
)} `,
);
switch (type) {
case "TRANSACTION_CREATED": {
const { data } = req.body as ITransactionCreatedMessagePayload;
const { id, status } = data;
await patchTransactionAmountUsd(data, this.clients.cmc);
await handleTransactionCreated(id, status, data);
return res.status(200).send("ok");
}
case "TRANSACTION_STATUS_UPDATED": {
const { data } = req.body as ITransactionCreatedMessagePayload;
const { id, status } = data;
await patchTransactionAmountUsd(data, this.clients.cmc);
await handleTransactionStatusUpdated(id, status, data);
return res.status(200).send("ok");
}
case "ON_NEW_EXTERNAL_TRANSACTION":
case "VAULT_ACCOUNT_ADDED":
case "VAULT_WALLET_READY":
case "UNMANAGED_WALLET_ADDED":
case "UNMANAGED_WALLET_REMOVED":
case "THIRD_PARTY_ACCOUNT_ADDED":
case "NETWORK_CONNECTION_ADDED":
case "NETWORK_CONNECTION_REMOVED":
case "CONFIG_CHANGE_REQUEST_STATUS":
case "TRANSACTION_APPROVAL_STATUS_UPDATED":
case "VAULT_ACCOUNT_ASSET_ADDED":
case "EXTERNAL_WALLET_ASSET_ADDED":
case "INTERNAL_WALLET_ASSET_ADDED":
return res.status(200).send("ok");
default:
console.error(`unknown webhook type ${type}`);
return res.status(400).send("error");
}
} catch (err) {
return next(err);
}
}
Webhook Signature Validation
The ncw-backend-demo/src/middleware/webhook.ts
middleware validates the webhook signature:
export const validateWebhook =
(publicKey: string) => (req: Request, res: Response, next: NextFunction) => {
const message = JSON.stringify(req.body);
const signature = req.headers["fireblocks-signature"];
if (typeof signature !== "string") {
next(new Error(`Invalid signature`));
return;
}
const verifier = crypto.createVerify("RSA-SHA512");
verifier.write(message);
verifier.end();
const isVerified = verifier.verify(publicKey, signature, "base64");
if (isVerified) {
next();
} else {
next(new Error(`Invalid signature`));
}
};
Webhook Route
The /src/routes/webhook.route.ts
route defines the webhook route:
export function createWebhook(clients: Clients, publicKey: string) {
const contoller = new WebhookController(clients);
const route = Router({ mergeParams: true });
route.post("/", validateWebhook(publicKey), contoller.handle.bind(contoller));
return route;
}
Updated 10 months ago