@mentaproject/client 0.1.11 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,8 @@
1
- import { IPersistenceAdapter, TransactionWithAccount, GetPersistentTransactionsParams } from '../types/PersistenceAdapter';
1
+ import { Address } from '@mentaproject/core/types';
2
+ import { IPersistenceAdapter } from '../types/PersistenceAdapter';
2
3
  import { Account } from '../structures/Account';
3
- import { MentaClient } from '../structures';
4
+ import { MentaClient, Transaction } from '../structures';
5
+ import { GetTransactionsParams } from 'src/types';
4
6
  /**
5
7
  * Manages the persistence of data, including transactions, using a specified persistence adapter.
6
8
  * It handles fetching data from both local storage and remote sources, and synchronizing them.
@@ -19,7 +21,7 @@ export declare class PersistenceManager {
19
21
  * @param params - Parameters for retrieving transactions.
20
22
  * @returns A promise that resolves to an array of transactions with associated account information.
21
23
  */
22
- getTransactions(params: GetPersistentTransactionsParams): Promise<TransactionWithAccount[]>;
24
+ getTransactions(address: Address, params: GetTransactionsParams): Promise<Transaction[]>;
23
25
  /**
24
26
  * Synchronizes an account's transactions from the remote source to the local persistence.
25
27
  * It fetches new transactions starting from the last synced block and updates the local storage.
@@ -19,8 +19,8 @@ export class PersistenceManager {
19
19
  * @param params - Parameters for retrieving transactions.
20
20
  * @returns A promise that resolves to an array of transactions with associated account information.
21
21
  */
