Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion apps/consumers/src/services/bot/slack-bot.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,8 @@ export class SlackBotService implements BotServiceInterface {
if (payload.metadata?.addresses) {
for (const [placeholder, address] of Object.entries(payload.metadata.addresses)) {
const displayName = await this.ensResolver.resolveDisplayName(address);
processedMessage = processedMessage.replace(`{{${placeholder}}}`, displayName);
const regex = new RegExp(`\\{\\{${placeholder}\\}\\}`, 'g');
processedMessage = processedMessage.replace(regex, displayName);
}
}

Expand Down
3 changes: 2 additions & 1 deletion apps/consumers/src/services/bot/telegram-bot.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@ export class TelegramBotService implements BotServiceInterface {
if (payload.metadata?.addresses) {
for (const [placeholder, address] of Object.entries(payload.metadata.addresses)) {
const displayName = await this.ensResolver.resolveDisplayName(address);
processedMessage = processedMessage.replace(`{{${placeholder}}}`, displayName);
const regex = new RegExp(`\\{\\{${placeholder}\\}\\}`, 'g');
processedMessage = processedMessage.replace(regex, displayName);
}
}

Expand Down
5 changes: 3 additions & 2 deletions apps/consumers/src/services/ens-resolver.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Handles ENS name resolution and reverse lookups using Viem.
*/

import { createPublicClient, http } from 'viem';
import { createPublicClient, http, getAddress } from 'viem';
import { mainnet } from 'viem/chains';
import { normalize } from 'viem/ens';

Expand Down Expand Up @@ -45,8 +45,9 @@ export class EnsResolverService {
*/
async resolveDisplayName(address: string): Promise<string> {
try {
const checksumAddress = getAddress(address);
const ensName = await this.client.getEnsName({
address: address as `0x${string}`
address: checksumAddress
});
if (ensName) return ensName;
} catch (error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ export class VoteConfirmationTriggerHandler extends BaseTriggerHandler<VoteEvent
chainId
},
addresses: {
voterAccountId: vote.voterAccountId
address: vote.voterAccountId
},
proposalId: vote.proposalId,
support: vote.support,
Expand All @@ -174,7 +174,6 @@ export class VoteConfirmationTriggerHandler extends BaseTriggerHandler<VoteEvent
daoId: vote.daoId,
proposalIdShort: vote.proposalId.slice(0, 8) + '...',
votingPower,
address: vote.voterAccountId,
...(hasReason && { reason: vote.reason! })
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,16 +152,22 @@ describe('VotingPowerTriggerHandler', () => {
};

await handler.handleMessage(mockMessage);

expect(mockNotificationClient.sendNotification).toHaveBeenCalledWith(
expect.objectContaining({
message: expect.stringContaining('🥳 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 received a new delegation in test-dao!')
message: expect.stringContaining('🥳 {{address}} received a new delegation in test-dao!'),
metadata: expect.objectContaining({
addresses: expect.objectContaining({
address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
delegator: '0xEF8305E140ac520225DAf050e2f71d5fBcC543e7'
})
})
})
);

expect(mockNotificationClient.sendNotification).toHaveBeenCalledWith(
expect.objectContaining({
message: expect.stringContaining('delegated to 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045')
message: expect.stringContaining('{{delegator}} delegated to {{address}}')
})
);
});
Expand All @@ -185,16 +191,22 @@ describe('VotingPowerTriggerHandler', () => {
};

await handler.handleMessage(mockMessage);

expect(mockNotificationClient.sendNotification).toHaveBeenCalledWith(
expect.objectContaining({
message: expect.stringContaining('✅ Delegation confirmed in test-dao!')
message: expect.stringContaining('✅ Delegation confirmed in test-dao!'),
metadata: expect.objectContaining({
addresses: expect.objectContaining({
delegatorAccount: '0xEF8305E140ac520225DAf050e2f71d5fBcC543e7',
delegate: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
})
})
})
);

expect(mockNotificationClient.sendNotification).toHaveBeenCalledWith(
expect.objectContaining({
message: expect.stringContaining('Account 0xEF8305E140ac520225DAf050e2f71d5fBcC543e7 delegated')
message: expect.stringContaining('Account {{delegatorAccount}} delegated')
})
);
});
Expand All @@ -218,16 +230,22 @@ describe('VotingPowerTriggerHandler', () => {
};

await handler.handleMessage(mockMessage);

expect(mockNotificationClient.sendNotification).toHaveBeenCalledWith(
expect.objectContaining({
message: expect.stringContaining('🥺 A delegator just undelegated in test-dao!')
message: expect.stringContaining('🥺 A delegator just undelegated in test-dao!'),
metadata: expect.objectContaining({
addresses: expect.objectContaining({
address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
delegator: '0xEF8305E140ac520225DAf050e2f71d5fBcC543e7'
})
})
})
);

expect(mockNotificationClient.sendNotification).toHaveBeenCalledWith(
expect.objectContaining({
message: expect.stringContaining('removed their delegation from 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045')
message: expect.stringContaining('removed their delegation from {{address}}')
})
);
});
Expand All @@ -251,16 +269,22 @@ describe('VotingPowerTriggerHandler', () => {
};

await handler.handleMessage(mockMessage);

expect(mockNotificationClient.sendNotification).toHaveBeenCalledWith(
expect.objectContaining({
message: expect.stringContaining('↩️ Undelegation confirmed in test-dao!')
message: expect.stringContaining('↩️ Undelegation confirmed in test-dao!'),
metadata: expect.objectContaining({
addresses: expect.objectContaining({
delegatorAccount: '0xEF8305E140ac520225DAf050e2f71d5fBcC543e7',
delegate: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
})
})
})
);

expect(mockNotificationClient.sendNotification).toHaveBeenCalledWith(
expect.objectContaining({
message: expect.stringContaining('Account 0xEF8305E140ac520225DAf050e2f71d5fBcC543e7 removed')
message: expect.stringContaining('Account {{delegatorAccount}} removed')
})
);
});
Expand Down Expand Up @@ -359,7 +383,7 @@ describe('VotingPowerTriggerHandler', () => {
expect(mockNotificationClient.sendNotification).toHaveBeenCalledTimes(1);
expect(mockNotificationClient.sendNotification).toHaveBeenCalledWith(
expect.objectContaining({
message: expect.stringContaining('🥳 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 received a new delegation')
message: expect.stringContaining('🥳 {{address}} received a new delegation')
})
);
});
Expand Down Expand Up @@ -450,15 +474,44 @@ describe('VotingPowerTriggerHandler', () => {
triggerId: 'voting-power-changed',
events: [transferEvent]
};

await handler.handleMessage(mockMessage);

expect(mockNotificationClient.sendNotification).toHaveBeenCalledWith(
expect.objectContaining({
message: expect.stringContaining('📉 Voting power decreased in test-dao!')
})
);
});

