feat: Add initial code drop
This commit is contained in:
parent
d968c9460c
commit
1ae919599b
10
README.md
10
README.md
@ -1 +1,9 @@
|
||||
# australian_capital_dao
|
||||
# Australian Capital DAO
|
||||
|
||||
This is a repo to hold the code for the ACD bot.
|
||||
The bot uses N8N to automate the process of sending messages on any DAO transaction.
|
||||
|
||||
## Files
|
||||
[n8n.json](/n8n.json) - The n8n workflow file (import this into n8n and add the necessary credentials)
|
||||
[parser.js](/parser.js) - The script that parses the transaction data to be used to create the message
|
||||
[message.js](/message.js) - The script that creates the message to send to the telegram and discord bots
|
75
message.js
Normal file
75
message.js
Normal file
@ -0,0 +1,75 @@
|
||||
function cleanJsonString(jsonString) {
|
||||
// Remove invisible and non-printable characters (excluding newlines, carriage returns, and tabs)
|
||||
const cleanedString = jsonString.replace(/[^\x20-\x7E\r\n\t]+/g, '');
|
||||
|
||||
// Remove leading or trailing whitespace
|
||||
const trimmedString = cleanedString.trim();
|
||||
|
||||
// Ensure the string is enclosed within curly braces if it’s a JSON object
|
||||
if (!trimmedString.startsWith('{') || !trimmedString.endsWith('}')) {
|
||||
throw new Error('Invalid JSON format: Missing opening or closing brace.');
|
||||
}
|
||||
|
||||
return trimmedString;
|
||||
}
|
||||
|
||||
const addressNames = {
|
||||
"0x6cb4b39bec23a921c9a20d061bf17d4640b0d39e":"woodburn.au"
|
||||
};
|
||||
function addressName(address) {
|
||||
if (addressNames.hasOwnProperty(address)){
|
||||
return addressNames[address];
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
|
||||
|
||||
var message = "New DAO transaction: ";
|
||||
const parsed = $('Parser').first().json;
|
||||
message += parsed.method;
|
||||
|
||||
if (parsed.method == "Submit Vote"){
|
||||
message += "\n"+ addressName(parsed.member) + " voted ";
|
||||
if (parsed.vote == 1){
|
||||
message += "for";
|
||||
} else {
|
||||
message += "against";
|
||||
}
|
||||
message += " proposal #"+parsed.proposal;
|
||||
message += " using " + parsed.votes + " votes";
|
||||
}
|
||||
else if (parsed.method == "Sponsor Proposal"){
|
||||
message += "\n"+ addressName(parsed.member) + " sponsored ";
|
||||
message += "proposal #"+parsed.proposal;
|
||||
}
|
||||
else if (parsed.method == "Submit Proposal"){
|
||||
message += "\n"+ addressName($('HTTP Request').first().json.result.from);
|
||||
message += " created proposal #" + parsed.proposal;
|
||||
try {
|
||||
const cleanedJsonString = cleanJsonString(parsed.data.details);
|
||||
const details = JSON.parse(cleanedJsonString);
|
||||
message += "\nProposal: " + details.title;
|
||||
message += "\nDescription: " + details.description;
|
||||
|
||||
if (details.contentURI != ""){
|
||||
message += "\nURL: " + details.contentURI;
|
||||
}
|
||||
}
|
||||
catch (error){
|
||||
message += "\nProposal details failed to parse";
|
||||
message += error;
|
||||
}
|
||||
}
|
||||
else if (parsed.method == "Process Proposal"){
|
||||
message += "\n"+ addressName($('HTTP Request').first().json.result.from);
|
||||
message += " executed proposal #" + parsed.proposal;
|
||||
}
|
||||
|
||||
return {
|
||||
"message":message,
|
||||
"explorer":"https://optimistic.etherscan.io/tx/"+$('HTTP Request').first().json.result.transactionHash,
|
||||
"proposalURL":"https://admin.daohaus.club/#/molochV3/0xa/0xf4604948ad5365840803297bf81cd9a46c36fce7/proposal/"+parsed.proposal
|
||||
};
|
||||
|
||||
|
570
n8n.json
Normal file
570
n8n.json
Normal file
@ -0,0 +1,570 @@
|
||||
{
|
||||
"name": "DAOHaus Alerts",
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {
|
||||
"httpMethod": "POST",
|
||||
"path": "530c914a-c732-4cb6-aaf1-2b722f9e7398",
|
||||
"options": {}
|
||||
},
|
||||
"id": "def14e6f-a3fc-4844-8a94-b2d3a0a9bdb5",
|
||||
"name": "Webhook",
|
||||
"type": "n8n-nodes-base.webhook",
|
||||
"typeVersion": 1.1,
|
||||
"position": [
|
||||
660,
|
||||
540
|
||||
],
|
||||
"webhookId": "530c914a-c732-4cb6-aaf1-2b722f9e7398"
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"method": "POST",
|
||||
"url": "https://opt-mainnet.g.alchemy.com/v2/{alchemy_api_key}",
|
||||
"sendBody": true,
|
||||
"specifyBody": "json",
|
||||
"jsonBody": "={\n \"id\": 1,\n \"jsonrpc\": \"2.0\",\n \"method\": \"eth_getTransactionReceipt\",\n \"params\": [\n\"{{ $json[\"body\"][\"event\"][\"activity\"][0][\"hash\"] }}\"\n ]\n}",
|
||||
"options": {}
|
||||
},
|
||||
"id": "b97eaff4-26f2-4230-b3e2-3eb14b5cbbba",
|
||||
"name": "HTTP Request",
|
||||
"type": "n8n-nodes-base.httpRequest",
|
||||
"typeVersion": 4.1,
|
||||
"position": [
|
||||
1160,
|
||||
540
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"authentication": "webhook",
|
||||
"options": {},
|
||||
"embeds": {
|
||||
"values": [
|
||||
{
|
||||
"description": "={{ $json[\"message\"] }}\n\n{{ $json[\"proposalURL\"] }}",
|
||||
"author": "Australian Capital DAO",
|
||||
"color": "#FF00D9",
|
||||
"timestamp": "={{ ($now.minus({hours:10})).toFormat('yyyy-LL-dd HH:mm:ss') }}\n",
|
||||
"title": "New DAO TX",
|
||||
"url": "={{ $json[\"explorer\"] }}"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"id": "8e49fb62-06a1-4e51-898c-c17e1eb5dae0",
|
||||
"name": "Discord2",
|
||||
"type": "n8n-nodes-base.discord",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
1960,
|
||||
420
|
||||
],
|
||||
"credentials": {
|
||||
"discordWebhookApi": {
|
||||
"id": "XzOnTbxymIRJMNFK",
|
||||
"name": "N8N Channel"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"chatId": "-4260162868",
|
||||
"text": "={{ $json[\"message\"] }}",
|
||||
"replyMarkup": "inlineKeyboard",
|
||||
"inlineKeyboard": {
|
||||
"rows": [
|
||||
{
|
||||
"row": {
|
||||
"buttons": [
|
||||
{
|
||||
"text": "View tx on Etherscan",
|
||||
"additionalFields": {
|
||||
"url": "={{ $json[\"explorer\"] }}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"text": "View Proposal",
|
||||
"additionalFields": {
|
||||
"url": "={{ $json[\"proposalURL\"] }}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"additionalFields": {
|
||||
"appendAttribution": false
|
||||
}
|
||||
},
|
||||
"id": "2577c299-f86e-46d2-8799-e4e10875e3c7",
|
||||
"name": "Telegram",
|
||||
"type": "n8n-nodes-base.telegram",
|
||||
"typeVersion": 1.1,
|
||||
"position": [
|
||||
1960,
|
||||
640
|
||||
],
|
||||
"credentials": {
|
||||
"telegramApi": {
|
||||
"id": "VWQskb1y7DoFEnMh",
|
||||
"name": "Telegram account"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"updates": [
|
||||
"message"
|
||||
],
|
||||
"additionalFields": {}
|
||||
},
|
||||
"id": "245d297b-8838-441e-b206-1f9cfdff8591",
|
||||
"name": "Telegram Trigger",
|
||||
"type": "n8n-nodes-base.telegramTrigger",
|
||||
"typeVersion": 1.1,
|
||||
"position": [
|
||||
480,
|
||||
940
|
||||
],
|
||||
"webhookId": "47a00ca7-1eb5-408d-8846-4af7f8b1e36b",
|
||||
"credentials": {
|
||||
"telegramApi": {
|
||||
"id": "VWQskb1y7DoFEnMh",
|
||||
"name": "Telegram account"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"authentication": "webhook",
|
||||
"content": "=New message from: {{ $json[\"message\"][\"from\"][\"first_name\"] }} (username: {{ $json[\"message\"][\"from\"][\"username\"] }}) (ID: {{ $json[\"message\"][\"from\"][\"id\"] }})\nChat Title: {{ $json[\"message\"][\"chat\"][\"title\"] }}\nChat ID: {{ $json[\"message\"][\"chat\"][\"id\"] }}\nChat Type: {{ $json[\"message\"][\"chat\"][\"type\"] }}\nMessage text: {{ $json[\"message\"][\"text\"] }}",
|
||||
"options": {}
|
||||
},
|
||||
"id": "ce165915-be3e-49f2-b9e8-308f98e37ffd",
|
||||
"name": "Discord3",
|
||||
"type": "n8n-nodes-base.discord",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
1560,
|
||||
900
|
||||
],
|
||||
"credentials": {
|
||||
"discordWebhookApi": {
|
||||
"id": "XzOnTbxymIRJMNFK",
|
||||
"name": "N8N Channel"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"conditions": {
|
||||
"options": {
|
||||
"caseSensitive": true,
|
||||
"leftValue": "",
|
||||
"typeValidation": "strict"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"id": "ca511fdf-180b-4236-b474-3bfe439ded0c",
|
||||
"leftValue": "={{ $json[\"body\"][\"event\"][\"activity\"].length }}",
|
||||
"rightValue": 1,
|
||||
"operator": {
|
||||
"type": "number",
|
||||
"operation": "equals"
|
||||
}
|
||||
}
|
||||
],
|
||||
"combinator": "and"
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "9536c45d-ae2a-472d-87f5-2b4535150128",
|
||||
"name": "If1",
|
||||
"type": "n8n-nodes-base.if",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
880,
|
||||
540
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "function hexToDecimal(hex) {\n return parseInt(hex, 16);\n}\nfunction stripExtraZeros(hexString) {\n // Remove leading zeros while keeping at least \"0x\" if present\n hexString = hexString.replace(/^0x0+/, '');\n return \"0x\"+hexString;\n}\n\n\n\nconst topics = {\n \"0xb9956173924f9c1204bae41dd3737d7ed1161846d13183879cdc03c4b9f8d019\":\"Submit Proposal\",\n \"0x786755545a7e27c12c90cc7f0934514d03fdacfe3684a340b8c4100531e7ecd5\":\"Submit Vote\",\n \"0xb4571f7e4e2c2b6e6185e47ab5caa5fe34087299bd49fbae945a4583101ee3f0\":\"Process Proposal\",\n \"0xd45ad122361f16d6f50d7c4a73638f20ee48eff6186af15224e2a4a1f6d50171\":\"Sponsor Proposal\"\n};\n\nvar Logs = $('HTTP Request').first().json.result.logs;\nvar topicsFromLogs = [];\n\nfor (var i = 0; i < Logs.length; i++) {\n var log = Logs[i];\n topicsFromLogs.push(...log.topics); // Using spread operator to append topics array\n}\n\nvar data = {\n \"method\":\"Unknown method\"\n};\n\nconst opts = {\n \"Submit Vote\":{\n 1:\"member\",\n 2:\"proposal\",\n 3:\"vote\"\n },\n \"Submit Proposal\":{\n 1:\"proposal\",\n 2:\"dataHash\"\n },\n \"Process Proposal\":{\n 1:\"member\",\n 2:\"proposal\",\n 3:\"vote\"\n },\n \"Sponsor Proposal\":{\n 1:\"member\",\n 2:\"proposal\",\n 3:\"votingStarts\"\n }\n}\n\n\n// Check each topic in the logs against the topics object\nfor (let i = 0; i < topicsFromLogs.length; i++) {\n const topic = topicsFromLogs[i];\n if (topics.hasOwnProperty(topic)) {\n data[\"method\"] = topics[topic];\n console.log('Matched Option:', data[\"method\"]);\n } else {\n if (opts.hasOwnProperty(data[\"method\"])){\n var keys = opts[data[\"method\"]];\n if (keys[i] != \"member\"){\n data[keys[i]] = hexToDecimal(topic); \n } else {\n data[keys[i]] = stripExtraZeros(topic);\n }\n }\n }\n}\nfunction hexToUtf8(hexStr) {\n return Buffer.from(hexStr, 'hex').toString('utf8');\n}\n\nif (data[\"method\"]== \"Submit Proposal\"){\n const hexData = $('HTTP Request').first().json.result.logs[0].data;\n // Extracting segments from hexData (assuming it's already defined)\n const votingPeriodHex = hexData.slice(2, 66); // 64 characters (32 bytes) for votingPeriod\n const proposalDataHex = hexData.slice(66, 130); // 64 characters (32 bytes) for proposalData\n const expirationHex = hexData.slice(130, 194); // 64 characters (32 bytes) for expiration\n const baalGasHex = hexData.slice(194, 258); // 64 characters (32 bytes) for baalGas\n const selfSponsorHex = hexData.slice(258, 322); // 64 characters (32 bytes) for selfSponsor\n const timestampHex = hexData.slice(322, 386); // 64 characters (32 bytes) for timestamp\n const detailsHex = hexData.slice(386); // Remaining part for details\n \n // Decode hex segments into decimal or string format\n const votingPeriod = hexToDecimal(votingPeriodHex);\n const proposalData = proposalDataHex;\n const expiration = hexToDecimal(expirationHex);\n const baalGas = hexToDecimal(baalGasHex);\n const selfSponsor = hexToDecimal(selfSponsorHex);\n const timestamp = hexToDecimal(timestampHex);\n \n let detailsObj;\n detailsObj = hexToUtf8(detailsHex);\n const jsonStringStart = detailsObj.indexOf('{\"');\n if (jsonStringStart !== -1) {\n detailsObj = detailsObj.slice(jsonStringStart);\n }\n\n \n // Construct the JSON object\n const jsonObject = {\n votingPeriod: votingPeriod,\n proposalData: proposalData,\n expiration: expiration,\n baalGas: baalGas,\n selfSponsor: selfSponsor,\n timestamp: timestamp,\n details: detailsObj\n };\n\n data['data'] = jsonObject;\n} else if (data[\"method\"]== \"Submit Vote\"){\n const hexData = $('HTTP Request').first().json.result.logs[0].data;\n data[\"votes\"]= hexToDecimal(hexData)/1000000000000000000;\n} else if (data[\"method\"]== \"Process Proposal\"){\n var logData = []\n for (var i = 0; i < Logs.length; i++) {\n if (Logs[i].topics[0]==\"0xb4571f7e4e2c2b6e6185e47ab5caa5fe34087299bd49fbae945a4583101ee3f0\"){\n data[\"proposal\"] = hexToDecimal(Logs[i].topics[1]);\n }\n}\n\n\n}\n\nconsole.log(data);\nreturn data;\n"
|
||||
},
|
||||
"id": "eb7edb1c-a29d-4a55-9e69-3526edb2194a",
|
||||
"name": "Parser",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
1360,
|
||||
540
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"jsCode": "function cleanJsonString(jsonString) {\n // Remove invisible and non-printable characters (excluding newlines, carriage returns, and tabs)\n const cleanedString = jsonString.replace(/[^\\x20-\\x7E\\r\\n\\t]+/g, '');\n \n // Remove leading or trailing whitespace\n const trimmedString = cleanedString.trim();\n \n // Ensure the string is enclosed within curly braces if it’s a JSON object\n if (!trimmedString.startsWith('{') || !trimmedString.endsWith('}')) {\n throw new Error('Invalid JSON format: Missing opening or closing brace.');\n }\n\n return trimmedString;\n}\n\nconst addressNames = {\n \"0x6cb4b39bec23a921c9a20d061bf17d4640b0d39e\":\"woodburn.au\" \n};\nfunction addressName(address) {\n if (addressNames.hasOwnProperty(address)){\n return addressNames[address];\n }\n return address;\n}\n\n\n\nvar message = \"New DAO transaction: \";\nconst parsed = $('Parser').first().json;\nmessage += parsed.method;\n\nif (parsed.method == \"Submit Vote\"){\n message += \"\\n\"+ addressName(parsed.member) + \" voted \";\n if (parsed.vote == 1){\n message += \"for\";\n } else {\n message += \"against\";\n }\n message += \" proposal #\"+parsed.proposal;\n message += \" using \" + parsed.votes + \" votes\";\n}\nelse if (parsed.method == \"Sponsor Proposal\"){\n message += \"\\n\"+ addressName(parsed.member) + \" sponsored \";\n message += \"proposal #\"+parsed.proposal;\n}\nelse if (parsed.method == \"Submit Proposal\"){\n message += \"\\n\"+ addressName($('HTTP Request').first().json.result.from);\n message += \" created proposal #\" + parsed.proposal;\n try {\n const cleanedJsonString = cleanJsonString(parsed.data.details);\n const details = JSON.parse(cleanedJsonString);\n message += \"\\nProposal: \" + details.title;\n message += \"\\nDescription: \" + details.description;\n\n if (details.contentURI != \"\"){\n message += \"\\nURL: \" + details.contentURI;\n }\n }\n catch (error){\n message += \"\\nProposal details failed to parse\";\n message += error;\n }\n}\nelse if (parsed.method == \"Process Proposal\"){\n message += \"\\n\"+ addressName($('HTTP Request').first().json.result.from);\n message += \" executed proposal #\" + parsed.proposal;\n}\n\n\n// message += \"\\n\\nhttps://optimistic.etherscan.io/tx/\";\n// message += $('HTTP Request').first().json.result.transactionHash;\n// message += \"\\nhttps://admin.daohaus.club/#/molochV3/0xa/0xf4604948ad5365840803297bf81cd9a46c36fce7/proposal/\"\n// message += parsed.proposal;\n\nreturn {\n \"message\":message,\n \"explorer\":\"https://optimistic.etherscan.io/tx/\"+$('HTTP Request').first().json.result.transactionHash,\n\"proposalURL\":\"https://admin.daohaus.club/#/molochV3/0xa/0xf4604948ad5365840803297bf81cd9a46c36fce7/proposal/\"+parsed.proposal\n};\n\n"
|
||||
},
|
||||
"id": "22c0ce02-9388-4dca-ac32-3fda22a4f280",
|
||||
"name": "Create message",
|
||||
"type": "n8n-nodes-base.code",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
1580,
|
||||
500
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"conditions": {
|
||||
"options": {
|
||||
"caseSensitive": true,
|
||||
"leftValue": "",
|
||||
"typeValidation": "strict"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"id": "21456147-b1d5-4cb6-877d-ffe7c567eec6",
|
||||
"leftValue": "={{ $json[\"message\"][\"entities\"].length }}",
|
||||
"rightValue": 0,
|
||||
"operator": {
|
||||
"type": "number",
|
||||
"operation": "notEquals"
|
||||
}
|
||||
}
|
||||
],
|
||||
"combinator": "and"
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "cc10be80-8d35-43d0-84a7-78440d3b7801",
|
||||
"name": "If",
|
||||
"type": "n8n-nodes-base.if",
|
||||
"typeVersion": 2,
|
||||
"position": [
|
||||
660,
|
||||
1100
|
||||
]
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"chatId": "={{ $json[\"message\"][\"chat\"][\"id\"] }}",
|
||||
"text": "Pong",
|
||||
"additionalFields": {
|
||||
"appendAttribution": false,
|
||||
"reply_to_message_id": "={{ $json[\"message\"][\"message_id\"] }}"
|
||||
}
|
||||
},
|
||||
"id": "d6d67b9f-279f-4618-a2d4-14737449131f",
|
||||
"name": "Ping Pong",
|
||||
"type": "n8n-nodes-base.telegram",
|
||||
"typeVersion": 1.1,
|
||||
"position": [
|
||||
1280,
|
||||
1000
|
||||
],
|
||||
"credentials": {
|
||||
"telegramApi": {
|
||||
"id": "VWQskb1y7DoFEnMh",
|
||||
"name": "Telegram account"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"chatId": "={{ $json[\"message\"][\"chat\"][\"id\"] }}",
|
||||
"text": "Sure here is the link to the Australian Capital DAO",
|
||||
"replyMarkup": "inlineKeyboard",
|
||||
"inlineKeyboard": {
|
||||
"rows": [
|
||||
{
|
||||
"row": {
|
||||
"buttons": [
|
||||
{
|
||||
"text": "Go to DAO Page",
|
||||
"additionalFields": {
|
||||
"url": "https://admin.daohaus.club/#/molochv3/0xa/0xf4604948ad5365840803297bf81cd9a46c36fce7"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"additionalFields": {
|
||||
"appendAttribution": false,
|
||||
"reply_to_message_id": "={{ $json[\"message\"][\"message_id\"] }}"
|
||||
}
|
||||
},
|
||||
"id": "402477d9-701c-4d08-80d9-608c4b702881",
|
||||
"name": "Dao Link",
|
||||
"type": "n8n-nodes-base.telegram",
|
||||
"typeVersion": 1.1,
|
||||
"position": [
|
||||
1280,
|
||||
1160
|
||||
],
|
||||
"credentials": {
|
||||
"telegramApi": {
|
||||
"id": "VWQskb1y7DoFEnMh",
|
||||
"name": "Telegram account"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"parameters": {
|
||||
"rules": {
|
||||
"values": [
|
||||
{
|
||||
"conditions": {
|
||||
"options": {
|
||||
"caseSensitive": true,
|
||||
"leftValue": "",
|
||||
"typeValidation": "strict"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"leftValue": "={{ $json[\"message\"][\"text\"] }}",
|
||||
"rightValue": "/ping",
|
||||
"operator": {
|
||||
"type": "string",
|
||||
"operation": "startsWith"
|
||||
}
|
||||
}
|
||||
],
|
||||
"combinator": "and"
|
||||
}
|
||||
},
|
||||
{
|
||||
"conditions": {
|
||||
"options": {
|
||||
"caseSensitive": true,
|
||||
"leftValue": "",
|
||||
"typeValidation": "strict"
|
||||
},
|
||||
"conditions": [
|
||||
{
|
||||
"id": "4c2f8464-cf52-467d-a219-e75793559353",
|
||||
"leftValue": "={{ $json[\"message\"][\"text\"] }}",
|
||||
"rightValue": "/dao",
|
||||
"operator": {
|
||||
"type": "string",
|
||||
"operation": "startsWith"
|
||||
}
|
||||
}
|
||||
],
|
||||
"combinator": "and"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {}
|
||||
},
|
||||
"id": "eb1090bf-5f39-4c8e-ac85-ed2e7b59e76e",
|
||||
"name": "Switch",
|
||||
"type": "n8n-nodes-base.switch",
|
||||
"typeVersion": 3,
|
||||
"position": [
|
||||
960,
|
||||
1080
|
||||
]
|
||||
}
|
||||
],
|
||||
"pinData": {
|
||||
"Webhook": [
|
||||
{
|
||||
"json": {
|
||||
"headers": {
|
||||
"host": "n8n.woodburn.au",
|
||||
"x-forwarded-scheme": "https",
|
||||
"x-forwarded-proto": "https",
|
||||
"x-forwarded-for": "118.208.168.176",
|
||||
"x-real-ip": "118.208.168.176",
|
||||
"content-length": "845",
|
||||
"content-type": "application/json",
|
||||
"user-agent": "insomnia/9.3.1",
|
||||
"accept": "*/*"
|
||||
},
|
||||
"params": {},
|
||||
"query": {},
|
||||
"body": {
|
||||
"webhookId": "wh_mvrhnhyqysvf70qj",
|
||||
"id": "whevt_rc0mq97pww9a7leo",
|
||||
"createdAt": "2024-07-18T05:46:57.824Z",
|
||||
"type": "ADDRESS_ACTIVITY",
|
||||
"event": {
|
||||
"network": "OPT_MAINNET",
|
||||
"activity": [
|
||||
{
|
||||
"fromAddress": "0xf4604948ad5365840803297bf81cd9a46c36fce7",
|
||||
"toAddress": "0x35d3efffa0e6c63ee5c7e8c7dd7e7d6e961a6689",
|
||||
"blockNum": "0x752694c",
|
||||
"hash": "0x02d3f83b6663df1edc04db532190a17ef7a3267ca3104d7c36435eb2aad12b3f",
|
||||
"value": 0,
|
||||
"typeTraceAddress": "STATICCALL_0_0",
|
||||
"asset": "ETH",
|
||||
"category": "internal",
|
||||
"rawContract": {
|
||||
"rawValue": "0x0",
|
||||
"decimals": 18
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"Telegram Trigger": [
|
||||
{
|
||||
"json": {
|
||||
"update_id": 328606253,
|
||||
"message": {
|
||||
"message_id": 34,
|
||||
"from": {
|
||||
"id": 5166524939,
|
||||
"is_bot": false,
|
||||
"first_name": "Nathan.Woodburn/",
|
||||
"username": "nathanwoodburn",
|
||||
"language_code": "en"
|
||||
},
|
||||
"chat": {
|
||||
"id": -4260162868,
|
||||
"title": "Test Bot Group",
|
||||
"type": "group",
|
||||
"all_members_are_administrators": true
|
||||
},
|
||||
"date": 1721355038,
|
||||
"text": "/dao@australian_capital_dao_bot",
|
||||
"entities": [
|
||||
{
|
||||
"offset": 0,
|
||||
"length": 31,
|
||||
"type": "bot_command"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"connections": {
|
||||
"Webhook": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "If1",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"HTTP Request": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Parser",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Telegram Trigger": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Discord3",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
},
|
||||
{
|
||||
"node": "If",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"If1": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "HTTP Request",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Parser": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Create message",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Create message": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Discord2",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
},
|
||||
{
|
||||
"node": "Telegram",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"If": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Switch",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
"Switch": {
|
||||
"main": [
|
||||
[
|
||||
{
|
||||
"node": "Ping Pong",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
],
|
||||
[
|
||||
{
|
||||
"node": "Dao Link",
|
||||
"type": "main",
|
||||
"index": 0
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
},
|
||||
"active": true,
|
||||
"settings": {
|
||||
"executionOrder": "v1"
|
||||
},
|
||||
"versionId": "4d31c171-d9e4-47a8-8a76-4a56b6fd3101",
|
||||
"meta": {
|
||||
"templateCredsSetupCompleted": true,
|
||||
"instanceId": "716fbd4310435337bb8df7c59b7984bfb867d59d9129682cbc4d8523a713d40e"
|
||||
},
|
||||
"id": "POAYZQJI8PYGlKWt",
|
||||
"tags": []
|
||||
}
|
131
parser.js
Normal file
131
parser.js
Normal file
@ -0,0 +1,131 @@
|
||||
function hexToDecimal(hex) {
|
||||
return parseInt(hex, 16);
|
||||
}
|
||||
function stripExtraZeros(hexString) {
|
||||
// Remove leading zeros while keeping at least "0x" if present
|
||||
hexString = hexString.replace(/^0x0+/, '');
|
||||
return "0x"+hexString;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const topics = {
|
||||
"0xb9956173924f9c1204bae41dd3737d7ed1161846d13183879cdc03c4b9f8d019":"Submit Proposal",
|
||||
"0x786755545a7e27c12c90cc7f0934514d03fdacfe3684a340b8c4100531e7ecd5":"Submit Vote",
|
||||
"0xb4571f7e4e2c2b6e6185e47ab5caa5fe34087299bd49fbae945a4583101ee3f0":"Process Proposal",
|
||||
"0xd45ad122361f16d6f50d7c4a73638f20ee48eff6186af15224e2a4a1f6d50171":"Sponsor Proposal"
|
||||
};
|
||||
|
||||
var Logs = $('HTTP Request').first().json.result.logs;
|
||||
var topicsFromLogs = [];
|
||||
|
||||
for (var i = 0; i < Logs.length; i++) {
|
||||
var log = Logs[i];
|
||||
topicsFromLogs.push(...log.topics); // Using spread operator to append topics array
|
||||
}
|
||||
|
||||
var data = {
|
||||
"method":"Unknown method" // Default value
|
||||
};
|
||||
|
||||
const opts = {
|
||||
"Submit Vote":{
|
||||
1:"member",
|
||||
2:"proposal",
|
||||
3:"vote"
|
||||
},
|
||||
"Submit Proposal":{
|
||||
1:"proposal",
|
||||
2:"dataHash"
|
||||
},
|
||||
"Process Proposal":{
|
||||
1:"member",
|
||||
2:"proposal",
|
||||
3:"vote"
|
||||
},
|
||||
"Sponsor Proposal":{
|
||||
1:"member",
|
||||
2:"proposal",
|
||||
3:"votingStarts"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check each topic in the logs against the topics object
|
||||
for (let i = 0; i < topicsFromLogs.length; i++) {
|
||||
const topic = topicsFromLogs[i];
|
||||
if (topics.hasOwnProperty(topic)) {
|
||||
data["method"] = topics[topic];
|
||||
console.log('Matched Option:', data["method"]);
|
||||
} else {
|
||||
if (opts.hasOwnProperty(data["method"])){
|
||||
var keys = opts[data["method"]];
|
||||
if (keys[i] != "member"){
|
||||
data[keys[i]] = hexToDecimal(topic);
|
||||
} else {
|
||||
data[keys[i]] = stripExtraZeros(topic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function hexToUtf8(hexStr) {
|
||||
return Buffer.from(hexStr, 'hex').toString('utf8');
|
||||
}
|
||||
|
||||
// Extracting data for specific methods
|
||||
if (data["method"]== "Submit Proposal"){
|
||||
const hexData = $('HTTP Request').first().json.result.logs[0].data;
|
||||
// Extracting segments from hexData (assuming it's already defined)
|
||||
const votingPeriodHex = hexData.slice(2, 66); // 64 characters (32 bytes) for votingPeriod
|
||||
const proposalDataHex = hexData.slice(66, 130); // 64 characters (32 bytes) for proposalData
|
||||
const expirationHex = hexData.slice(130, 194); // 64 characters (32 bytes) for expiration
|
||||
const baalGasHex = hexData.slice(194, 258); // 64 characters (32 bytes) for baalGas
|
||||
const selfSponsorHex = hexData.slice(258, 322); // 64 characters (32 bytes) for selfSponsor
|
||||
const timestampHex = hexData.slice(322, 386); // 64 characters (32 bytes) for timestamp
|
||||
const detailsHex = hexData.slice(386); // Remaining part for details
|
||||
|
||||
// Decode hex segments into decimal or string format
|
||||
const votingPeriod = hexToDecimal(votingPeriodHex);
|
||||
const proposalData = proposalDataHex;
|
||||
const expiration = hexToDecimal(expirationHex);
|
||||
const baalGas = hexToDecimal(baalGasHex);
|
||||
const selfSponsor = hexToDecimal(selfSponsorHex);
|
||||
const timestamp = hexToDecimal(timestampHex);
|
||||
|
||||
let detailsObj;
|
||||
detailsObj = hexToUtf8(detailsHex);
|
||||
const jsonStringStart = detailsObj.indexOf('{"');
|
||||
if (jsonStringStart !== -1) {
|
||||
detailsObj = detailsObj.slice(jsonStringStart);
|
||||
}
|
||||
|
||||
|
||||
// Construct the JSON object
|
||||
const jsonObject = {
|
||||
votingPeriod: votingPeriod,
|
||||
proposalData: proposalData,
|
||||
expiration: expiration,
|
||||
baalGas: baalGas,
|
||||
selfSponsor: selfSponsor,
|
||||
timestamp: timestamp,
|
||||
details: detailsObj
|
||||
};
|
||||
|
||||
data['data'] = jsonObject;
|
||||
} else if (data["method"]== "Submit Vote"){
|
||||
const hexData = $('HTTP Request').first().json.result.logs[0].data;
|
||||
data["votes"]= hexToDecimal(hexData)/1000000000000000000;
|
||||
} else if (data["method"]== "Process Proposal"){
|
||||
var logData = []
|
||||
for (var i = 0; i < Logs.length; i++) {
|
||||
if (Logs[i].topics[0]=="0xb4571f7e4e2c2b6e6185e47ab5caa5fe34087299bd49fbae945a4583101ee3f0"){
|
||||
data["proposal"] = hexToDecimal(Logs[i].topics[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
console.log(data);
|
||||
return data;
|
||||
|
Loading…
Reference in New Issue
Block a user