Skip to content

Commit

Permalink
Merge pull request #1187 from starknet-io/next-version
Browse files Browse the repository at this point in the history
Next version
  • Loading branch information
tabaktoni authored Jul 26, 2024
2 parents 7f5e42d + 96a3dfb commit df78f60
Show file tree
Hide file tree
Showing 27 changed files with 1,254 additions and 58 deletions.
25 changes: 20 additions & 5 deletions __tests__/config/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ import fs from 'node:fs';
import path from 'node:path';

import { Account, Provider, ProviderInterface, RpcProvider, json } from '../../src';
import { CompiledSierra, CompiledSierraCasm, LegacyCompiledContract } from '../../src/types';
import {
CompiledSierra,
CompiledSierraCasm,
LegacyCompiledContract,
RpcProviderOptions,
} from '../../src/types';
import { ETransactionVersion } from '../../src/types/api';
import { toHex } from '../../src/utils/num';
import { wait } from '../../src/utils/provider';
Expand Down Expand Up @@ -72,12 +77,22 @@ export const compiledSidMulticallCasm = readContractSierraCasm('starknetId/multi
export const compiledNonZero = readContractSierra('cairo/cairo263/zeroable.sierra');
export const compiledNonZeroCasm = readContractSierraCasm('cairo/cairo263/zeroable');

export function getTestProvider(isProvider?: true): ProviderInterface;
export function getTestProvider(isProvider?: false): RpcProvider;
export function getTestProvider(isProvider: boolean = true): ProviderInterface | RpcProvider {
export function getTestProvider(
isProvider?: true,
setProviderOptions?: RpcProviderOptions
): ProviderInterface;
export function getTestProvider(
isProvider?: false,
setProviderOptions?: RpcProviderOptions
): RpcProvider;
export function getTestProvider(
isProvider: boolean = true,
setProviderOptions?: RpcProviderOptions
): ProviderInterface | RpcProvider {
const isDevnet = process.env.IS_DEVNET === 'true';

const providerOptions = {
const providerOptions: RpcProviderOptions = {
...setProviderOptions,
nodeUrl: process.env.TEST_RPC_URL,
// accelerate the tests when running locally
...(isDevnet && { transactionRetryIntervalFallback: 1000 }),
Expand Down
46 changes: 30 additions & 16 deletions __tests__/config/jest.setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,46 @@ const combiner: object[] = [];
if (process.env.DEBUG === 'true') {
register({
request(url, config) {
const body = JSON.parse(config.body);
combiner.push({
request: {
url,
method: config.method,
body,
},
});
const randId = crypto.randomUUID();
if (config.body) {
const body = JSON.parse(config.body);
combiner.push({
request: {
matchId: randId,
url,
method: config.method,
body,
},
});

// match request and response when DEBUG, lib override headers instead of add
const headers = {
'Content-Type': 'application/json',
Accept: 'application/json',
'x-match-id': randId,
};
// eslint-disable-next-line no-param-reassign
config.headers = headers;
}
return [url, config];
},

requestError(error) {
const match: any = combiner.find((it: any) => typeof it.result === 'undefined');
match.result = error;
console.log('[fetch.requestError]', match);
// unknown original request
console.log('[fetch.requestError]', error);
return Promise.reject(error);
},

response(response) {
const requestId = response.request.headers.get('x-match-id');
const cloned = response.clone();
cloned.json().then((res) => {
const { result } = res;
const match: any = combiner.find((it: any) => it.request.body.id === res.id);
const match: any = combiner.find((it: any) => it.request.matchId === requestId);
if (match && 'request' in match) {
match.result = result;
if (result) match.result = result;
else match.response = res;

console.log(util.inspect(match, false, null, true /* enable colors */));
} else {
console.log(result);
Expand All @@ -52,9 +67,8 @@ if (process.env.DEBUG === 'true') {
},

responseError(error) {
const match: any = combiner.find((it: any) => typeof it.result === 'undefined');
match.result = error;
console.log('[fetch.responseError]', match);
// unknown original request
console.log('[fetch.responseError]', error);
return Promise.reject(error);
},
});
Expand Down
49 changes: 49 additions & 0 deletions __tests__/utils/batch.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { BatchClient } from '../../src/utils/batch';
import { createBlockForDevnet, getTestProvider } from '../config/fixtures';
import { initializeMatcher } from '../config/schema';

describe('Batch Client', () => {
const provider = getTestProvider(false);

const batchClient = new BatchClient({
nodeUrl: provider.channel.nodeUrl,
headers: provider.channel.headers,
interval: 0,
});

initializeMatcher(expect);

test('should batch two requests', async () => {
await createBlockForDevnet();

const fetchSpy = jest.spyOn(batchClient as any, 'sendBatch');

const [blockNumber, blockWithReceipts] = await Promise.all([
batchClient.fetch('starknet_blockNumber'),
batchClient.fetch('starknet_getBlockWithReceipts', { block_id: 'latest' }),
]);

expect(typeof blockNumber.result).toBe('number');
expect(blockWithReceipts.result).toMatchSchemaRef('BlockWithTxReceipts');

expect(fetchSpy).toHaveBeenCalledTimes(1);
fetchSpy.mockRestore();
});

test('batch request using Provider', async () => {
const myBatchProvider = getTestProvider(false, {
batch: 0,
});

// eslint-disable-next-line @typescript-eslint/dot-notation
const sendBatchSpy = jest.spyOn(myBatchProvider.channel['batchClient'] as any, 'sendBatch');

await Promise.all([
myBatchProvider.getBlock(),
myBatchProvider.getBlockLatestAccepted(),
myBatchProvider.getBlockTransactionCount('latest'),
]);

expect(sendBatchSpy).toHaveBeenCalledTimes(1);
});
});
10 changes: 10 additions & 0 deletions __tests__/utils/encode.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { encode } from '../../src';
import { atobUniversal, btoaUniversal } from '../../src/utils/encode';

describe('atobUniversal and btoaUniversal functions', () => {
Expand Down Expand Up @@ -32,3 +33,12 @@ describe('atobUniversal and btoaUniversal functions', () => {
expect(decoded).toEqual(new Uint8Array([]));
});
});

describe('concatenateArrayBuffer', () => {
test('should concatenate uint8Arrays', () => {
const path0buff = new Uint8Array([128, 0, 10, 85]);
const path1buff = new Uint8Array([71, 65, 233, 201]);
const result = encode.concatenateArrayBuffer([path0buff, path1buff]);
expect(result).toEqual(new Uint8Array([128, 0, 10, 85, 71, 65, 233, 201]));
});
});
14 changes: 14 additions & 0 deletions __tests__/utils/ethSigner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
encode,
eth,
extractContractHashes,
getLedgerPathBuffer,
hash,
num,
stark,
Expand Down Expand Up @@ -353,3 +354,16 @@ describe('Ethereum signer', () => {
});
});
});

describe('Ledger Signer', () => {
// signature of Ledger can't be tested automatically.
// So, just the test of the path encoding.
test('getLedgerPathBuffer', () => {
const path = getLedgerPathBuffer(3, 'AstroAPP');
expect(path).toEqual(
new Uint8Array([
128, 0, 10, 85, 71, 65, 233, 201, 95, 192, 123, 107, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0,
])
);
});
});
59 changes: 59 additions & 0 deletions __tests__/utils/hash.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { keccakBn, starknetKeccak, getSelectorFromName, getSelector } from '../../src/utils/hash';
import { constants, hash } from '../../src';

describe('keccakBn', () => {
test('should properly calculate the Keccak hash', () => {
Expand Down Expand Up @@ -38,4 +39,62 @@ describe('getSelector', () => {
test('should return the proper selector when provided a decimal string', () => {
expect(getSelector('123456')).toBe('0x1e240');
});

test('should return the proper selector when provided a number', () => {
expect(getSelector(123456)).toBe('0x1e240');
});

test('should return the proper selector when provided a bigint', () => {
expect(getSelector(123456n)).toBe('0x1e240');
});
});

describe('L1->L2 messaging', () => {
// L1 tx for a message L1->L2
// data extracted from :
// https://sepolia.etherscan.io/tx/0xd82ce7dd9f3964d89d2eb9d555e1460fb7792be274950abe578d610f95cc40f5
// data extracted from etherscan :
const l1FromAddress = '0x0000000000000000000000008453fc6cd1bcfe8d4dfc069c400b433054d47bdc';
const l2ToAddress = 2158142789748719025684046545159279785659305214176670733242887773692203401023n;
const l2Selector = 774397379524139446221206168840917193112228400237242521560346153613428128537n;
const payload = [
4543560n,
829565602143178078434185452406102222830667255948n,
3461886633118033953192540141609307739580461579986333346825796013261542798665n,
9000000000000000n,
0n,
];
const l1Nonce = 8288n;

test('solidityUint256PackedKeccak256', () => {
const kec256Hash = hash.solidityUint256PackedKeccak256(['0x100', '200', 300, 400n]);
expect(kec256Hash).toBe('0xd1e6cb422b65269603c491b0c85463295edabebfb2a6844e4fdc389ff1dcdd97');
});

test('getL2MessageHash', () => {
// https://sepolia.starkscan.co/message/0x2e350fa9d830482605cb68be4fdb9f0cb3e1f95a0c51623ac1a5d1bd997c2090#messagelogs
const l1ToL2MessageHash = hash.getL2MessageHash(
l1FromAddress,
l2ToAddress,
l2Selector,
payload,
l1Nonce
);
expect(l1ToL2MessageHash).toBe(
'0x2e350fa9d830482605cb68be4fdb9f0cb3e1f95a0c51623ac1a5d1bd997c2090'
);
});

test('calculateL2MessageTxHash', () => {
// https://sepolia.starkscan.co/tx/0x067d959200d65d4ad293aa4b0da21bb050a1f669bce37d215c6edbf041269c07
const l2TxHash = hash.calculateL2MessageTxHash(
l1FromAddress,
l2ToAddress,
l2Selector,
payload,
constants.StarknetChainId.SN_SEPOLIA,
l1Nonce
);
expect(l2TxHash).toBe('0x67d959200d65d4ad293aa4b0da21bb050a1f669bce37d215c6edbf041269c07');
});
});
8 changes: 8 additions & 0 deletions __tests__/utils/num.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
isNumber,
isBoolean,
} from '../../src/utils/num';
import { num } from '../../src';

describe('isHex', () => {
test('should return true for valid hex strings', () => {
Expand Down Expand Up @@ -208,3 +209,10 @@ describe('isBoolean', () => {
expect(isBoolean({})).toBe(false);
});
});

describe('stringToSha256ToArrayBuff4', () => {
test('should correctly hash&encode an utf8 string', () => {
const buff = num.stringToSha256ToArrayBuff4('LedgerW');
expect(buff).toEqual(new Uint8Array([43, 206, 231, 219]));
});
});
Loading

0 comments on commit df78f60

Please sign in to comment.