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

fix: estimateMessageFee - eth address format #1040

Merged
merged 4 commits into from
Mar 27, 2024
Merged
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
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', () => {
PhilippeR26 marked this conversation as resolved.
Show resolved Hide resolved
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