Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Account abstraction context #361

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
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
25 changes: 25 additions & 0 deletions src/commands/runContextualizers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { program } from './main';
import { fetchTransactions } from './utils';
import { Transaction } from '../types';
import { contextualizer } from '../contextualizers';
import { Hash } from 'viem';

export function registerRunContextualizersCommand() {
program
Expand Down Expand Up @@ -36,6 +37,30 @@ export function registerRunContextualizersCommand() {
err,
);
}

if (transaction.pseudotransactions?.length) {
transaction.pseudotransactions.forEach((pseudoTransaction) => {
const toContextualize = {
...pseudoTransaction,
hash: pseudoTransaction.meta.key as unknown as Hash,
};

console.log(`Running contextualizer on pseudoTransaction`);
try {
const txResult = contextualizer.contextualize(toContextualize);
if (!txResult.from) {
console.error(
`No matching contextualizer on pseudoTransaction ${pseudoTransaction.meta}`,
);
}
} catch (err) {
console.error(
`failed to run contextualizer on pseudoTransaction ${pseudoTransaction.meta}: `,
err,
);
}
});
}
});

console.log('Successfully ran contextualizers');
Expand Down
17 changes: 17 additions & 0 deletions src/contextualizers/contextualizer.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { contextualizer } from './index';
import { Transaction } from '../types';
import { contextSummary } from '../helpers/utils';

// contract deployed
import contractDeployed0x88e7d866 from './test/transactions/contractDeployed-0x88e7d866.json';
Expand Down Expand Up @@ -44,6 +45,8 @@ import ens0xdb203e93 from './test/transactions/ens-0xdb203e93.json';
import ens0xea1b4ab6 from './test/transactions/ens-0xea1b4ab6.json';
import ensRegistrar0xb14b4771 from './test/transactions/ensRegistrar-0xb14b4771.json';
import ensBulkRenew0x25add712 from './test/transactions/ensBulkRenew-0x25add712.json';
// ERC4337
import accountAbstractionEthTransfer0x7a5e9ca7 from './test/transactions/erc4337-eth-transfer-0x7a5e9ca7.json';

describe('ContextualizerService', () => {
describe('Detect transactions correctly', () => {
Expand Down Expand Up @@ -235,4 +238,18 @@ describe('ContextualizerService', () => {
expect(bulkRenew.context?.summaries?.en.title).toBe('ENS');
});
});

describe('pseudo transactions', () => {
it('Should detect ETH transfer', () => {
const transfer = contextualizer.contextualize(
(accountAbstractionEthTransfer0x7a5e9ca7 as unknown as Transaction)
.pseudotransactions![0],
);

expect(transfer.context?.summaries?.en.title).toBe('ETH Transfer');
expect(contextSummary(transfer.context)).toBe(
'0x2991c3845396c9f1d262b2ca0674111a59e2c90a SENT 0.005 ETH to 0x5d72015cc621025c265fabffc2fa55ac4821d79f',
);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Transaction } from '../../../types';
import { detect, generate } from './accountAbstraction';
import { contextSummary } from '../../../helpers/utils';

import accountAbstractionSingleBundle0x6ae53f78 from '../../test/transactions/erc4337-eth-transfer-0x6ae53f78.json';
import accountAbstractionMultipleBundles0xc7d49ad1 from '../../test/transactions/erc4337-multiple-ops-0xc7d49ad1.json';
import catchall0xc35c01ac from '../../test/transactions/catchall-0xc35c01ac.json';

describe('Token Transfer', () => {
it('Should detect token transfer transaction', () => {
const accountAbstraction = detect(
accountAbstractionSingleBundle0x6ae53f78 as unknown as Transaction,
);
expect(accountAbstraction).toBe(true);
});

it('Should not detect accountAbstraction transaction', () => {
const other = detect(catchall0xc35c01ac as unknown as Transaction);
expect(other).toBe(false);
});

describe('Should generate context', () => {
it('works with 1 bundle', () => {
const transaction = generate(
accountAbstractionSingleBundle0x6ae53f78 as unknown as Transaction,
);

expect(transaction.context?.summaries?.en.title).toBe('ERC4337 Bundle');
expect(contextSummary(transaction.context)).toBe(
'0xa5fdfcbceeceb5741ef73f86cf3ed6e80e5e920d SUBMITTED_ACCOUNT_ABSTRACTION_BUNDLE with 1 user op',
);
});

it('works with multiple bundles', () => {
const transaction = generate(
accountAbstractionMultipleBundles0xc7d49ad1 as unknown as Transaction,
);

expect(transaction.context?.summaries?.en.title).toBe('ERC4337 Bundle');
expect(contextSummary(transaction.context)).toBe(
'0x13284299074631de638be076a5aaf73b1d471afd SUBMITTED_ACCOUNT_ABSTRACTION_BUNDLE with 2 user ops',
);
});
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { HeuristicContextActionEnum, Transaction } from '../../../types';

export function contextualize(transaction: Transaction): Transaction {
if (!detect(transaction)) return transaction;

return generate(transaction);
}

export function detect(transaction: Transaction): boolean {
return !!transaction.pseudotransactions?.length;
}

export function generate(transaction: Transaction): Transaction {
if (!transaction.pseudotransactions) return transaction;

const userOps = transaction.pseudotransactions.length;
transaction.context = {
variables: {
subject: {
type: 'address',
value: transaction.from,
},
userOps: {
type: 'number',
emphasis: true,
value: userOps,
unit: `user op${userOps > 1 ? 's' : ''}`,
},
contextAction: {
type: 'contextAction',
value: HeuristicContextActionEnum.SUBMITTED_ACCOUNT_ABSTRACTION_BUNDLE,
},
},
summaries: {
category: 'ACCOUNT_ABSTRACTION',
en: {
title: 'ERC4337 Bundle',
default: '[[subject]][[contextAction]]with[[userOps]]',
},
},
};

return transaction;
}
1 change: 1 addition & 0 deletions src/contextualizers/heuristics/accountAbstraction/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { contextualize as accountAbstractionContextualizer } from './accountAbstraction';
2 changes: 2 additions & 0 deletions src/contextualizers/heuristics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { erc20MintContextualizer } from './erc20Mint';
import { erc721MintContextualizer } from './erc721Mint';
import { erc1155MintContextualizer } from './erc1155Mint';
import { tokenTransferContextualizer } from './tokenTransfer';
import { accountAbstractionContextualizer } from './accountAbstraction';

const children = {
cancelPendingTransactionContextualizer,
Expand All @@ -27,6 +28,7 @@ const children = {
tokenAirdropContextualizer,
tokenApprovalContextualizer,
tokenTransferContextualizer,
accountAbstractionContextualizer,
};

const contextualize = makeContextualize(children);
Expand Down
Loading
Loading