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.