@mentaproject/client 0.0.3 → 0.0.4

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.
@@ -2,10 +2,10 @@ import type { Address, CoreClient } from "@mentaproject/core/types";
2
2
  import { Transaction } from "./Transaction";
3
3
  import { GetTransactionsReturnType } from "../types/Account";
4
4
  /**
5
- * Represents a user account with methods for interacting with the blockchain.
5
+ * Represents an account with methods for interacting with it.
6
6
  */
7
7
  export declare class Account {
8
- protected rpcClient: CoreClient;
8
+ rpcClient: CoreClient;
9
9
  address: Address;
10
10
  /**
11
11
  * Creates an instance of Account.
@@ -13,6 +13,12 @@ export declare class Account {
13
13
  * @param address The blockchain address of the account.
14
14
  */
15
15
  constructor(rpcClient: CoreClient, address: Address);
16
+ /**
17
+ * If the account is a contract, returns a ContractAccount instance. Otherwise, returns undefined.
18
+ * @returns
19
+ */
20
+ isContract(): Promise<boolean>;
21
+ getContractType(): Promise<any>;
16
22
  /**
17
23
  * Sends native cryptocurrency (ETH) to the account.
18
24
  * @param amount The amount of ETH to send (in wei).
@@ -1,8 +1,9 @@
1
- import { createBlockRangePager, getBalance, getBlockNumber, getTransaction, getTransactionCount, sendTransaction, traceFilter } from "@mentaproject/core/actions";
1
+ import { createBlockRangePager, getBalance, getBlockNumber, getCode, getTransaction, getTransactionCount, sendTransaction, traceFilter } from "@mentaproject/core/actions";
2
2
  import { Transaction } from "./Transaction";
3
3
  import { toHex } from "@mentaproject/core/utils";
4
+ import { getContractType } from "@mentaproject/contracts";
4
5
  /**
5
- * Represents a user account with methods for interacting with the blockchain.
6
+ * Represents an account with methods for interacting with it.
6
7
  */
7
8
  export class Account {
8
9
  /**
@@ -14,6 +15,21 @@ export class Account {
14
15
  this.rpcClient = rpcClient;
15
16
  this.address = address;
16
17
  }
18
+ /**
19
+ * If the account is a contract, returns a ContractAccount instance. Otherwise, returns undefined.
20
+ * @returns
21
+ */
22
+ async isContract() {
23
+ const code = await getCode(this.rpcClient, { address: this.address });
24
+ if (!code || code === "0x")
25
+ return false;
26
+ return true;
27
+ }
28
+ ;
29
+ async getContractType() {
30
+ return await getContractType(this.rpcClient, this.address);
31
+ }
32
+ ;
17
33
  /**
18
34
  * Sends native cryptocurrency (ETH) to the account.
19
35
  * @param amount The amount of ETH to send (in wei).
@@ -84,3 +100,4 @@ export class Account {
84
100
  }, onBlockRange);
85
101
  }
86
102
  }
103
+ ;
@@ -0,0 +1,6 @@
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
+ }
@@ -0,0 +1,12 @@
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
+ ;
@@ -24,6 +24,14 @@ export declare class Transaction implements Omit<ITransactionData, "from" | "to"
24
24
  from?: Account;
25
25
  to?: Account;
26
26
  constructor(rpcClient: CoreClient, data: ITransactionData);
27
+ getCalls(): Promise<{
28
+ from: Account;
29
+ to: Account;
30
+ value: bigint;
31
+ input: Hex;
32
+ gas: bigint;
33
+ callType: string | undefined;
34
+ }[]>;
27
35
  waitForReceipt(confirmations?: number): Promise<WaitForTransactionReceiptReturnType>;
28
36
  receipt(): Promise<WaitForTransactionReceiptReturnType>;
29
37
  block(): Promise<Block>;
@@ -1,6 +1,7 @@
1
1
  import { Account } from './Account';
2
2
  import { Block } from './Block';
3
- import { getBlock, getTransactionReceipt, waitForTransactionReceipt } from '@mentaproject/core/actions';
3
+ import { getBlock, getTransactionReceipt, traceTransaction, waitForTransactionReceipt } from '@mentaproject/core/actions';
4
+ import { hexToBigInt } from '@mentaproject/core/utils';
4
5
  export class Transaction {
5
6
  constructor(rpcClient, data) {
6
7
  this.rpcClient = rpcClient;
@@ -25,6 +26,18 @@ export class Transaction {
25
26
  this.to = data.to ? new Account(this.rpcClient, data.to) : undefined;
26
27
  }
27
28
  ;
29
+ async getCalls() {
30
+ const traces = await traceTransaction(this.rpcClient, this.hash);
31
+ const calls = traces.filter(t => t.type === "call" && t.action !== undefined);
32
+ return calls.map(c => ({
33
+ from: new Account(this.rpcClient, c.action.from),
34
+ to: new Account(this.rpcClient, c.action.to),
35
+ value: hexToBigInt(c.action.value),
36
+ input: c.action.input,
37
+ gas: hexToBigInt(c.action.gas),
38
+ callType: c.action.callType,
39
+ }));
40
+ }
28
41
  async waitForReceipt(confirmations) {
29
42
  return await waitForTransactionReceipt(this.rpcClient, {
30
43
  hash: this.hash,
@@ -0,0 +1,20 @@
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
+ }
@@ -0,0 +1,62 @@
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();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mentaproject/client",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
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",
@@ -29,9 +29,9 @@
29
29
  "author": "@mentaproject",
30
30
  "license": "ISC",
31
31
  "dependencies": {
32
- "@shazow/whatsabi": "^0.21.1",
33
- "@mentaproject/contracts": "0.0.2",
34
- "@mentaproject/core": "0.0.3"
32
+ "@mentaproject/contracts": "^0.0.8",
33
+ "@mentaproject/core": "^0.0.4",
34
+ "@shazow/whatsabi": "^0.21.1"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@rollup/plugin-commonjs": "^28.0.3",
package/test.ts CHANGED
@@ -1,11 +1,7 @@
1
- import { Address, erc20Abi, getAddress, http, toFunctionSelector, zeroAddress } from "viem";
1
+ import { http } from "viem";
2
2
  import { MentaClient } from "./src";
3
3
  import { privateKeyToAccount, generatePrivateKey } from "viem/accounts"
4
4
  import { mainnet } from "@mentaproject/core/chains";
5
- import { getCode, getStorageAt } from "@mentaproject/core/actions";
6
- import { selectorsFromBytecode } from "@shazow/whatsabi";
7
- import { toFunctionSignature } from "viem"
8
- import { bytes32ToAddress } from "@mentaproject/core/utils";
9
5
 
10
6
  const viemAccount = privateKeyToAccount(generatePrivateKey());
11
7
 
@@ -16,45 +12,17 @@ const client = new MentaClient({
16
12
  });
17
13
 
18
14
  (async () => {
19
- // const firstTx = await client.transactions.get({ hash: "0x1ac2418d94a069d3460b7dd52cfc251879da4948bb0df8362598b5595d28cbf1" });
20
- // const receipt = await firstTx.receipt();
21
-
22
- // const log = receipt.logs[0];
23
-
24
- // if (!log) return;
25
-
26
- // const decoded = decodeEventLog({
27
- // abi: erc20Abi,
28
- // data: receipt.logs[0].data,
29
- // topics: receipt.logs[0].topics,
30
- // });
31
-
32
- // console.log(decoded.args)
33
-
34
- const erc20Signatures = erc20Abi.filter(item => item.type === "function").map(item => ({ signature:toFunctionSignature(item), selector: toFunctionSelector(item)}));
35
-
36
- const code = await getCode(client.rpcClient, { address: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48" });
37
- const infos = selectorsFromBytecode(code as string);
38
-
39
- console.log(infos);
40
-
41
- async function getImplementationAddress(proxyAddr: Address) {
42
- const storageValue = await getStorageAt(client.rpcClient, {
43
- address: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
44
- slot: "0x7050c9e0f4ca769c69bd3a8ef740bc37934f8e2c036e5a723fd8ee048ed3f8c3"
45
- });
46
-
47
- if (storageValue) {
48
-
49
- console.log(storageValue);
50
- // La valeur retournée est un hex de 32 octets. L'adresse est dans les 20 derniers octets.
51
- const address = getAddress(bytes32ToAddress(storageValue))
52
- if (address !== zeroAddress) {
53
- return address;
54
- }
55
- }
56
- return null; // Pas d'adresse trouvée ou contrat non EIP-1967
57
- };
58
-
59
- getImplementationAddress("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48").then(console.log);
15
+ const firstTx = await client.transactions.get({ hash: "0xeae261aeada2db19fee5cc4dfd47d575ff2380a5fb6a4039685d5044fdc8e2bb" });
16
+ const calls = await firstTx.getCalls();
17
+
18
+ for (const call of calls) {
19
+ const contract = call.to;
20
+ console.log(`Calling ${contract.address}`);
21
+ const isContract = await contract.isContract();
22
+ console.log(isContract);
23
+ if (!isContract) continue;
24
+ const contractType = await contract.getContractType();
25
+ console.log(contractType);
26
+ console.log(`Contract ${contract.address} detected as ${Object.keys(contractType).join(", ")}`);
27
+ }
60
28
  })()