Skip to content

Commit

Permalink
fix: estimateMessageFee - eth address format (starknet-io#1040)
Browse files Browse the repository at this point in the history
* fix: estimatemessagefee eth address format

* fix: implement requests
  • Loading branch information
PhilippeR26 authored and penovicp committed Apr 3, 2024
1 parent ca93ef0 commit c832116
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 12 deletions.
39 changes: 32 additions & 7 deletions __tests__/rpcProvider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import { StarknetChainId } from '../src/constants';
import { felt, uint256 } from '../src/utils/calldata/cairo';
import { toHexString } from '../src/utils/num';
import {
compiledC1v2,
compiledC1v2Casm,
compiledErc20Echo,
compiledL1L2,
compiledOpenZeppelinAccount,
Expand Down Expand Up @@ -109,24 +111,47 @@ describeIfRpc('RPCProvider', () => {
});

describe('Test Estimate message fee', () => {
const L1_ADDRESS = '0x8359E4B0152ed5A731162D3c7B0D8D56edB165A0';
let l1l2ContractAddress: string;
let l1l2ContractCairo0Address: string;
let l1l2ContractCairo1Address: string;

beforeAll(async () => {
const { deploy } = await account.declareAndDeploy({
contract: compiledL1L2,
});
l1l2ContractAddress = deploy.contract_address;
l1l2ContractCairo0Address = deploy.contract_address;
const { deploy: deploy2 } = await account.declareAndDeploy({
contract: compiledC1v2,
casm: compiledC1v2Casm,
});
l1l2ContractCairo1Address = deploy2.contract_address;
});

test('estimate message fee', async () => {
const estimation = await rpcProvider.estimateMessageFee({
test('estimate message fee Cairo 0', async () => {
const L1_ADDRESS = '0x8359E4B0152ed5A731162D3c7B0D8D56edB165A0';
const estimationCairo0 = await rpcProvider.estimateMessageFee({
from_address: L1_ADDRESS,
to_address: l1l2ContractAddress,
to_address: l1l2ContractCairo0Address,
entry_point_selector: 'deposit',
payload: ['556', '123'],
});
expect(estimation).toEqual(
expect(estimationCairo0).toEqual(
expect.objectContaining({
gas_consumed: expect.anything(),
gas_price: expect.anything(),
overall_fee: expect.anything(),
})
);
});

test('estimate message fee Cairo 1', async () => {
const L1_ADDRESS = '0x8359E4B0152ed5A731162D3c7B0D8D56edB165'; // not coded in 20 bytes
const estimationCairo1 = await rpcProvider.estimateMessageFee({
from_address: L1_ADDRESS,
to_address: l1l2ContractCairo1Address,
entry_point_selector: 'increase_bal',
payload: ['100'],
});
expect(estimationCairo1).toEqual(
expect.objectContaining({
gas_consumed: expect.anything(),
gas_price: expect.anything(),
Expand Down
15 changes: 15 additions & 0 deletions __tests__/utils/ethSigner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
num,
stark,
} from '../../src';
import { validateAndParseEthAddress } from '../../src/utils/eth';
import { ETransactionVersion } from '../../src/types/api';
import {
compiledDummy1Eth,
Expand Down Expand Up @@ -321,4 +322,18 @@ describe('Ethereum signer', () => {
);
});
});
describe('Ethereum address', () => {
test('Eth address format', async () => {
const ethAddr = '0x8359E4B0152ed5A731162D3c7B0D8D56edB165'; // not a valid 20 bytes ETh address
expect(validateAndParseEthAddress(ethAddr)).toBe(
'0x008359e4b0152ed5a731162d3c7b0d8d56edb165'
);
expect(validateAndParseEthAddress(BigInt(ethAddr))).toBe(
'0x008359e4b0152ed5a731162d3c7b0d8d56edb165'
);
expect(validateAndParseEthAddress(BigInt(ethAddr).toString(10))).toBe(
'0x008359e4b0152ed5a731162d3c7b0d8d56edb165'
);
});
});
});
3 changes: 2 additions & 1 deletion src/channel/rpc_0_6.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
import { JRPC, RPCSPEC06 as RPC } from '../types/api';
import { CallData } from '../utils/calldata';
import { isSierra } from '../utils/contract';
import { validateAndParseEthAddress } from '../utils/eth';
import fetch from '../utils/fetchPonyfill';
import { getSelector, getSelectorFromName } from '../utils/hash';
import { stringify } from '../utils/json';
Expand Down Expand Up @@ -565,7 +566,7 @@ export class RpcChannel {
) {
const { from_address, to_address, entry_point_selector, payload } = message;
const formattedMessage = {
from_address: toHex(from_address),
from_address: validateAndParseEthAddress(from_address),
to_address: toHex(to_address),
entry_point_selector: getSelector(entry_point_selector),
payload: getHexStringArray(payload),
Expand Down
3 changes: 2 additions & 1 deletion src/channel/rpc_0_7.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
import { JRPC, RPCSPEC07 as RPC } from '../types/api';
import { CallData } from '../utils/calldata';
import { isSierra } from '../utils/contract';
import { validateAndParseEthAddress } from '../utils/eth';
import fetch from '../utils/fetchPonyfill';
import { getSelector, getSelectorFromName } from '../utils/hash';
import { stringify } from '../utils/json';
Expand Down Expand Up @@ -569,7 +570,7 @@ export class RpcChannel {
) {
const { from_address, to_address, entry_point_selector, payload } = message;
const formattedMessage = {
from_address: toHex(from_address),
from_address: validateAndParseEthAddress(from_address),
to_address: toHex(to_address),
entry_point_selector: getSelector(entry_point_selector),
payload: getHexStringArray(payload),
Expand Down
25 changes: 24 additions & 1 deletion src/utils/eth.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,37 @@
import { secp256k1 } from '@noble/curves/secp256k1';

import { buf2hex, sanitizeHex } from './encode';
import { addHexPrefix, buf2hex, removeHexPrefix, sanitizeHex } from './encode';
import type { BigNumberish } from '../types';
import { assertInRange, toHex } from './num';
import { ZERO } from '../constants';
import assert from './assert';

/**
* Get random Ethereum private Key.
* @returns an Hex string
* @example
* ```typescript
* const myPK: string = randomAddress()
* // result = "0xf04e69ac152fba37c02929c2ae78c9a481461dda42dbc6c6e286be6eb2a8ab83"
* ```
*/
export function ethRandomPrivateKey(): string {
return sanitizeHex(buf2hex(secp256k1.utils.randomPrivateKey()));
}

/**
* Get a string formatted for an Ethereum address, without uppercase characters.
* @param {BigNumberish} address Address of an Ethereum account.
* @returns an Hex string coded on 20 bytes
* @example
* ```typescript
* const myEthAddress: string = validateAndParseEthAddress("0x8359E4B0152ed5A731162D3c7B0D8D56edB165")
* // result = "0x008359e4b0152ed5a731162d3c7b0d8d56edb165"
* ```
*/
export function validateAndParseEthAddress(address: BigNumberish): string {
assertInRange(address, ZERO, 2n ** 160n - 1n, 'Ethereum Address ');
const result = addHexPrefix(removeHexPrefix(toHex(address)).padStart(40, '0'));
assert(result.match(/^(0x)?[0-9a-f]{40}$/), 'Invalid Ethereum Address Format');
return result;
}
4 changes: 2 additions & 2 deletions www/docs/guides/L1message.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ const responseEstimateMessageFee = await provider.estimateMessageFee({
from_address: L1address,
to_address: L2address,
entry_point_selector: 'handle_l1_mess',
payload: ['1234567890123456789', '200'],
payload: ['1234567890123456789', '200'], // without from_address
});
```

If the fee is paid in L1, the Cairo contract at `to_Address` is automatically executed, function `entry_point_selector` (the function shall have a decorator `@l1_handler` in the Cairo code), with parameters `payload`.
If the fee is paid in L1, the Cairo contract at `to_Address` is automatically executed, function `entry_point_selector` (the function shall have a decorator `#[l1_handler]` in the Cairo code, with a first parameter called `from_address: felt252`). The payload shall not include the `from_address` parameter.

## L2 ➡️ L1 messages

Expand Down

0 comments on commit c832116

Please sign in to comment.