it('should include address in metadata for ENS resolution', async () => {
const transferEvent = {
accountId: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
daoId: 'test-dao',
transactionHash: 'tx123',
changeType: 'transfer',
delta: '1000',
chainId: 1,
timestamp: '2023-01-01T00:00:00Z'
};

const mockMessage: DispatcherMessage = {
triggerId: 'voting-power-changed',
events: [transferEvent]
};

await handler.handleMessage(mockMessage);

expect(mockNotificationClient.sendNotification).toHaveBeenCalledWith(
expect.objectContaining({
metadata: expect.objectContaining({
addresses: expect.objectContaining({
address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
})
})
})
);
});
});

describe('other voting power change notifications', () => {
Expand All @@ -477,12 +530,17 @@ describe('VotingPowerTriggerHandler', () => {
triggerId: 'voting-power-changed',
events: [otherEvent]
};

await handler.handleMessage(mockMessage);

expect(mockNotificationClient.sendNotification).toHaveBeenCalledWith(
expect.objectContaining({
message: expect.stringContaining('⚡ Voting power changed for 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 in test-dao!')
message: expect.stringContaining('⚡ Voting power increased for {{address}} in test-dao!'),
metadata: expect.objectContaining({
addresses: expect.objectContaining({
address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
})
})
})
);
});
Expand All @@ -502,18 +560,76 @@ describe('VotingPowerTriggerHandler', () => {
triggerId: 'voting-power-changed',
events: [otherEvent]
};

await handler.handleMessage(mockMessage);

expect(mockNotificationClient.sendNotification).toHaveBeenCalledWith(
expect.objectContaining({
message: expect.stringContaining('⚡ Voting power changed for 0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045 in test-dao!')
message: expect.stringContaining('⚡ Voting power increased for {{address}} in test-dao!'),
metadata: expect.objectContaining({
addresses: expect.objectContaining({
address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
})
})
})
);

});

it('should send generic voting power decreased notification', async () => {
const otherEvent = {
accountId: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
daoId: 'test-dao',
transactionHash: 'tx123',
changeType: 'other',
delta: '-1000',
chainId: 1,
timestamp: '2023-01-01T00:00:00Z'
};

const mockMessage: DispatcherMessage = {
triggerId: 'voting-power-changed',
events: [otherEvent]
};

await handler.handleMessage(mockMessage);

expect(mockNotificationClient.sendNotification).toHaveBeenCalledWith(
expect.objectContaining({
message: expect.stringContaining('⚡ Voting power decreased for {{address}} in test-dao!'),
metadata: expect.objectContaining({
addresses: expect.objectContaining({
address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
})
})
})
);
});

it('should include address in metadata for ENS resolution', async () => {
const otherEvent = {
accountId: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045',
daoId: 'test-dao',
transactionHash: 'tx123',
changeType: 'other',
delta: '1000',
chainId: 1,
timestamp: '2023-01-01T00:00:00Z'
};

const mockMessage: DispatcherMessage = {
triggerId: 'voting-power-changed',
events: [otherEvent]
};

await handler.handleMessage(mockMessage);

expect(mockNotificationClient.sendNotification).toHaveBeenCalledWith(
expect.objectContaining({
message: expect.stringContaining('Voting power activity detected.')
metadata: expect.objectContaining({
addresses: expect.objectContaining({
address: '0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045'
})
})
})
);
});
Expand Down
Loading