Skip to content

Twilio

Twilio SMS allows you to send SMS notifications to phone numbers when events happen on chain.

Setup a Twilio account

  1. Sign up for a Twilio account at twilio.com.
  2. Navigate to the Twilio Console to find your Account SID and Auth Token.
  3. Get a Twilio phone number from the Console under Phone Numbers > Manage > Buy a number.
  4. Keep your Account SID, Auth Token, and Twilio phone number safe, you will need them shortly.

Configure rindexer

twilio property accepts an array allowing you to split up the SMS notifications any way you wish.

Example

contract events
name: RocketPoolETHIndexer
description: My first rindexer project
repository: https://github.com/joshstevens19/rindexer
project_type: no-code
networks:
- name: ethereum
  chain_id: 1
  rpc: https://mainnet.gateway.tenderly.co
contracts:
- name: RocketPoolETH
  details:
  - network: ethereum
    address: "0xae78736cd615f374d3085123a210448e74fc6393"
    start_block: "18600000"
    end_block: "18600181"
  abi: "./abis/RocketTokenRETH.abi.json"
  include_events:
  - Transfer
  chat: 
    twilio: 
      - account_sid: ${TWILIO_ACCOUNT_SID}
        auth_token: ${TWILIO_AUTH_TOKEN}
        from_number: ${TWILIO_FROM_NUMBER}
        to_number: ${TWILIO_TO_NUMBER}
        networks: 
          - ethereum
        messages:
          - event_name: Transfer
            # filter_expression is optional
            filter_expression: "from = '0x0338ce5020c447f7e668dc2ef778025ce3982662' || from = '0x0338ce5020c447f7e668dc2ef778025ce398266u' && value >= 10 && value <= 2000000000000000000"
            template_inline: "New RETH Transfer Event
 
                              from: {{from}}
 
                              to: {{to}}
 
                              amount: {{format_value(value, 18)}}
 
                              RETH contract: {{transaction_information.address}}
 
                              etherscan: https://etherscan.io/tx/{{transaction_information.transaction_hash}}
                              "

account_sid

This is your Twilio Account SID which you can find in your Twilio Console dashboard.

...
contracts:
- name: RocketPoolETH
  details:
  - network: ethereum
    address: "0xae78736cd615f374d3085123a210448e74fc6393"
    start_block: "18600000"
    end_block: "18600181"
  abi: "./abis/RocketTokenRETH.abi.json"
  include_events:
  - Transfer
  chat: 
    twilio: 
      - account_sid: ${TWILIO_ACCOUNT_SID}

auth_token

This is your Twilio Auth Token which you can find in your Twilio Console dashboard.

...
contracts:
- name: RocketPoolETH
  details:
  - network: ethereum
    address: "0xae78736cd615f374d3085123a210448e74fc6393"
    start_block: "18600000"
    end_block: "18600181"
  abi: "./abis/RocketTokenRETH.abi.json"
  include_events:
  - Transfer
  chat: 
    twilio: 
      - account_sid: ${TWILIO_ACCOUNT_SID}
        auth_token: ${TWILIO_AUTH_TOKEN}

from_number

This is the Twilio phone number you purchased to send SMS messages from. Must be in E.164 format (e.g., +1234567890).

...
contracts:
- name: RocketPoolETH
  details:
  - network: ethereum
    address: "0xae78736cd615f374d3085123a210448e74fc6393"
    start_block: "18600000"
    end_block: "18600181"
  abi: "./abis/RocketTokenRETH.abi.json"
  include_events:
  - Transfer
  chat: 
    twilio: 
      - account_sid: ${TWILIO_ACCOUNT_SID}
        auth_token: ${TWILIO_AUTH_TOKEN}
        from_number: ${TWILIO_FROM_NUMBER}

to_number

This is the phone number you want to send SMS messages to. Must be in E.164 format (e.g., +1234567890).