22
- async getTransactions(params) {
23
- const localTransactions = await this.persistenceAdapter.getTransactions(params);
22
+ async getTransactions(address, params) {
23
+ const localTransactions = await this.persistenceAdapter.getTransactions(address, params);
24
24
  return localTransactions;
25
25
  }
26
26
  /**
@@ -67,7 +67,7 @@ export declare class Account {
67
67
  * @param {'asc' | 'desc'} [options.sort] - The sorting order for transactions based on block number ('asc' for ascending, 'desc' for descending).
68
68
  * @returns {Promise<Transaction[]>} A promise that resolves to an array of transactions.
69
69
  */
70
- transactions(options: GetTransactionsParams): Promise<Transaction[]>;
70
+ transactions(params: GetTransactionsParams): Promise<Transaction[]>;
71
71
  /**
72
72
  * Synchronizes the account's transactions with the remote data source using the configured `PersistenceManager`.
73
73
  * @description This method initiates a synchronization process to ensure that the local cache of transactions
@@ -93,19 +93,14 @@ export class Account {
93
93
  * @param {'asc' | 'desc'} [options.sort] - The sorting order for transactions based on block number ('asc' for ascending, 'desc' for descending).
94
94
  * @returns {Promise<Transaction[]>} A promise that resolves to an array of transactions.
95
95
  */
96
- async transactions(options) {
96
+ async transactions(params) {
97
97
  if (!this.persistenceManager) {
98
98
  // If persistence is not configured, fetch directly from remote
99
- const hashes = await this._fetchTransactions(options);
99
+ const hashes = await this._fetchTransactions(params);
100
100
  const transactions = await Promise.all(hashes.map(hash => this.client.transactions.get({ hash })));
101
101
  return transactions;
102
102
  }
103
- // If persistence is configured, try to get from cache first
104
- const filters = {
105
- accountAddress: this.address,
106
- ...options
107
- };
108
- const cachedTransactions = await this.persistenceManager.getTransactions(filters);
103
+ const cachedTransactions = await this.persistenceManager.getTransactions(this.address, params);
109
104
  return cachedTransactions;
110
105
  }
111
106
  /**
@@ -1,12 +1,6 @@
1
- import { Transaction } from '../structures';
1
+ import { Address } from '@mentaproject/core/types';
2
+ import { Transaction } from '../structures/Transaction';
2
3
  import { GetTransactionsParams } from './Account';
3
- export interface TransactionWithAccount extends Transaction {
4
- accountAddress: string;
5
- timestamp: number;
6
- }
7
- export interface GetPersistentTransactionsParams extends GetTransactionsParams {
8
- accountAddress: string;
9
- }
10
4
  /**
11
5
  * @interface IPersistenceAdapter
12
6
  * @description Defines the contract for persistence layers, ensuring consistent data storage and retrieval operations.
@@ -23,9 +17,9 @@ export interface IPersistenceAdapter {
23
17
  * @method getTransactions
24
18
  * @description Retrieves a paginated list of transactions for a specific account based on provided filters.
25
19
  * @param {GetTransactionsFilters} filters - An object containing filters for retrieving transactions, such as account address, block range, pagination, and sort order.
26
- * @returns {Promise<TransactionWithAccount[]>} A Promise that resolves with an array of transactions matching the filters.
20
+ * @returns {Promise<Transaction[]>} A Promise that resolves with an array of transactions matching the filters.
27
21
  */
28
- getTransactions(filters: GetPersistentTransactionsParams): Promise<TransactionWithAccount[]>;
22
+ getTransactions(address: Address, params: GetTransactionsParams): Promise<Transaction[]>;
29
23
  /**
30
24
  * @method getLastSyncedBlock
31
25
  * @description Retrieves the last synced block number for a given account. This is used to track the synchronization progress of an account's transactions.
@@ -1,2 +1 @@
1
- ;
2
1
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mentaproject/client",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "description": "High level EVM library used into the Menta App to facilitate Blockchain interactions. ",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -124,7 +124,7 @@ describe('Account', () => {
124
124
  (mockPersistenceManager.getTransactions as jest.Mock).mockResolvedValue(mockTransactions);
125
125
 
126
126
  const result = await account.transactions({});
127
- expect(mockPersistenceManager.getTransactions).toHaveBeenCalledWith({ accountAddress: mockAddress });
127
+ expect(mockPersistenceManager.getTransactions).toHaveBeenCalledWith(mockAddress, {});
128
128
  expect(result).toEqual(mockTransactions);
129
129
  });
130
130
 
@@ -150,8 +150,8 @@ describe('Account', () => {
150
150
 
151
151
  describe('syncTransactions', () => {
152
152
  it('should call syncTransactions on the persistence manager', async () => {
153
- await account.syncTransactions();
154
- expect(mockPersistenceManager.syncTransactions).toHaveBeenCalledWith(account);
153
+ await account.syncTransactions(1n);
154
+ expect(mockPersistenceManager.syncTransactions).toHaveBeenCalledWith(account, 1n);
155
155
  });
156
156
 
157
157
  it('should throw an error if persistence manager is not configured', async () => {
@@ -1,6 +0,0 @@
1
- import { Address, CoreClient } from "src/types";
2
- import { Account } from "./Account";
3
- export declare class ContractAccount extends Account {
4
- constructor(rpcClient: CoreClient, address: Address);
5
- getType(): Promise<any>;
6
- }
@@ -1,12 +0,0 @@
1
- import { Account } from "./Account";
2
- import { getContractType } from "@mentaproject/contracts";
3
- export class ContractAccount extends Account {
4
- constructor(rpcClient, address) {
5
- super(rpcClient, address);
6
- }
7
- ;
8
- async getType() {
9
- return await getContractType(this.rpcClient, this.address);
10
- }
11
- }
12
- ;
File without changes
@@ -1 +0,0 @@
1
- "use strict";
@@ -1,20 +0,0 @@
1
- declare class BaseService {
2
- id: string;
3
- rpcClient: any;
4
- address: string;
5
- constructor(id: string, rpcClient: any, address: string);
6
- protected fetchCode(): Promise<string | null>;
7
- }
8
- type ContractService = BaseService & {
9
- isContractMarker: true;
10
- getContractDetails: () => string;
11
- };
12
- declare class AccountVerifier extends BaseService {
13
- isContractMarker?: true;
14
- getContractDetails?: () => string;
15
- /**
16
- * Vérifie si le compte est un contrat.
17
- */
18
- isContractAccount(): Promise<this is ContractService>;
19
- processAccount(): Promise<void>;
20
- }
@@ -1,62 +0,0 @@
1
- "use strict";
2
- // test-guard.ts
3
- // Simulez vos dépendances externes si nécessaire pour ce test
4
- // Par exemple :
5
- // declare function getCode(rpcClient: any, params: { address: string }): Promise<string | null | undefined>;
6
- // interface RpcClientType {}
7
- // Définition de la classe de base
8
- class BaseService {
9
- constructor(id, rpcClient, address) {
10
- this.id = id;
11
- this.rpcClient = rpcClient;
12
- this.address = address;
13
- }
14
- // Méthode pour simuler l'appel externe
15
- async fetchCode() {
16
- // Remplacez par votre vrai appel à getCode si possible pour le test,
17
- // ou utilisez ce mock :
18
- console.log(`Workspaceing code for ${this.address} using client ${this.rpcClient}`);
19
- if (this.address === "contract_address") {
20
- return "0x12345"; // code de contrat valide
21
- }
22
- return "0x"; // pas de code ou compte externe
23
- }
24
- }
25
- // Classe contenant le type guard asynchrone
26
- class AccountVerifier extends BaseService {
27
- /**
28
- * Vérifie si le compte est un contrat.
29
- */
30
- async isContractAccount() {
31
- const code = await this.fetchCode(); // Utilise la méthode de la classe (ou de la base)
32
- if (code && typeof code === 'string' && code !== '0x' && code.length > 2) {
33
- // Logique pour rendre 'this' conforme à ContractService
34
- this.isContractMarker = true;
35
- this.getContractDetails = () => `Details for contract ${this.address}`;
36
- return true;
37
- }
38
- else {
39
- delete this.isContractMarker;
40
- delete this.getContractDetails;
41
- return false;
42
- }
43
- }
44
- async processAccount() {
45
- if (await this.isContractAccount()) {
46
- // Ici, 'this' est affiné en ContractService
47
- console.log(`Account ${this.id} (${this.address}) is a contract.`);
48
- console.log(this.getContractDetails());
49
- console.log(`Marker: ${this.isContractMarker}`);
50
- }
51
- else {
52
- // Ici, 'this' est AccountVerifier (ou BaseService)
53
- console.log(`Account ${this.id} (${this.address}) is not a contract.`);
54
- }
55
- }
56
- }
57
- // Test
58
- // const mockRpcClient: RpcClientType = {}; // Votre client RPC
59
- // const verifier1 = new AccountVerifier("service1", mockRpcClient, "contract_address");
60
- // const verifier2 = new AccountVerifier("service2", mockRpcClient, "eoa_address");
61
- // verifier1.processAccount();
62
- // verifier2.processAccount();
@@ -1,44 +0,0 @@
1
- import { Transaction } from 'src/structures';
2
- import { GetTransactionsOptions } from './Account';
3
- export interface TransactionWithAccount extends Transaction {
4
- accountAddress: string;
5
- timestamp: number;
6
- }
7
- export interface GetTransactionsFilters extends GetTransactionsOptions {
8
- accountAddress: string;
9
- }
10
- /**
11
- * @interface IPersistenceAdapter
12
- * @description Defines the contract for persistence layers, ensuring consistent data storage and retrieval operations.
13
- */
14
- export interface IPersistenceAdapter {
15
- /**
16
- * @method upsertTransactions
17
- * @description Inserts or updates a list of transactions. The operation must be atomic.
18
- * @param {TransactionWithAccount[]} transactions - An array of transaction data, including associated account addresses and timestamps.
19
- * @returns {Promise<void>} A Promise that resolves when the transactions have been successfully inserted or updated.
20
- */
21
- upsertTransactions(transactions: TransactionWithAccount[]): Promise<void>;
22
- /**
23
- * @method getTransactions
24
- * @description Retrieves a paginated list of transactions for a specific account based on provided filters.
25
- * @param {GetTransactionsFilters} filters - An object containing filters for retrieving transactions, such as account address, block range, pagination, and sort order.
26
- * @returns {Promise<TransactionWithAccount[]>} A Promise that resolves with an array of transactions matching the filters.
27
- */
28
- getTransactions(filters: GetTransactionsFilters): Promise<TransactionWithAccount[]>;
29
- /**
30
- * @method getLastSyncedBlock
31
- * @description Retrieves the last synced block number for a given account. This is used to track the synchronization progress of an account's transactions.
32
- * @param {string} accountAddress - The address of the account for which to retrieve the last synced block number.
33
- * @returns {Promise<number | null>} A Promise that resolves with the last synced block number, or `null` if no block has been synced for the account.
34
- */
35
- getLastSyncedBlock(accountAddress: string): Promise<bigint | null>;
36
- /**
37
- * @method setLastSyncedBlock
38
- * @description Saves the last synced block number for a given account. This updates the synchronization progress for an account.
39
- * @param {string} accountAddress - The address of the account for which to save the last synced block number.
40
- * @param {number} blockNumber - The block number to save as the last synced block for the account.
41
- * @returns {Promise<void>} A Promise that resolves when the last synced block number has been successfully saved.
42
- */
43
- setLastSyncedBlock(accountAddress: string, blockNumber: number): Promise<void>;
44
- }
@@ -1,2 +0,0 @@
1
- ;
2
- export {};
@@ -1,9 +0,0 @@
1
- import { GetTransactionReceiptReturnType } from "@mentaproject/core/types";
2
- export interface IDecodedLog<T extends {
3
- [key: string]: any;
4
- } = {}> {
5
- eventName: string;
6
- args: T;
7
- }
8
- export interface ITransactionReceiptData extends GetTransactionReceiptReturnType {
9
- }
@@ -1,3 +0,0 @@
1
- ;
2
- ;
3
- export {};
@@ -1,13 +0,0 @@
1
- import { ICache, ICacheConfig } from '../types/Cache';
2
- export declare class Cache implements ICache {
3
- private cache;
4
- config: ICacheConfig;
5
- private blockNumber;
6
- constructor(blockNumber: bigint, options?: Partial<ICacheConfig>);
7
- protected isExpired(expiry: bigint): boolean;
8
- setBlockNumber(blockNumber: bigint): void;
9
- set<T>(key: string, value: T, ttl?: number): Promise<void>;
10
- get<T>(key: string): Promise<T | undefined>;
11
- has(key: string): Promise<boolean>;
12
- private evict;
13
- }
@@ -1,57 +0,0 @@
1
- export class Cache {
2
- constructor(blockNumber, options) {
3
- this.cache = new Map();
4
- this.blockNumber = blockNumber;
5
- this.config = {
6
- maxSize: 500,
7
- defaultTtl: 1,
8
- ttlPolicies: options?.ttlPolicies || {},
9
- ...options,
10
- };
11
- }
12
- ;
13
- isExpired(expiry) {
14
- return this.blockNumber > expiry;
15
- }
16
- ;
17
- setBlockNumber(blockNumber) {
18
- this.blockNumber = blockNumber;
19
- }
20
- async set(key, value, ttl = this.config.defaultTtl) {
21
- if (this.cache.has(key)) {
22
- this.cache.delete(key);
23
- }
24
- if (this.cache.size >= this.config.maxSize)
25
- this.evict();
26
- const expiry = this.blockNumber + BigInt(ttl);
27
- this.cache.set(key, { value, expiry });
28
- }
29
- async get(key) {
30
- const entry = this.cache.get(key);
31
- if (!entry)
32
- return undefined;
33
- if (this.isExpired(entry.expiry)) {
34
- this.cache.delete(key);
35
- return undefined;
36
- }
37
- this.cache.delete(key);
38
- this.cache.set(key, entry);
39
- return entry.value;
40
- }
41
- async has(key) {
42
- const entry = this.cache.get(key);
43
- if (!entry)
44
- return false;
45
- if (this.isExpired(entry.expiry)) {
46
- this.cache.delete(key);
47
- return false;
48
- }
49
- return true;
50
- }
51
- evict() {
52
- const oldestKey = this.cache.keys().next().value;
53
- if (!oldestKey)
54
- return;
55
- this.cache.delete(oldestKey);
56
- }
57
- }
@@ -1,15 +0,0 @@
1
- import { Abi, Address } from 'viem';
2
- import { CoreClient } from '@mentaproject/core/types';
3
- /**
4
- * Vérifie de manière plus "absolue" si un contrat est conforme à une ABI
5
- * en utilisant ERC-165 (if applicable) et en simulant les appels de fonctions.
6
- *
7
- * @param client - Le client viem connecté au réseau.
8
- * @param contractAddress - L'adresse du contrat à vérifier.
9
- * @param contractAbi - L'ABI complète du contrat.
10
- * @param options - Options pour la vérification : { erc165InterfaceId?: any } // Utilisation de 'any' pour contourner l'erreur de type bytes4
11
- * @returns True si le contrat semble implémenter toutes les fonctions de l'ABI (Selon les checks), False sinon.
12
- */
13
- export declare function isContractCompliantWithAbi(client: CoreClient, contractAddress: Address, contractAbi: Abi, options?: {
14
- erc165InterfaceId?: any;
15
- }): Promise<boolean>;
@@ -1,280 +0,0 @@
1
- import { parseAbi, } from 'viem';
2
- import { getCode, readContract, simulateContract } from '@mentaproject/core/actions'; // Importer les actions depuis viem/actions
3
- // import type { bytes4, AbiParameter, AbiParameterWithComponents } from 'viem'; // Impossible d'importer ces types directement dans cette version de viem
4
- const zeroAddress = '0xB21fD8AF36937Cf0ac1B84368E756C580BFdA342';
5
- // --- Configuration du client viem (remplacez par votre configuration) ---
6
- // const client = createPublicClient({
7
- // chain: mainnet, // ou une autre chaîne
8
- // transport: http() // ou autre transport
9
- // });
10
- // ---------------------------------------------------------------------
11
- // Helper pour générer des paramètres factices basés sur le type ABI
12
- function generateDummyArgs(inputs) {
13
- return inputs.map(input => {
14
- // Gérer les types simples
15
- switch (input.type) {
16
- case 'address':
17
- return zeroAddress; // Adresse nulle
18
- case 'uint8':
19
- case 'uint16':
20
- case 'uint24':
21
- case 'uint32':
22
- case 'uint40':
23
- case 'uint48':
24
- case 'uint56':
25
- case 'uint64':
26
- case 'uint72':
27
- case 'uint80':
28
- case 'uint88':
29
- case 'uint96':
30
- case 'uint104':
31
- case 'uint112':
32
- case 'uint120':
33
- case 'uint128':
34
- case 'uint136':
35
- case 'uint144':
36
- case 'uint152':
37
- case 'uint160':
38
- case 'uint168':
39
- case 'uint176':
40
- case 'uint184':
41
- case 'uint192':
42
- case 'uint200':
43
- case 'uint208':
44
- case 'uint216':
45
- case 'uint224':
46
- case 'uint232':
47
- case 'uint240':
48
- case 'uint248':
49
- case 'uint256':
50
- case 'int8':
51
- case 'int16':
52
- case 'int24':
53
- case 'int32':
54
- case 'int40':
55
- case 'int48':
56
- case 'int56':
57
- case 'int64':
58
- case 'int72':
59
- case 'int80':
60
- case 'int88':
61
- case 'int96':
62
- case 'int104':
63
- case 'int112':
64
- case 'int120':
65
- case 'int128':
66
- case 'int136':
67
- case 'int144':
68
- case 'int152':
69
- case 'int160':
70
- case 'int168':
71
- case 'int176':
72
- case 'int184':
73
- case 'int192':
74
- case 'int200':
75
- case 'int208':
76
- case 'int216':
77
- case 'int224':
78
- case 'int232':
79
- case 'int240':
80
- case 'int248':
81
- case 'int256':
82
- return 1n;
83
- case 'bool':
84
- return false; // Faux pour les booléens
85
- case 'bytes':
86
- case 'string':
87
- return ''; // Chaîne vide pour les chaînes/bytes dynamiques
88
- default:
89
- // Gérer les bytes fixes (bytes1 à bytes32)
90
- if (input.type.startsWith('bytes') && input.type !== 'bytes') {
91
- const size = parseInt(input.type.substring(5), 10);
92
- if (!isNaN(size) && size >= 1 && size <= 32) {
93
- return '0x' + '00'.repeat(size); // Zero-filled hex string
94
- }
95
- }
96
- // Gérer les tableaux et les tuples (récursion)
97
- if (input.type.endsWith('[]')) { // Tableau dynamique
98
- // Retourne un tableau vide pour la simulation simple
99
- return [];
100
- }
101
- else if (input.type.endsWith(']')) { // Tableau fixe (ex: address[5])
102
- const baseType = input.type.substring(0, input.type.indexOf('['));
103
- const length = parseInt(input.type.substring(input.type.indexOf('[') + 1, input.type.indexOf(']')), 10);
104
- if (!isNaN(length)) {
105
- // On pourrait créer un tableau de dummyArgs du baseType de taille 'length'
106
- // Pour une simplicité minimale ici, on pourrait aussi retourner un tableau vide,
107
- // mais c'est moins précis. Faisons un tableau de dummy du bon type.
108
- // Correction: Pass only the base type, not components/indexed from the array type
109
- const dummyValue = generateDummyArgs([{ name: '', type: baseType }])[0];
110
- // Check if dummyValue generation failed for the base type
111
- if (dummyValue === undefined) {
112
- return undefined; // Propagate undefined if base type failed
113
- }
114
- return Array(length).fill(dummyValue);
115
- }
116
- }
117
- else if (input.type === 'tuple' && input.components) { // Tuple (struct) - Utilisation de 'any' pour contourner l'erreur de type AbiParameterWithComponents
118
- // Générer des dummy args pour chaque composant du tuple
119
- const componentArgs = generateDummyArgs(input.components); // Utilisation de 'any'
120
- // Check if any component arg generation failed
121
- if (componentArgs.some(arg => arg === undefined)) {
122
- return undefined; // Propagate undefined if any component failed
123
- }
124
- // Les tuples sont souvent attendus comme des objets ou des tableaux selon l'impl
125
- // Retournons un objet avec les noms des composants si possible
126
- return componentArgs.reduce((obj, arg, index) => {
127
- // Correction: Access components from the casted input
128
- obj[input.components[index].name || index] = arg; // Utilise le nom du composant ou l'index - Utilisation de 'any'
129
- return obj;
130
- }, {});
131
- }
132
- // On retourne undefined, cela pourrait causer l'échec de la simulation
133
- return undefined; // Indique qu'on n'a pas pu générer le paramètre
134
- }
135
- });
136
- }
137
- /**
138
- * Vérifie de manière plus "absolue" si un contrat est conforme à une ABI
139
- * en utilisant ERC-165 (if applicable) et en simulant les appels de fonctions.
140
- *
141
- * @param client - Le client viem connecté au réseau.
142
- * @param contractAddress - L'adresse du contrat à vérifier.
143
- * @param contractAbi - L'ABI complète du contrat.
144
- * @param options - Options pour la vérification : { erc165InterfaceId?: any } // Utilisation de 'any' pour contourner l'erreur de type bytes4
145
- * @returns True si le contrat semble implémenter toutes les fonctions de l'ABI (Selon les checks), False sinon.
146
- */
147
- export async function isContractCompliantWithAbi(client, contractAddress, contractAbi, options // Utilisation de 'any'
148
- ) {
149
- // Check 1: Bytecode Existence
150
- try {
151
- const bytecode = await getCode(client, { address: contractAddress });
152
- if (!bytecode || bytecode === '0x') {
153
- return false; // No code at address
154
- }
155
- }
156
- catch (e) {
157
- // Handle potential errors during RPC call (e.g., network)
158
- return false;
159
- }
160
- // Check 2: ERC-165 Support (if interfaceId and supportsInterface are in ABI)
161
- const erc165InterfaceId = options?.erc165InterfaceId;
162
- const supportsInterfaceAbiItem = contractAbi.find((item) => item.type === 'function' &&
163
- item.name === 'supportsInterface' &&
164
- item.inputs.length === 1 &&
165
- item.inputs[0].type === 'bytes4' &&
166
- (item.stateMutability === 'view' || item.stateMutability === 'pure'));
167
- if (erc165InterfaceId && supportsInterfaceAbiItem) {
168
- try {
169
- const erc165AbiMinimal = parseAbi(['function supportsInterface(bytes4 interfaceId) view returns (bool)']);
170
- // Check if it supports ERC-165 itself first
171
- const supports165Self = await readContract(client, {
172
- address: contractAddress,
173
- abi: erc165AbiMinimal, // Use minimal ABI for supportsInterface itself
174
- functionName: 'supportsInterface',
175
- args: ['0x01ffc9a7'] // ERC-165 interface ID
176
- });
177
- if (!supports165Self) {
178
- // Contract has supportsInterface but doesn't claim ERC-165 support
179
- return false;
180
- }
181
- // Now check if it supports the target interfaceId
182
- const supportsTargetInterface = await readContract(client, {
183
- address: contractAddress,
184
- abi: erc165AbiMinimal, // Use minimal ABI for supportsInterface
185
- functionName: 'supportsInterface',
186
- args: [erc165InterfaceId] // The target interface ID
187
- });
188
- if (!supportsTargetInterface) {
189
- // It supports ERC-165 but not the specific target interface
190
- return false;
191
- }
192
- // ERC-165 check passed for the target interface.
193
- }
194
- catch (e) {
195
- // If calling supportsInterface failed (function not found, revert, etc.)
196
- // Treat as not compliant with the ERC-165 check.
197
- return false;
198
- }
199
- }
200
- // Check 3: Simulate or Read all functions, distinguishing errors
201
- const functions = contractAbi.filter((item) => item.type === 'function');
202
- if (functions.length === 0) {
203
- // If no functions in ABI, and bytecode exists + ERC165 passed (if applicable), consider compliant
204
- // with an ABI that defines no functions to check.
205
- return true;
206
- }
207
- // Track if any function was *not found* or had a non-revert error
208
- let hasFunctionNotFoundError = false;
209
- let hasOtherUnexpectedError = false;
210
- for (const func of functions) {
211
- // Skip supportsInterface if we already checked it via ERC-165 logic
212
- if (func.name === 'supportsInterface' && func.inputs.length === 1 && func.inputs[0].type === 'bytes4') {
213
- if (erc165InterfaceId && supportsInterfaceAbiItem)
214
- continue; // Already checked as part of ERC-165 flow
215
- // If not part of ERC-165 flow, treat as a regular function to check below
216
- }
217
- try {
218
- const dummyArgs = generateDummyArgs(func.inputs);
219
- // If generateDummyArgs returned undefined for any arg, we cannot simulate this function reliably
220
- if (dummyArgs.some(arg => arg === undefined)) {
221
- // Cannot generate valid inputs -> Cannot test this function -> Not compliant with ABI requiring complex inputs
222
- hasOtherUnexpectedError = true;
223
- // We could break here, but checking other functions might still be useful.
224
- continue; // Move to the next function
225
- }
226
- const commonCallArgs = {
227
- address: contractAddress,
228
- abi: contractAbi,
229
- functionName: func.name,
230
- args: dummyArgs,
231
- };
232
- if (func.stateMutability === 'view' || func.stateMutability === 'pure') {
233
- // Simulate view/pure functions
234
- await readContract(client, commonCallArgs); // Use any for args typing simplification
235
- }
236
- else if (func.stateMutability === 'nonpayable' || func.stateMutability === 'payable') {
237
- // Simulate write functions
238
- await simulateContract(client, {
239
- ...commonCallArgs, // Use any for args typing simplification
240
- account: zeroAddress, // Use a dummy account for simulation
241
- // Add value for payable functions if needed for simulation logic, e.g.:
242
- // value: func.stateMutability === 'payable' ? 1n : 0n
243
- });
244
- }
245
- else {
246
- // Unknown state mutability - cannot verify this function type
247
- hasOtherUnexpectedError = true;
248
- continue; // Move to the next function
249
- }
250
- }
251
- catch (e) {
252
- const error = e;
253
- if (error.name === "AbiFunctionNotFoundError") {
254
- // Function not found in ABI
255
- hasFunctionNotFoundError = true;
256
- console.warn(`Warning: Function ${func.name} not found in ABI`);
257
- continue; // Move to the next function
258
- }
259
- if (error.name === "ContractFunctionExecutionError") {
260
- // Function reverted, but not a failure of the function itself
261
- // This is a valid state/logic check, but not a failure of the function
262
- console.warn(`Warning: Function ${func.name} reverted: ${error.name}`);
263
- continue; // Move to the next function
264
- }
265
- }
266
- }
267
- // Final Decision:
268
- // Compliant only if:
269
- // 1. Bytecode exists
270
- // 2. ERC-165 check passed (if requested)
271
- // 3. NO ContractFunctionNotFoundError occurred for ANY function.
272
- // 4. NO other unexpected errors occurred (like generation of dummy args failing, or network issues during checks).
273
- // Revert errors (ContractFunctionRevertedError) are ACCEPTED, implying the function exists but failed state/logic checks with dummy args.
274
- if (hasFunctionNotFoundError || hasOtherUnexpectedError) {
275
- return false; // Found a missing function or hit an unexpected issue
276
- }
277
- // If we went through all functions without hitting ContractFunctionNotFoundError or other unexpected errors,
278
- // and Bytecode & ERC165 (if applicable) checks passed.
279
- return true;
280
- }
@@ -1,168 +0,0 @@
1
- export declare const ERC20: readonly [{
2
- readonly constant: true;
3
- readonly inputs: readonly [];
4
- readonly name: "name";
5
- readonly outputs: readonly [{
6
- readonly name: "";
7
- readonly type: "string";
8
- }];
9
- readonly payable: false;
10
- readonly stateMutability: "view";
11
- readonly type: "function";
12
- }, {
13
- readonly constant: false;
14
- readonly inputs: readonly [{
15
- readonly name: "_spender";
16
- readonly type: "address";
17
- }, {
18
- readonly name: "_value";
19
- readonly type: "uint256";
20
- }];
21
- readonly name: "approve";
22
- readonly outputs: readonly [{
23
- readonly name: "";
24
- readonly type: "bool";
25
- }];
26
- readonly payable: false;
27
- readonly stateMutability: "nonpayable";
28
- readonly type: "function";
29
- }, {
30
- readonly constant: true;
31
- readonly inputs: readonly [];
32
- readonly name: "totalSupply";
33
- readonly outputs: readonly [{
34
- readonly name: "";
35
- readonly type: "uint256";
36
- }];
37
- readonly payable: false;
38
- readonly stateMutability: "view";
39
- readonly type: "function";
40
- }, {
41
- readonly constant: false;
42
- readonly inputs: readonly [{
43
- readonly name: "_from";
44
- readonly type: "address";
45
- }, {
46
- readonly name: "_to";
47
- readonly type: "address";
48
- }, {
49
- readonly name: "_value";
50
- readonly type: "uint256";
51
- }];
52
- readonly name: "transferFrom";
53
- readonly outputs: readonly [{
54
- readonly name: "";
55
- readonly type: "bool";
56
- }];
57
- readonly payable: false;
58
- readonly stateMutability: "nonpayable";
59
- readonly type: "function";
60
- }, {
61
- readonly constant: true;
62
- readonly inputs: readonly [];
63
- readonly name: "decimals";
64
- readonly outputs: readonly [{
65
- readonly name: "";
66
- readonly type: "uint8";
67
- }];
68
- readonly payable: false;
69
- readonly stateMutability: "view";
70
- readonly type: "function";
71
- }, {
72
- readonly constant: true;
73
- readonly inputs: readonly [{
74
- readonly name: "_owner";
75
- readonly type: "address";
76
- }];
77
- readonly name: "balanceOf";
78
- readonly outputs: readonly [{
79
- readonly name: "balance";
80
- readonly type: "uint256";
81
- }];
82
- readonly payable: false;
83
- readonly stateMutability: "view";
84
- readonly type: "function";
85
- }, {
86
- readonly constant: true;
87
- readonly inputs: readonly [];
88
- readonly name: "symbol";
89
- readonly outputs: readonly [{
90
- readonly name: "";
91
- readonly type: "string";
92
- }];
93
- readonly payable: false;
94
- readonly stateMutability: "view";
95
- readonly type: "function";
96
- }, {
97
- readonly constant: false;
98
- readonly inputs: readonly [{
99
- readonly name: "_to";
100
- readonly type: "address";
101
- }, {
102
- readonly name: "_value";
103
- readonly type: "uint256";
104
- }];
105
- readonly name: "transfer";
106
- readonly outputs: readonly [{
107
- readonly name: "";
108
- readonly type: "bool";
109
- }];
110
- readonly payable: false;
111
- readonly stateMutability: "nonpayable";
112
- readonly type: "function";
113
- }, {
114
- readonly constant: true;
115
- readonly inputs: readonly [{
116
- readonly name: "_owner";
117
- readonly type: "address";
118
- }, {
119
- readonly name: "_spender";
120
- readonly type: "address";
121
- }];
122
- readonly name: "allowance";
123
- readonly outputs: readonly [{
124
- readonly name: "";
125
- readonly type: "uint256";
126
- }];
127
- readonly payable: false;
128
- readonly stateMutability: "view";
129
- readonly type: "function";
130
- }, {
131
- readonly payable: true;
132
- readonly stateMutability: "payable";
133
- readonly type: "fallback";
134
- }, {
135
- readonly anonymous: false;
136
- readonly inputs: readonly [{
137
- readonly indexed: true;
138
- readonly name: "owner";
139
- readonly type: "address";
140
- }, {
141
- readonly indexed: true;
142
- readonly name: "spender";
143
- readonly type: "address";
144
- }, {
145
- readonly indexed: false;
146
- readonly name: "value";
147
- readonly type: "uint256";
148
- }];
149
- readonly name: "Approval";
150
- readonly type: "event";
151
- }, {
152
- readonly anonymous: false;
153
- readonly inputs: readonly [{
154
- readonly indexed: true;
155
- readonly name: "from";
156
- readonly type: "address";
157
- }, {
158
- readonly indexed: true;
159
- readonly name: "to";
160
- readonly type: "address";
161
- }, {
162
- readonly indexed: false;
163
- readonly name: "value";
164
- readonly type: "uint256";
165
- }];
166
- readonly name: "Transfer";
167
- readonly type: "event";
168
- }];
@@ -1,222 +0,0 @@
1
- export const ERC20 = [
2
- {
3
- "constant": true,
4
- "inputs": [],
5
- "name": "name",
6
- "outputs": [
7
- {
8
- "name": "",
9
- "type": "string"
10
- }
11
- ],
12
- "payable": false,
13
- "stateMutability": "view",
14
- "type": "function"
15
- },
16
- {
17
- "constant": false,
18
- "inputs": [
19
- {
20
- "name": "_spender",
21
- "type": "address"
22
- },
23
- {
24
- "name": "_value",
25
- "type": "uint256"
26
- }
27
- ],
28
- "name": "approve",
29
- "outputs": [
30
- {
31
- "name": "",
32
- "type": "bool"
33
- }
34
- ],
35
- "payable": false,
36
- "stateMutability": "nonpayable",
37
- "type": "function"
38
- },
39
- {
40
- "constant": true,
41
- "inputs": [],
42
- "name": "totalSupply",
43
- "outputs": [
44
- {
45
- "name": "",
46
- "type": "uint256"
47
- }
48
- ],
49
- "payable": false,
50
- "stateMutability": "view",
51
- "type": "function"
52
- },
53
- {
54
- "constant": false,
55
- "inputs": [
56
- {
57
- "name": "_from",
58
- "type": "address"
59
- },
60
- {
61
- "name": "_to",
62
- "type": "address"
63
- },
64
- {
65
- "name": "_value",
66
- "type": "uint256"
67
- }
68
- ],
69
- "name": "transferFrom",
70
- "outputs": [
71
- {
72
- "name": "",
73
- "type": "bool"
74
- }
75
- ],
76
- "payable": false,
77
- "stateMutability": "nonpayable",
78
- "type": "function"
79
- },
80
- {
81
- "constant": true,
82
- "inputs": [],
83
- "name": "decimals",
84
- "outputs": [
85
- {
86
- "name": "",
87
- "type": "uint8"
88
- }
89
- ],
90
- "payable": false,
91
- "stateMutability": "view",
92
- "type": "function"
93
- },
94
- {
95
- "constant": true,
96
- "inputs": [
97
- {
98
- "name": "_owner",
99
- "type": "address"
100
- }
101
- ],
102
- "name": "balanceOf",
103
- "outputs": [
104
- {
105
- "name": "balance",
106
- "type": "uint256"
107
- }
108
- ],
109
- "payable": false,
110
- "stateMutability": "view",
111
- "type": "function"
112
- },
113
- {
114
- "constant": true,
115
- "inputs": [],
116
- "name": "symbol",
117
- "outputs": [
118
- {
119
- "name": "",
120
- "type": "string"
121
- }
122
- ],
123
- "payable": false,
124
- "stateMutability": "view",
125
- "type": "function"
126
- },
127
- {
128
- "constant": false,
129
- "inputs": [
130
- {
131
- "name": "_to",
132
- "type": "address"
133
- },
134
- {
135
- "name": "_value",
136
- "type": "uint256"
137
- }
138
- ],
139
- "name": "transfer",
140
- "outputs": [
141
- {
142
- "name": "",
143
- "type": "bool"
144
- }
145
- ],
146
- "payable": false,
147
- "stateMutability": "nonpayable",
148
- "type": "function"
149
- },
150
- {
151
- "constant": true,
152
- "inputs": [
153
- {
154
- "name": "_owner",
155
- "type": "address"
156
- },
157
- {
158
- "name": "_spender",
159
- "type": "address"
160
- }
161
- ],
162
- "name": "allowance",
163
- "outputs": [
164
- {
165
- "name": "",
166
- "type": "uint256"
167
- }
168
- ],
169
- "payable": false,
170
- "stateMutability": "view",
171
- "type": "function"
172
- },
173
- {
174
- "payable": true,
175
- "stateMutability": "payable",
176
- "type": "fallback"
177
- },
178
- {
179
- "anonymous": false,
180
- "inputs": [
181
- {
182
- "indexed": true,
183
- "name": "owner",
184
- "type": "address"
185
- },
186
- {
187
- "indexed": true,
188
- "name": "spender",
189
- "type": "address"
190
- },
191
- {
192
- "indexed": false,
193
- "name": "value",
194
- "type": "uint256"
195
- }
196
- ],
197
- "name": "Approval",
198
- "type": "event"
199
- },
200
- {
201
- "anonymous": false,
202
- "inputs": [
203
- {
204
- "indexed": true,
205
- "name": "from",
206
- "type": "address"
207
- },
208
- {
209
- "indexed": true,
210
- "name": "to",
211
- "type": "address"
212
- },
213
- {
214
- "indexed": false,
215
- "name": "value",
216
- "type": "uint256"
217
- }
218
- ],
219
- "name": "Transfer",
220
- "type": "event"
221
- }
222
- ];
@@ -1 +0,0 @@
1
- export * from './ERC20';
@@ -1 +0,0 @@
1
- export * from './ERC20';