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

Next version #1187

Merged
merged 19 commits into from
Jul 26, 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
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