...
contracts:
- name: RocketPoolETH
  details:
  - network: ethereum
    address: "0xae78736cd615f374d3085123a210448e74fc6393"
    start_block: "18600000"
    end_block: "18600181"
  abi: "./abis/RocketTokenRETH.abi.json"
  include_events:
  - Transfer
  chat: 
    twilio: 
      - account_sid: ${TWILIO_ACCOUNT_SID}
        auth_token: ${TWILIO_AUTH_TOKEN}
        from_number: ${TWILIO_FROM_NUMBER}
        to_number: ${TWILIO_TO_NUMBER}

networks

This is an array of networks you want to send SMS messages for.

rindexer.yaml
...
contracts:
- name: RocketPoolETH
  details:
  - network: ethereum
    address: "0xae78736cd615f374d3085123a210448e74fc6393"
    start_block: "18600000"
    end_block: "18600181"
  abi: "./abis/RocketTokenRETH.abi.json"
  include_events:
  - Transfer
  chat: 
    twilio: 
      - account_sid: ${TWILIO_ACCOUNT_SID}
        auth_token: ${TWILIO_AUTH_TOKEN}
        from_number: ${TWILIO_FROM_NUMBER}
        to_number: ${TWILIO_TO_NUMBER}
        networks: 
          - ethereum

messages

This is an array of messages you want to send as SMS. It is an array as you can define many different messages to send with different conditions.

event_name

This is the name of the event you want to send a message for, must match the ABI event name.

rindexer.yaml
...
contracts:
- name: RocketPoolETH
  details:
  - network: ethereum
    address: "0xae78736cd615f374d3085123a210448e74fc6393"
    start_block: "18600000"
    end_block: "18600181"
  abi: "./abis/RocketTokenRETH.abi.json"
  include_events:
  - Transfer
  chat: 
    twilio: 
      - account_sid: ${TWILIO_ACCOUNT_SID}
        auth_token: ${TWILIO_AUTH_TOKEN}
        from_number: ${TWILIO_FROM_NUMBER}
        to_number: ${TWILIO_TO_NUMBER}
        networks:
          - ethereum
        messages:
          - event_name: Transfer

filter_expression

This accepts a filter expression to filter the events before sending an SMS message.

Filter expressions allow for condition checking of the event data and support logical operators to combine multiple conditions.

Supported types and operations:

TypeDescriptionOperatorsNotes
Numeric (uint/int variants)Integer values (e.g., 42, -100) or decimal values (e.g., 3.14, -0.5)>, <, =, >=, <=Numeric comparisons
AddressEthereum addresses (e.g., 0x1234567890abcdef1234567890abcdef12345678)=, !=Comparisons (e.g., from == '0xABC...') are typically case-insensitive regarding the hex characters of the address value itself
StringText values. Can be single-quoted (e.g., 'hello') or, on the right-hand side of a comparison, unquoted (e.g., active)=, !=Quoted strings support \' to escape a single quote and \\ to escape a backslash. All string comparison operations (e.g., name == 'Alice', description contains 'error') are performed case-insensitively during evaluation.
BooleanTrue or false values=, !=Represented as true or false. These keywords are parsed case-insensitively (e.g., TRUE, False are also valid in expressions).
Hex String LiteralA string literal starting with 0x or 0X followed by hexadecimal characters (0-9, a-f, A-F).=, !=Treated as a string for comparison purposes (e.g., input_data starts_with '0xa9059cbb'). Comparison is case-sensitive for the hex characters after 0x.
ArrayOrdered list of items==, !=, [index]See "Array Type Operations" below

Logical Operators

  • && - All conditions must be true
  • || - At least one condition must be true
  • () - Parentheses for grouping
  • && has higher precedence than || (i.e., && operations are evaluated before || operations if not grouped by parentheses)

Array Type Operations

For array types, you can use the following operations:

  • array_param == '["raw_json_array_string"]' string comparison of the array's entire JSON string representation against the provided string
  • array_param != '["raw_json_array_string"]' the negation of the above
  • array_param[0] indexed access. The index must be a non-negative integer.

Whitespace

