Skip to content

Commit

Permalink
Feat/erc20 track deposit withdraw staging (#866) TG-222 #staging
Browse files Browse the repository at this point in the history
* feat: erc20 track deposit & withdrawal

* refactor: review

* refactor: log error when decode activity fail

* refactor: review
  • Loading branch information
phamphong9981 authored Jul 29, 2024
1 parent eeaff7a commit 12eb3d1
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 14 deletions.
3 changes: 2 additions & 1 deletion ci/config.json.ci
Original file line number Diff line number Diff line change
Expand Up @@ -387,7 +387,8 @@
"key": "erc20",
"blocksPerCall": 100,
"millisecondRepeatJob": 5000,
"chunkSizeInsert": 1000
"chunkSizeInsert": 1000,
"wrapExtensionContract": ["0xe974cc14c93fc6077b0d65f98832b846c5454a0b"]
},
"erc721": {
"key": "erc721",
Expand Down
3 changes: 2 additions & 1 deletion config.json
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,8 @@
"key": "erc20",
"blocksPerCall": 100,
"millisecondRepeatJob": 2000,
"chunkSizeInsert": 1000
"chunkSizeInsert": 1000,
"wrapExtensionContract": ["0xe974cc14c93fc6077b0d65f98832b846c5454a0b"]
},
"erc721": {
"key": "erc721",
Expand Down
12 changes: 10 additions & 2 deletions src/services/evm/erc20.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,15 +144,23 @@ export default class Erc20Service extends BullableService {
const erc20Activities: Erc20Activity[] = [];
erc20Events.forEach((e) => {
if (e.topic0 === ERC20_EVENT_TOPIC0.TRANSFER) {
const activity = Erc20Handler.buildTransferActivity(e);
const activity = Erc20Handler.buildTransferActivity(e, this.logger);
if (activity) {
erc20Activities.push(activity);
}
} else if (e.topic0 === ERC20_EVENT_TOPIC0.APPROVAL) {
const activity = Erc20Handler.buildApprovalActivity(e);
const activity = Erc20Handler.buildApprovalActivity(e, this.logger);
if (activity) {
erc20Activities.push(activity);
}
} else if (config.erc20.wrapExtensionContract.includes(e.address)) {
const wrapActivity = Erc20Handler.buildWrapExtensionActivity(
e,
this.logger
);
if (wrapActivity) {
erc20Activities.push(wrapActivity);
}
}
});
erc20CosmosEvents.forEach((event) => {
Expand Down
103 changes: 95 additions & 8 deletions src/services/evm/erc20_handler.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { decodeAbiParameters, keccak256, toHex } from 'viem';
import Moleculer from 'moleculer';
import { Dictionary } from 'lodash';
import Moleculer from 'moleculer';
import { decodeAbiParameters, keccak256, toHex } from 'viem';
import config from '../../../config.json' assert { type: 'json' };
import { Erc20Activity, Event, EventAttribute, EvmEvent } from '../../models';
import { AccountBalance } from '../../models/account_balance';
import { ZERO_ADDRESS } from './constant';
import { convertBech32AddressToEthAddress } from './utils';
import config from '../../../config.json' assert { type: 'json' };

export const ERC20_ACTION = {
TRANSFER: 'transfer',
APPROVAL: 'approval',
DEPOSIT: 'deposit',
WITHDRAWAL: 'withdrawal',
};
export const ABI_TRANSFER_PARAMS = {
FROM: {
Expand Down Expand Up @@ -42,6 +44,8 @@ export const ABI_APPROVAL_PARAMS = {
export const ERC20_EVENT_TOPIC0 = {
TRANSFER: keccak256(toHex('Transfer(address,address,uint256)')),
APPROVAL: keccak256(toHex('Approval(address,address,uint256)')),
DEPOSIT: keccak256(toHex('Deposit(address,uint256)')),
WITHDRAWAL: keccak256(toHex('Withdrawal(address,uint256)')),
};
export class Erc20Handler {
// key: {accountId}_{erc20ContractAddress}
Expand All @@ -60,7 +64,13 @@ export class Erc20Handler {

process() {
this.erc20Activities.forEach((erc20Activity) => {
if (erc20Activity.action === ERC20_ACTION.TRANSFER) {
if (
[
ERC20_ACTION.TRANSFER,
ERC20_ACTION.DEPOSIT,
ERC20_ACTION.WITHDRAWAL,
].includes(erc20Activity.action)
) {
this.handlerErc20Transfer(erc20Activity);
}
});
Expand Down Expand Up @@ -113,7 +123,10 @@ export class Erc20Handler {
}
}

static buildTransferActivity(e: EvmEvent) {
static buildTransferActivity(
e: EvmEvent,
logger: Moleculer.LoggerInstance
): Erc20Activity | undefined {
try {
const [from, to, amount] = decodeAbiParameters(
[
Expand All @@ -135,7 +148,8 @@ export class Erc20Handler {
tx_hash: e.tx_hash,
evm_tx_id: e.evm_tx_id,
});
} catch {
} catch (e) {
logger.error(e);
return undefined;
}
}
Expand Down Expand Up @@ -209,7 +223,10 @@ export class Erc20Handler {
}
}

static buildApprovalActivity(e: EvmEvent) {
static buildApprovalActivity(
e: EvmEvent,
logger: Moleculer.LoggerInstance
): Erc20Activity | undefined {
try {
const [from, to, amount] = decodeAbiParameters(
[
Expand All @@ -231,7 +248,77 @@ export class Erc20Handler {
tx_hash: e.tx_hash,
evm_tx_id: e.evm_tx_id,
});
} catch {
} catch (e) {
logger.error(e);
return undefined;
}
}

static buildWrapExtensionActivity(
e: EvmEvent,
logger: Moleculer.LoggerInstance
): Erc20Activity | undefined {
if (e.topic0 === ERC20_EVENT_TOPIC0.DEPOSIT) {
const activity = Erc20Handler.buildWrapDepositActivity(e, logger);
return activity;
}
if (e.topic0 === ERC20_EVENT_TOPIC0.WITHDRAWAL) {
const activity = Erc20Handler.buildWrapWithdrawalActivity(e, logger);
return activity;
}
return undefined;
}

private static buildWrapDepositActivity(
e: EvmEvent,
logger: Moleculer.LoggerInstance
): Erc20Activity | undefined {
try {
const [to, amount] = decodeAbiParameters(
[ABI_TRANSFER_PARAMS.TO, ABI_APPROVAL_PARAMS.VALUE],
(e.topic1 + toHex(e.data).slice(2)) as `0x${string}`
) as [string, bigint];
return Erc20Activity.fromJson({
evm_event_id: e.id,
sender: e.sender,
action: ERC20_ACTION.DEPOSIT,
erc20_contract_address: e.address,
amount: amount.toString(),
from: ZERO_ADDRESS,
to: to.toLowerCase(),
height: e.block_height,
tx_hash: e.tx_hash,
evm_tx_id: e.evm_tx_id,
});
} catch (e) {
logger.error(e);
return undefined;
}
}

private static buildWrapWithdrawalActivity(
e: EvmEvent,
logger: Moleculer.LoggerInstance
): Erc20Activity | undefined {
try {
const [from, amount] = decodeAbiParameters(
[ABI_TRANSFER_PARAMS.FROM, ABI_APPROVAL_PARAMS.VALUE],
(e.topic1 + toHex(e.data).slice(2)) as `0x${string}`
) as [string, bigint];
return Erc20Activity.fromJson({
evm_event_id: e.id,
sender: e.sender,
action: ERC20_ACTION.WITHDRAWAL,
erc20_contract_address: e.address,
amount: amount.toString(),
from: from.toLowerCase(),
to: ZERO_ADDRESS,
height: e.block_height,
tx_hash: e.tx_hash,
evm_tx_id: e.evm_tx_id,
});
} catch (e) {
logger.error(e);
return undefined;
}
}
Expand Down
6 changes: 4 additions & 2 deletions test/unit/services/erc20/erc20_handler.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ export default class Erc20HandlerTest {
toHex(evmEvent.data).slice(2)) as `0x${string}`
) as [string, string, bigint];
const result = Erc20Handler.buildTransferActivity(
EvmEvent.fromJson(evmEvent)
EvmEvent.fromJson(evmEvent),
this.broker.logger
);
expect(result).toMatchObject({
evm_event_id: evmEvent.id,
Expand Down Expand Up @@ -100,7 +101,8 @@ export default class Erc20HandlerTest {
sender: 'evmos1u47fy86l8uaz4t0f533d4dctpjuhmm2dh3ezg0',
};
const result = Erc20Handler.buildApprovalActivity(
EvmEvent.fromJson(evmEvent)
EvmEvent.fromJson(evmEvent),
this.broker.logger
);
const [from, to, amount] = decodeAbiParameters(
[
Expand Down

0 comments on commit 12eb3d1

Please sign in to comment.