Slack
Slack is one of the most popular chat platforms, and is great to build bots and notifications when things happen on chain.
Setup a bot on slack
- Go to api.slack.com, log into your workspace and click on Create an app
- Click on From scratch and then give it a name and select your workspace. We will call ours RethTransferEvents.
- Click on the Bots box under the Add features and functionality header
- Click on Review scopes to add
- Scroll down to the Bot token scopes header and add
chat:write
. These are the permissions the bot needs to write messages - Finally, scroll all the way up and click on Install to workspace, and Allow on the following screen. This should now show a screen with the Bot User OAuth Token visible. Take note of this token, since itβs the one we will be using to send messages.
- Now add the bot to the channel you want to send a message to, channels are the
#
followed by the channel name. You need to include the#
in the channel name.
Configure rindexer
slack
property accepts an array allowing you to split up the channels any way you wish.
Example
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:
slack:
- bot_token: ${SLACK_BOT_TOKEN}
channel: "#RethTransferEvents"
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}}
<https://etherscan.io/tx/{{transaction_information.transaction_hash}} | etherscan>
"
bot_token
This is your slack bot token which you generate using @BotFather.
...
contracts:
- name: RocketPoolETH
details:
- network: ethereum
address: "0xae78736cd615f374d3085123a210448e74fc6393"
start_block: "18600000"
end_block: "18600181"
abi: "./abis/RocketTokenRETH.abi.json"
include_events:
- Transfer
chat:
slack:
- bot_token: ${SLACK_BOT_TOKEN}
channel
This is the channel you want to send messages to.
...
contracts:
- name: RocketPoolETH
details:
- network: ethereum
address: "0xae78736cd615f374d3085123a210448e74fc6393"
start_block: "18600000"
end_block: "18600181"
abi: "./abis/RocketTokenRETH.abi.json"
include_events:
- Transfer
chat:
slack:
- bot_token: ${SLACK_BOT_TOKEN}
channel: "#RethTransferEvents"
networks
This is an array of networks you want to send messages to this slack channel.
...
contracts:
- name: RocketPoolETH
details:
- network: ethereum
address: "0xae78736cd615f374d3085123a210448e74fc6393"
start_block: "18600000"
end_block: "18600181"
abi: "./abis/RocketTokenRETH.abi.json"
include_events:
- Transfer
chat:
slack:
- bot_token: ${SLACK_BOT_TOKEN}
channel: "#RethTransferEvents"
networks:
- ethereum
messages
This is an array of messages you want to send to this slack channel. It is an array as you can define many different messages to send to this channel 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.
...
contracts:
- name: RocketPoolETH
details:
- network: ethereum
address: "0xae78736cd615f374d3085123a210448e74fc6393"
start_block: "18600000"
end_block: "18600181"
abi: "./abis/RocketTokenRETH.abi.json"
include_events:
- Transfer
chat:
slack:
- bot_token: ${SLACK_BOT_TOKEN}
channel: "#RethTransferEvents"
networks:
- ethereum
messages:
- event_name: Transfer
filter_expression
This accepts a filter expression to filter the events before sending a message to this discord channel
Filter expressions allow for condition checking of the event data and support logical operators to combine multiple conditions.
Supported types and operations:
Type | Description | Operators | Notes |
---|---|---|---|
Numeric (uint/int variants) | Integer values (e.g., 42 , -100 ) or decimal values (e.g., 3.14 , -0.5 ) | > , < , = , >= , <= | Numeric comparisons |
Address | Ethereum addresses (e.g., 0x1234567890abcdef1234567890abcdef12345678 ) | = , != | Comparisons (e.g., from == '0xABC...' ) are typically case-insensitive regarding the hex characters of the address value itself |
String | Text 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. |
Boolean | True 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 Literal | A 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 . |
Array | Ordered 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 stringarray_param != '["raw_json_array_string"]'
the negation of the abovearray_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 ifvalue
is greater than 1000.from = '0x1234567890abcdef1234567890abcdef12345678'
- Address comparison, checks iffrom
matches the specified address.name != 'Alice'
- String comparison, checks ifname
is not equal to 'Alice'.active = true
- Boolean comparison, checks ifactive
is true.value >= 1000 && value <= 2000
- Numeric range check, checks ifvalue
is between 1000 and 2000 inclusive.from = '0x1234567890abcdef1234567890abcdef12345678' || from = '0xabcdefabcdefabcdefabcdefabcdefabcdef'
- Address comparison with logical OR, checks iffrom
matches either of the two addresses.value > 1000 && (from = '0x1234567890abcdef1234567890abcdef12345678' || from = '0xabcdefabcdefabcdefabcdefabcdefabcdef')
- Combined numeric and address checks with logical AND and OR, checks ifvalue
is greater than 1000 andfrom
matches either of the two addresses.
conditions
This accepts an array of conditions you want to apply to the event data before sending a message to this slack channel.
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.
>
- higher then (for numbers only)<
- lower then (for numbers only)=
- equals>=
- higher then or equals (for numbers only)<=
- lower then or equals (for numbers only)||
- or&&
- and
So lets look at an example lets say i only want to get transfer events which are higher then 2000000000000000000
RETH wei
...
contracts:
- name: RocketPoolETH
details:
- network: ethereum
address: "0xae78736cd615f374d3085123a210448e74fc6393"
start_block: "18600000"
end_block: "18600181"
abi: "./abis/RocketTokenRETH.abi.json"
include_events:
- Transfer
chat:
slack:
- bot_token: ${SLACK_BOT_TOKEN}
channel: "#RethTransferEvents"
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.
...
contracts:
- name: RocketPoolETH
details:
- network: ethereum
address: "0xae78736cd615f374d3085123a210448e74fc6393"
start_block: "18600000"
end_block: "18600181"
abi: "./abis/RocketTokenRETH.abi.json"
include_events:
- Transfer
chat:
slack:
- bot_token: ${SLACK_BOT_TOKEN}
channel: "#RethTransferEvents"
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.
...
contracts:
- name: RocketPoolETH
details:
- network: ethereum
address: "0xae78736cd615f374d3085123a210448e74fc6393"
start_block: "18600000"
end_block: "18600181"
abi: "./abis/RocketTokenRETH.abi.json"
include_events:
- Transfer
chat:
slack:
- bot_token: ${SLACK_BOT_TOKEN}
channel: "#RethTransferEvents"
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"
}
...
contracts:
- name: RocketPoolETH
details:
- network: ethereum
address: "0xae78736cd615f374d3085123a210448e74fc6393"
start_block: "18600000"
end_block: "18600181"
abi: "./abis/RocketTokenRETH.abi.json"
include_events:
- Transfer
chat:
slack:
- bot_token: ${SLACK_BOT_TOKEN}
channel: "#RethTransferEvents"
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 to the channel.
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.
The template supports:
- bold text = *bold text*
- italic text = _italic text_
- strikethrough text = ~strikethrough text~
- block qoute = > block quote
- inline url = <URL | etherscan>
- inline fixed-width code = `inline fixed-width code`
- pre-formatted fixed-width code block = ```pre-formatted fixed-width code block```
- pre-formatted fixed-width known code block = ```rust pre-formatted fixed-width known code block```
- breaks = just line break in the template
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:
...
contracts:
- name: RocketPoolETH
details:
- network: ethereum
address: "0xae78736cd615f374d3085123a210448e74fc6393"
start_block: "18600000"
end_block: "18600181"
abi: "./abis/RocketTokenRETH.abi.json"
include_events:
- Transfer
chat:
slack:
- bot_token: ${SLACK_BOT_TOKEN}
channel: "#RethTransferEvents"
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}}
<https://etherscan.io/tx/{{transaction_information.transaction_hash}} | etherscan>
"