Flexible whitespace is generally allowed around operators, parentheses, and keywords for readability. However, whitespace within quoted string literals is significant and preserved.

Examples

  • value > 1000 - Numeric comparison, checks if value is greater than 1000.
  • from = '0x1234567890abcdef1234567890abcdef12345678' - Address comparison, checks if from matches the specified address.
  • name != 'Alice' - String comparison, checks if name is not equal to 'Alice'.
  • active = true - Boolean comparison, checks if active is true.
  • value >= 1000 && value <= 2000 - Numeric range check, checks if value is between 1000 and 2000 inclusive.
  • from = '0x1234567890abcdef1234567890abcdef12345678' || from = '0xabcdefabcdefabcdefabcdefabcdefabcdef' - Address comparison with logical OR, checks if from matches either of the two addresses.
  • value > 1000 && (from = '0x1234567890abcdef1234567890abcdef12345678' || from = '0xabcdefabcdefabcdefabcdefabcdefabcdef') - Combined numeric and address checks with logical AND and OR, checks if value is greater than 1000 and from matches either of the two addresses.

conditions

This accepts an array of conditions you want to apply to the event data before sending an SMS message.

You may want to filter on the message based on the event data, if the event data has not got an index on the on the solidity event you can not filter it over the logs. The conditions filter is here to help you with this, based on your ABI you can filter on the event data.

rindexer has enabled a special syntax which allows you to define on your ABI fields what you want to filter on.

  1. > - higher then (for numbers only)
  2. < - lower then (for numbers only)
  3. = - equals
  4. >= - higher then or equals (for numbers only)
  5. <= - lower then or equals (for numbers only)
  6. || - or
  7. && - and

So lets look at an example lets say i only want to get transfer events which are higher then 2000000000000000000 RETH wei

rindexer.yaml
...
contracts:
- name: RocketPoolETH
  details:
  - network: ethereum
    address: "0xae78736cd615f374d3085123a210448e74fc6393"
    start_block: "18600000"
    end_block: "18600181"
  abi: "./abis/RocketTokenRETH.abi.json"
  include_events:
  - Transfer
  chat: 
    twilio: 
      - account_sid: ${TWILIO_ACCOUNT_SID}
        auth_token: ${TWILIO_AUTH_TOKEN}
        from_number: ${TWILIO_FROM_NUMBER}
        to_number: ${TWILIO_TO_NUMBER}
        networks:
          - ethereum
        messages:
          - event_name: Transfer
            conditions: 
              - "value": ">=2000000000000000000"

We use the ABI input name value to filter on the value field, you can find these names in the ABI file.

{
    "anonymous":false,
    "inputs":[
      {
        "indexed":true,
        "internalType":"address",
        "name":"from",
        "type":"address"
      },
      {
        "indexed":true,
        "internalType":"address",
        "name":"to",
        "type":"address"
      },
      {
        "indexed":false,
        "internalType":"uint256",
        "name":"value", 
        "type":"uint256"
      }
    ],
    "name":"Transfer",
    "type":"event"
}

You can use the || or && to combine conditions.

rindexer.yaml
...
contracts:
- name: RocketPoolETH
  details:
  - network: ethereum
    address: "0xae78736cd615f374d3085123a210448e74fc6393"
    start_block: "18600000"
    end_block: "18600181"
  abi: "./abis/RocketTokenRETH.abi.json"
  include_events:
  - Transfer
  chat: 
    twilio: 
      - account_sid: ${TWILIO_ACCOUNT_SID}
        auth_token: ${TWILIO_AUTH_TOKEN}
        from_number: ${TWILIO_FROM_NUMBER}
        to_number: ${TWILIO_TO_NUMBER}
        networks:
          - ethereum
        messages:
          - event_name: Transfer
            conditions: 
              - "value": ">=2000000000000000000 && value <=4000000000000000000"

You can use the = to filter on other aspects like the from or to address.

