Skip to content

Latest commit

 

History

History
376 lines (300 loc) · 16.8 KB

using-notify.md

File metadata and controls

376 lines (300 loc) · 16.8 KB
description
Everything you need to know for using Alchemy Notify in your decentralized Ethereum app. Get notifications for external, internal, and token transfers, mined and dropped transactions, and gas price.

🔔 Using Alchemy Notify/Webhooks

**Looking for the instructions on how to create webhooks programmatically? Check out the page below! **

{% content-ref url="../documentation/enhanced-apis/notify-api.md" %} notify-api.md {% endcontent-ref %}

Alchemy Notify works by using webhooks, a way for you to subscribe to events that occur on your application. This guide will walk through what webhooks are and how you can use them in order to get started with Alchemy Notify.

What are Webhooks?

Webhooks are a way for users to receive notifications when an event occurs on your application. Rather than continuously polling the server to check if the state has changed, webhooks provide information to you as it becomes available, which is a lot more efficient and beneficial for developers. Webhooks work by registering a URL to send notifications to once certain events occur.

Webhooks are typically used to connect two different applications. One application is the "sender," which subscribes to events and sends them off to the the second "receiver" application, which takes actions based upon that received data. When an event occurs on the sender application it sends that data to the webhook URL of the receiver application. The receiver application can then send a callback message, with an HTTP status code to let the sender know the data was received successfully or not.

You can think of webhook notifications just like SMS notifications. The entity sending the message has your registered phone number and they send a specific message payload to that phone number. You then have the ability to respond confirming you have received it, creating a two-way communication stream.

{% hint style="info" %}

Webhooks vs. WebSockets:

The difference between webhooks and WebSockets is that webhooks can only facilitate one-way communication between two services, while WebSockets can facilitate two-way communication between a user and a service, recognizing events and displaying them to the user as they occur. {% endhint %}

Types of Webhooks

Alchemy offers four different types of webhooks each described below.

1. Mined Transactions

The Mined Transaction Webhook is used to notify your app anytime a transaction gets successfully mined that was sent through your Alchemy API key. This is extremely useful if you want to notify customers the moment their transactions goes through.

Example Response

{
  "app": "Demo", 
  "network": "MAINNET",
  "webhookType": "MINED_TRANSACTION",
  "fullTransaction": {
    "hash": "0x5a4bf6970980a9381e6d6c78d96ab278035bbff58c383ffe96a0a2bbc7c02a4b",
    "blockHash": "0xaa20f7bde5be60603f11a45fc4923aab7552be775403fc00c2e6b805e6297dbe",
    "blockNumber": "0x989680",
    "from": "0x8a9d69aa686fa0f9bbdec21294f67d4d9cfb4a3e",
    "gas": "0x5208",
    "gasPrice": "0x165a0bc00",
    "input": "0x",
    "nonce": "0x2f",
    "r": "0x575d26288c1e3aa63e80eea927f54d5ad587ad795ad830149837258344a87d7c",
    "s": "0x25f5a3abf22f5b8ef6ed307a76e670f0c9fb4a71fab2621fce8b52da2ab8fe82",
    "to": "0xd69b8ff1888e78d9c337c2f2e6b3bf3e7357800e",
    "transactionIndex": "0x66",
    "v": "0x1c",
    "value": "0x1bc16d674ec80000"
  },
  "timestamp": "2020-07-29T00:29:18.414Z"
}

**2. **Dropped Transactions

The Dropped Transactions Webhook is used to notify your app anytime a transaction gets dropped that was sent through your Alchemy API key.

Example Response

{
  "app": "Alchemy Mainnet",
  "network": "MAINNET",
  "webhookType": "DROPPED_TRANSACTION",
  "timestamp": "2020-06-08T22:12:57.126Z",
  "fullTransaction": {
    "hash": "0x5a4bf6970980a9381e6d6c78d96ab278035bbff58c383ffe96a0a2bbc7c02a4b",
    "blockHash": null,
    "blockNumber": null,
    "from": "0x8a9d69aa686fa0f9bbdec21294f67d4d9cfb4a3e",
    "gas": "0x5208",
    "gasPrice": "0x165a0bc00",
    "input": "0x",
    "nonce": "0x2f",
    "r": "0x575d26288c1e3aa63e80eea927f54d5ad587ad795ad830149837258344a87d7c",
    "s": "0x25f5a3abf22f5b8ef6ed307a76e670f0c9fb4a71fab2621fce8b52da2ab8fe82",
    "to": "0xd69b8ff1888e78d9c337c2f2e6b3bf3e7357800e",
    "transactionIndex": null,
    "v": "0x1c",
    "value": "0x1bc16d674ec80000"
  }
}

**3. **Address Activity

The Address Activity Webhook allows you to track all ETH, ERC20 and ERC721 external and internal transfer events for as many Ethereum addresses as you'd like (regardless if the transactions were sent through Alchemy or not). This provides your app with real-time state changes when an address sends or receives tokens.

{% hint style="info" %} If you are looking for historical activity, check out the Transfers API! {% endhint %}

Types of Transfers

There are three main types of transfers that are captured when receiving an address activity response.

