Manage webhooks
Check the webhook origin
Option 1 - Verify the signature of the event
The private key is used to sign the event from the blockchain before we send it to the webhook.
Get public key endpoint
Public keys rotate and so may change over time, but they can be cached because they don't change often and old keys remain valid for some time.
To obtain the public key, call the endpoint: /webhook/getEventSignaturePublicKey
In production: https://api.arianee.com/webhook/getEventSignaturePublicKey
Result:
{
publicKeys: ['here_your_public_key']
}
Check on your side the webhook origin
run npm i elliptic
const elliptic = require('elliptic');
const ec = new elliptic.ec('ed25519');
/**
* This method will verify if the signature is valid
* @param event
* @param signature
* @param publicKey
* @returns
*/
export const verifySignature = (event, signature, publicKey) => {
try {
const key = ec.keyFromPublic(publicKey, 'hex');
return key.verify(JSON.stringify(event), signature);
} catch (e) {
return false;
}
};
Option 2 - Endpoint to check the signature
Endpoint:
/webhook/verifyEventSignature
Body parameters:
{
"event": {
"name": "smartAssetContract.Hydrated",
"tokenId": "756328716",
"chainId": 77,
"network": "testnet",
"blocknumber": 28644254,
"raw": {
"address": "0x512C1FCF401133680f373a386F3f752b98070BC5",
"blockHash": "0xa8bb23115735290956e9d18b6463dd0f179e2340f49586371064511f7c9d05f6",
"blockNumber": 28644254,
"logIndex": 0,
"removed": false,
"transactionHash": "0x198431af98024ec958bd4561541720ad64026263d7e66abcdf416d09f36be12c",
"transactionIndex": 0,
"transactionLogIndex": "0x0",
"id": "log_060d9237",
"returnValues": {
"0": "0x3257d9f2D793Bd437E34C2312F888D8ce11c1Ea0",
"1": "0x08E3625273a9eAA4F466ecb701899BF11F7E3E90",
"2": "756328716",
"_from": "0x3257d9f2D793Bd437E34C2312F888D8ce11c1Ea0",
"_to": "0x08E3625273a9eAA4F466ecb701899BF11F7E3E90",
"_tokenId": "756328716"
},
"event": "Transfer",
"signature": "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"raw": {
"data": "0x",
"topics": [
"0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef",
"0x0000000000000000000000003257d9f2d793bd437e34c2312f888d8ce11c1ea0",
"0x00000000000000000000000008e3625273a9eaa4f466ecb701899bf11f7e3e90",
"0x000000000000000000000000000000000000000000000000000000002d14a90c"
]
}
},
"issuer": "0x3257d9f2D793Bd437E34C2312F888D8ce11c1Ea0",
"owner": "0x08E3625273a9eAA4F466ecb701899BF11F7E3E90",
"previousOwner": "0x3257d9f2D793Bd437E34C2312F888D8ce11c1Ea0"
},
"signature": "veryCoolSignature"
}
Result:
{
valid: true / false,
publicKey: 'thePublicKey'
}
๐ Our team recommendations
First in - first out order
With webhooks infrastructure, we cannot guarantee FIFO broadcasting. Note it is rare that the events are not broadcasted in the FIFO order and we guarantee that the events are delivered at least once.
The key phrase here is at least โ because you will eventually get the same events multiple times. Your application needs to be built to handle those scenarios.
Potential solutions when receiving events multiple times
- To treat all the webhook calls with the best accuracy, create aย
processed_webhooks
table with a unique constraint on the ID. - If the same event (say a transfer) is sent multiple times over some time, each time you receive a transfer event for a specific owner of a specific NFT, store the block number in a database. So if you receive an event with a lower block number compared to the last stored block number for the same owner of the same NFT, you can ignore the event as you have stored already the most recent data.
Updated about 1 year ago