rindexer.yaml
...
contracts:
- name: RocketPoolETH
  details:
  - network: ethereum
    address: "0xae78736cd615f374d3085123a210448e74fc6393"
    start_block: "18600000"
    end_block: "18600181"
  abi: "./abis/RocketTokenRETH.abi.json"
  include_events:
  - Transfer
  chat: 
    twilio: 
      - account_sid: ${TWILIO_ACCOUNT_SID}
        auth_token: ${TWILIO_AUTH_TOKEN}
        from_number: ${TWILIO_FROM_NUMBER}
        to_number: ${TWILIO_TO_NUMBER}
        networks:
          - ethereum
        messages:
          - event_name: Transfer
              conditions: 
                - "from": "0x0338ce5020c447f7e668dc2ef778025ce3982662 || 0x0338ce5020c447f7e668dc2ef778025ce398266u"
                - "value": ">=2000000000000000000 || value <=4000000000000000000"

If you have a tuple and you want to get that value you just use the object notation.

For example lets say we want to only get the events for profileId from the quoteParams tuple which equals 1:

{
     "anonymous": false,
     "inputs": [
       {
         "components": [
           {
             "internalType": "uint256",
             "name": "profileId", 
             "type": "uint256"
           },
           ...
         ],
         "indexed": false,
         "internalType": "struct Types.QuoteParams",
         "name": "quoteParams", 
         "type": "tuple"
       },
       ...
     ],
     "name": "QuoteCreated", 
     "type": "event"
}
rindexer.yaml
...
contracts:
- name: RocketPoolETH
  details:
  - network: ethereum
    address: "0xae78736cd615f374d3085123a210448e74fc6393"
    start_block: "18600000"
    end_block: "18600181"
  abi: "./abis/RocketTokenRETH.abi.json"
  include_events:
  - Transfer
  chat: 
    twilio: 
      - account_sid: ${TWILIO_ACCOUNT_SID}
        auth_token: ${TWILIO_AUTH_TOKEN}
        from_number: ${TWILIO_FROM_NUMBER}
        to_number: ${TWILIO_TO_NUMBER}
        networks:
          - ethereum
        messages:
          - event_name: Transfer
            conditions: 
              - "quoteParams.profileId": "=1"

template_inline

You can then write your own template inline, this is the template you want to send as SMS. You have to use the ABI input names in object notation for example if i wanted to put value in the template i just have to write {{value}} in the template and it will be replaced with the value of the event itself.

transaction_information

You also can use the transaction_information object to get common information about the transaction, this is the transaction information for the event.

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct TxInformation {
    pub network: String,
    // This will convert to a hex string in the template
    pub address: Address,
    // This will convert to a hex string in the template
    pub block_hash: BlockHash,
    // This will convert to a string decimal in the template
    pub block_number: U64,
    // This will convert to a hex string in the template
    pub transaction_hash: TxHash,
    // This will convert to a string decimal in the template
    pub log_index: U256,
    // This will convert to a string decimal in the template
    pub transaction_index: U64,
}

format_value

You can use the format_value function to format the value of the event to a decimal value with the specified decimals.

Lets put it all together:

rindexer.yaml
...
contracts:
- name: RocketPoolETH
  details:
  - network: ethereum
    address: "0xae78736cd615f374d3085123a210448e74fc6393"
    start_block: "18600000"
    end_block: "18600181"
  abi: "./abis/RocketTokenRETH.abi.json"
  include_events:
  - Transfer
  chat: 
    twilio: 
      - account_sid: ${TWILIO_ACCOUNT_SID}
        auth_token: ${TWILIO_AUTH_TOKEN}
        from_number: ${TWILIO_FROM_NUMBER}
        to_number: ${TWILIO_TO_NUMBER}
        networks:
          - ethereum
        messages:
          - event_name: Transfer
            template_inline: "New RETH Transfer Event
 
                              from: {{from}}
 
                              to: {{to}}
 
                              amount: {{format_value(value, 18)}}
 
                              RETH contract: {{transaction_information.address}}
 
                              etherscan: https://etherscan.io/tx/{{transaction_information.transaction_hash}}
                              "