1. External Eth Transfers

These are top level Ethereum transactions that occur with a from address being an external (user created) address. External addresses have private keys and are accessed by users.

2. Token Transfers (ERC20 or ERC721)

These are event logs for any ERC20 and ERC721 transfer.

3. Internal Eth Transfers

These are transfers that occur where the fromAddress is an internal (smart contract) address. (ex: a smart contract calling another smart contract or smart contract calling another external address).

{% hint style="warning" %} **NOTE: **Internal transfers are only available for mainnet, ropsten and kovan {% endhint %}

{% hint style="info" %} **NOTE: **For efficiency, we do not return internal transfers with 0 value as they don't provide useful information without digging deeper into the internal transaction itself. If you are interested in these type of events see our Trace API.

Additionally, we do not include any internal transfers with call typedelegatecall because although they have a _value _associated with them they do not actually transfer that value (see Appendix H of the Ethereum Yellow Paper if you're curious). We also do not include miner rewards as an internal transfer. {% endhint %}

Schema

  • category: external, internal, or token- label for the transfer
  • blockNum: the block where the transfer occurred (hex string).
  • fromAddress: from address of transfer (hex string).
  • toAddress: to address of transfer (hex string). null if contract creation.
  • value: converted asset transfer value as a number (raw value divided by contract decimal). null if erc721 transfer or contract decimal not available.
  • erc721TokenId: raw erc721 token id (hex string). null if not an erc721 token transfer
  • asset: ETH or the token's symbol. null if not defined in the contract and not available from other sources.
  • hash: transaction hash (hex string).
  • rawContract
    • value: raw transfer value (hex string). null if erc721 transfer
    • address: contract address (hex string). null if external or internal transfer
    • decimal: contract decimal (hex string). null if not defined in the contract and not available from other sources.
  • typeTraceAddress: the type of internal transfer (call, staticcall, create, suicide) followed by the trace address (ex. call_0_1).null if not internal transfer. (note you can use this as a unique id for internal transfers since they will have the same parent hash)

Example Response

{
  "app": "Test webhooks",
  "network": "MAINNET",
  "webhookType": "ADDRESS_ACTIVITY",
  "timestamp": null,
  "activity": [
    {
      "fromAddress": "0x7a250d5630b4cf539739df2c5dacb4c659f2488d",
      "toAddress": "0x9314941c11d6dee1d7bf93113eb74d4718949f3b",
      "blockNum": "0xbe09fb",
      "category": "token",
      "hash": "0x96bba899ebae1af0808421db6c2e78f78488ef4aa3f676f941ba72df10df3023",
      "value": 0.3727,
      "erc721TokenId": null,
      "asset": "WETH",
      "rawContract": {
        "rawValue": "0x000000000000000000000000000000000000000000000000052c18ace3c9c000",
        "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
        "decimals": 18
      },
      "typeTraceAddress": null
    },
    {
      "fromAddress": "0xca92a49187edce00ba235634b4ca13e89abb33fe",
      "toAddress": "0x9f5c880690e8a9dc7ce1142e304515eeb8b55e8f",
      "blockNum": "0x97c8c1",
      "category": "token",
      "hash": "0x5f07f0a4ebb894ac2e4d5f0e03b50bfa7e1933f3c7641795500c806f77d9e592",
      "value": null,
      "erc721TokenId": "0x1",
      "asset": "API",
      "rawContract": {
        "rawValue": "0x",
        "address": "0x4c4a07f737bf57f6632b6cab089b78f62385acae",
        "decimals": null
      }
      "typeTraceAddress": null
    },
    {
      "blockNum": "0xbe09fa",
      "hash": "0x1635135c035cd81320e444f4dd88296f408ee7305c3e07f7863e3142d017ec45",
      "fromAddress": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
      "toAddress": "0xe592427a0aece92de3edee1f18e0157c05861564",
      "value": 0.33974794305157613,
      "asset": "ETH",
      "category": "internal",
      "erc721TokenId": null,
      "typeTraceAddress": "call_1_1_0",
      "rawContract": {
        "rawValue": "0x4b706f442c2433c",
        "address": null,
        "decimals": 18
      }
    },
    {
      "fromAddress": "0x38f22e75642b91568ba9bdbf94c9c843b38f2721",
      "toAddress": "0x7a250d5630b4cf539739df2c5dacb4c659f2488d",
      "blockNum": "0xbe09fb",
      "hash": "0x9ff35291bcc0a1b359c1360c8a9f7eef0d7c48a1db5d0520aedebf2c8a8e3eb6",
      "category": "external",
      "value": 0.2,
      "erc721TokenId": null,
      "asset": "ETH",
      "rawContract": {
        "rawValue": "0x2c68af0bb140000",
        "address": null,
        "decimals": 18
      },
      "typeTraceAddress": null
    },
  ]
}

{% hint style="warning" %}

**HINT: Missing transactions? **

Double check that you are parsing the response payload correctly- remember, transactions are returned in a list! Transactions that are mined within the same block will be returned within the same "activity" list. {% endhint %}

4. Gas Price

The Gas Price Webhook allows you to receive a notification every minute when the Mainnet gas price rises above or drops below a certain threshold that you can select. It works by pulling the current gas prices from ETH Gas Station every minute.

Gas prices typically fall in a range, where a lower gas price means that the transaction will take longer to be mined, and a higher gas price means that the transaction will be mined more quickly. The Execution Speed metric allows you to specify a metric in that range that you would like to receive notifications, corresponding to ETH Gas Station's Price Type metric documented here. For example, selecting an Average Execution Speed means that you will receive notifications when a gas price typically mined in under 5 minutes rises above or drops below your selected threshold

Example Response

{
  "app": "Alchemy Mainnet",
  "network": "MAINNET",
  "timestamp": "2020-09-09T15:14:19.175Z",
  "gasPriceMetadata": {
    "fast": 160,
    "fastest": 167,
    "safeLow": 147,
    "average": 150,
    "block_time": 11.894736842105264,
    "blockNum": 10828228,
    "speed": 0.9968284026882861,
    "safeLowWait": 14.6,
    "avgWait": 3.9,
    "fastWait": 0.4,
    "fastestWait": 0.4
  }
}

Test Out Webhooks

There are many websites you can use to test out webhooks. For example, you can use https://webhook.site/ and copy your unique URL. Once you have the URL, you can test using the following steps:

  1. Navigate to your Notify dashboard
  2. Click "Create Webhook" on the webhook you want to test
  3. Specify which app you wish to add notifications to
  4. Paste in your unique URL and hit the "Test Webhook" button

You should then see the result updated on website: https://webhook.site/

How to Set Up Webhooks

Setting up a webhook is as simple as adding a new URL to your application. There are two primary ways to activate Alchemy Notify.

{% hint style="warning" %} **NOTE: **If you need to add over 10 addresses to the address activity webhook, we recommend adding them through an API call. See our Notify API Reference page for more information on this. {% endhint %}

1. Setting Up Webhooks from the Dashboard

Navigate to the Notify tab in your Alchemy Dashboard

  1. Determine which type of webhook you want to activate
  2. Click the "Create Webhook" button
  3. Specify which app you wish to add notifications to
  4. Add in your unique webhook URL, this can be any link that you want to receive requests at (your server, slack, etc.) **Note that the webhook payload might not **For instructions on how to set up Alchemy Notify programatically, check out the **always be compatible for 3rd party integrations. **
  5. Test out your webhook by hitting the "Test Webhook" button to ensure it works properly
  6. Hit "Create Webhook" and you should then see your webhook appear in the list!
  7. Check your endpoint to see responses rolling through!

2. Setting up Webhooks Programmatically

Notify API page:

{% content-ref url="../documentation/enhanced-apis/notify-api.md" %} notify-api.md {% endcontent-ref %}

Webhook Signature and Security

If you want to make your webhooks extra secure, you can verify that they originated from Alchemy by generating a HMAC SHA-256 hash code using your Authentication Token and request body.

1. Find your Authentication Token

Navigate to the top right corner of your Notify page to copy your "Auth Token".

2. Validate the signature received

Every outbound request will contain a hashed authentication signature in the header which is computed by concatenating your auth token and request body then generating a hash using the HMAC SHA256 hash algorithm.

In order to verify this signature came from Alchemy, you simply have to generate the HMAC SHA256 hash and compare it with the signature received.

Example Request Header

POST /yourWebhookServer/push HTTP/1.1
Content-Type: application/json;
X-Alchemy-Signature: your-hashed-signature

Example Signature Validation Function

{% tabs %} {% tab title="JavaScript" %}

function isValidSignature(request) {    
    const token = 'Auth token provided by Alchemy on the Webhook setup page';
    const headers = request.headers;
    const signature = headers['x-alchemy-signature']; // Lowercase for NodeJS
    const body = request.body;    
    const hmac = crypto.createHmac('sha256', token) // Create a HMAC SHA256 hash using the auth token
    hmac.update(JSON.stringify(body), 'utf8') // Update the token hash with the request body using utf8
    const digest = hmac.digest('hex');     
    return (signature === digest); // If signature equals your computed hash, return true
}

{% endtab %}

{% tab title="Python" %}

import hmac
import hashlib
import json
def isValidSignature(request):
    token = '<your token goes here>';
    headers = request['headers'];
    signature = headers['x-alchemy-signature']; 
    body = request['body'];
    string_body = json.dumps(body, separators=(',', ':'))
    
    digest = hmac.new(
		    bytes(token, 'utf-8'),
		    msg=bytes(string_body, 'utf-8'), 
		    digestmod=hashlib.sha256
    ).hexdigest()
    
return (signature == digest);

{% endtab %} {% endtabs %}

Capacity Limit

If you receive a capacity limit error, meaning you have exceeded your total monthly compute units, you should receive a response similar to the one below. You can upgrade your limits directly through the Alchemy dashboard.

{
  "app": "Demo",
  "network": "MAINNET",
  "error": "Monthly capacity limit exceeded. Upgrade your scaling policy for continued service.",
  "webhookType": "MINED_TRANSACTION",
  "timestamp": "2020-07-29T01:13:54.703Z"
}