Skip to content

Commit

Permalink
Merge pull request #399 from 0xs34n/use-faster-hasing
Browse files Browse the repository at this point in the history
feat(v5): Native BigInt and faster hashing
  • Loading branch information
dhruvkelawala authored Jan 6, 2023
2 parents 4a2a40f + 209f120 commit ec56c29
Show file tree
Hide file tree
Showing 52 changed files with 4,935 additions and 4,219 deletions.
57 changes: 29 additions & 28 deletions __tests__/account.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { isBN } from 'bn.js';
import { pedersen, sign } from '@noble/curves/stark';

import typedDataExample from '../__mocks__/typedDataExample.json';
import { Account, Contract, Provider, number, stark } from '../src';
import { getKeyPair, sign } from '../src/utils/ellipticCurve';
import { parseUDCEvent } from '../src/utils/events';
import { feeTransactionVersion, pedersen } from '../src/utils/hash';
import { cleanHex, hexToDecimalString, toBN } from '../src/utils/number';
import { feeTransactionVersion } from '../src/utils/hash';
import { cleanHex, hexToDecimalString, toBigInt, toHex } from '../src/utils/number';
import { encodeShortString } from '../src/utils/shortString';
import { randomAddress } from '../src/utils/stark';
import {
Expand All @@ -28,9 +27,8 @@ describe('deploy and test Wallet', () => {
beforeAll(async () => {
expect(account).toBeInstanceOf(Account);

const declareDeploy = await account.declareDeploy({
const declareDeploy = await account.declareAndDeploy({
contract: compiledErc20,
classHash: '0x54328a1075b8820eb43caf0caa233923148c983742402dcfc38541dd843d01a',
constructorCalldata: [
encodeShortString('Token'),
encodeShortString('ERC20'),
Expand All @@ -43,9 +41,9 @@ describe('deploy and test Wallet', () => {

const x = await erc20.balanceOf(account.address);

expect(number.toBN(x[0].low).toString()).toStrictEqual(number.toBN(1000).toString());
expect(number.toBigInt(x[0].low).toString()).toStrictEqual(number.toBigInt(1000).toString());

const dappResponse = await account.declareDeploy({
const dappResponse = await account.declareAndDeploy({
contract: compiledTestDapp,
classHash: '0x04367b26fbb92235e8d1137d19c080e6e650a6889ded726d00658411cc1046f5',
});
Expand All @@ -60,15 +58,15 @@ describe('deploy and test Wallet', () => {
entrypoint: 'transfer',
calldata: [erc20.address, '10', '0'],
});
expect(isBN(overall_fee)).toBe(true);
expect(typeof overall_fee === 'bigint').toBe(true);
expect(innerInvokeEstFeeSpy.mock.calls[0][1].version).toBe(feeTransactionVersion);
innerInvokeEstFeeSpy.mockClear();
});

test('read balance of wallet', async () => {
const x = await erc20.balanceOf(account.address);

expect(number.toBN(x[0].low).toString()).toStrictEqual(number.toBN(1000).toString());
expect(number.toBigInt(x[0].low).toString()).toStrictEqual(number.toBigInt(1000).toString());
});

test('execute by wallet owner', async () => {
Expand All @@ -84,12 +82,12 @@ describe('deploy and test Wallet', () => {
test('read balance of wallet after transfer', async () => {
const { balance } = await erc20.balanceOf(account.address);

expect(balance.low).toStrictEqual(toBN(990));
expect(balance.low).toStrictEqual(toBigInt(990));
});

test('execute with custom nonce', async () => {
const result = await account.getNonce();
const nonce = toBN(result).toNumber();
const nonce = toBigInt(result);
const { transaction_hash } = await account.execute(
{
contractAddress: erc20Address,
Expand Down Expand Up @@ -120,14 +118,21 @@ describe('deploy and test Wallet', () => {
await provider.waitForTransaction(transaction_hash, undefined, ['ACCEPTED_ON_L2']);

const response = await dapp.get_number(account.address);
expect(toBN(response.number as string).toString()).toStrictEqual('57');
expect(toBigInt(response.number as string).toString()).toStrictEqual('57');
});

test('sign and verify offchain message fail', async () => {
const signature = await account.signMessage(typedDataExample);
const [r, s] = stark.formatSignature(signature);

// change the signature to make it invalid
signature[0] += '123';
expect(await account.verifyMessage(typedDataExample, signature)).toBe(false);
const r2 = toBigInt(r) + 123n;

const signature2 = stark.parseSignature([r2.toString(), s]);

if (!signature2) return;

expect(await account.verifyMessage(typedDataExample, signature2)).toBe(false);
});

test('sign and verify offchain message', async () => {
Expand Down Expand Up @@ -171,16 +176,14 @@ describe('deploy and test Wallet', () => {

test('Get the stark name of the account and account from stark name (using starknet.id)', async () => {
// Deploy naming contract
const namingResponse = await account.declareDeploy({
const namingResponse = await account.declareAndDeploy({
contract: compiledNamingContract,
classHash: '0x3f2f8c80ab2d404bcfb4182e8528708e4efa2c646dd711bdd7b721ecc6111f7',
});
const namingAddress = namingResponse.deploy.contract_address;

// Deploy Starknet id contract
const idResponse = await account.declareDeploy({
const idResponse = await account.declareAndDeploy({
contract: compiledStarknetId,
classHash: '0x1eb5a8308760d82321cb3ee8967581bb1d38348c7d2f082a07580040c52217c',
});
const idAddress = idResponse.deploy.contract_address;

Expand All @@ -189,12 +192,11 @@ describe('deploy and test Wallet', () => {
'1893860513534673656759973582609638731665558071107553163765293299136715951024';
const whitelistingPrivateKey =
'301579081698031303837612923223391524790804435085778862878979120159194507372';
const hashed = pedersen([
pedersen([toBN('18925'), toBN('1922775124')]),
toBN(hexToDecimalString(account.address)),
]);
const keyPair = getKeyPair(toBN(whitelistingPrivateKey));
const signed = sign(keyPair, hashed);
const hashed = pedersen(
pedersen(toBigInt('18925'), toBigInt('1922775124')),
toBigInt(account.address)
);
const signed = sign(hashed, toHex(whitelistingPrivateKey));

const { transaction_hash } = await account.execute([
{
Expand All @@ -221,8 +223,8 @@ describe('deploy and test Wallet', () => {
'1922775124', // Expiry
'1', // Starknet id linked
account.address, // receiver_address
signed[0], // sig 0 for whitelist
signed[1], // sig 1 for whitelist
signed.r, // sig 0 for whitelist
signed.s, // sig 1 for whitelist
],
},
{
Expand All @@ -248,7 +250,6 @@ describe('deploy and test Wallet', () => {
describe('Declare and UDC Deploy Flow', () => {
test('ERC20 Declare', async () => {
const declareTx = await account.declare({
classHash: erc20ClassHash,
contract: compiledErc20,
});

Expand Down
46 changes: 20 additions & 26 deletions __tests__/contract.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { isBN } from 'bn.js';

import { Contract, ContractFactory, stark } from '../src';
import { getSelectorFromName } from '../src/utils/hash';
import { BigNumberish, toBN } from '../src/utils/number';
import { BigNumberish, isBigInt, toBigInt } from '../src/utils/number';
import { encodeShortString } from '../src/utils/shortString';
import { compileCalldata } from '../src/utils/stark';
import {
Expand All @@ -27,17 +25,15 @@ describe('contract module', () => {
let multicallContract: Contract;

beforeAll(async () => {
const { deploy } = await account.declareDeploy({
const { deploy } = await account.declareAndDeploy({
contract: compiledErc20,
classHash: '0x54328a1075b8820eb43caf0caa233923148c983742402dcfc38541dd843d01a',
constructorCalldata: [encodeShortString('Token'), encodeShortString('ERC20'), wallet],
});

erc20Contract = new Contract(compiledErc20.abi, deploy.contract_address!, provider);

const { deploy: multicallDeploy } = await account.declareDeploy({
const { deploy: multicallDeploy } = await account.declareAndDeploy({
contract: compiledMulticall,
classHash: '0x06f94f3229a8d9c1d51cb84f1f5ec306c8552a805e307540727dda53c4936b43',
});

multicallContract = new Contract(
Expand All @@ -61,7 +57,7 @@ describe('contract module', () => {
test('read initial balance of that account', async () => {
const result = await erc20Contract.balanceOf(wallet);
const [res] = result;
expect(res.low).toStrictEqual(toBN(1000));
expect(res.low).toStrictEqual(toBigInt(1000));
expect(res).toStrictEqual(result.balance);
});

Expand All @@ -81,9 +77,9 @@ describe('contract module', () => {
];
const result = await multicallContract.aggregate(calls);
const [block_number, res] = result;
expect(isBN(block_number));
expect(isBigInt(block_number));
expect(Array.isArray(res));
(res as BigNumberish[]).forEach((el) => expect(isBN(el)));
(res as BigNumberish[]).forEach((el) => expect(isBigInt(el)));
expect(block_number).toStrictEqual(result.block_number);
expect(res).toStrictEqual(result.result);
});
Expand All @@ -93,9 +89,8 @@ describe('contract module', () => {
let typeTransformedContract: Contract;

beforeAll(async () => {
const { deploy } = await account.declareDeploy({
const { deploy } = await account.declareAndDeploy({
contract: compiledTypeTransformation,
classHash: '0x022a0e662b13d18a2aaa3ee54ae290de6569621b549022c18169c6e7893809ea',
});

typeTransformedContract = new Contract(
Expand Down Expand Up @@ -152,55 +147,55 @@ describe('contract module', () => {
describe('Response Type Transformation', () => {
test('Parsing the felt in response', async () => {
const { res } = await typeTransformedContract.get_felt();
expect(res).toStrictEqual(toBN(4));
expect(res).toStrictEqual(toBigInt(4));
});

test('Parsing the array of felt in response', async () => {
const result = await typeTransformedContract.get_array_of_felts();
const [res] = result;
expect(res).toStrictEqual([toBN(4), toBN(5)]);
expect(res).toStrictEqual([toBigInt(4), toBigInt(5)]);
expect(res).toStrictEqual(result.res);
});

test('Parsing the array of structs in response', async () => {
const result = await typeTransformedContract.get_struct();
const [res] = result;
expect(res).toStrictEqual({ x: toBN(1), y: toBN(2) });
expect(res).toStrictEqual({ x: toBigInt(1), y: toBigInt(2) });
expect(res).toStrictEqual(result.res);
});

test('Parsing the array of structs in response', async () => {
const result = await typeTransformedContract.get_array_of_structs();
const [res] = result;
expect(res).toStrictEqual([{ x: toBN(1), y: toBN(2) }]);
expect(res).toStrictEqual([{ x: toBigInt(1), y: toBigInt(2) }]);
expect(res).toStrictEqual(result.res);
});

test('Parsing the nested structs in response', async () => {
const result = await typeTransformedContract.get_nested_structs();
const [res] = result;
expect(res).toStrictEqual({
p1: { x: toBN(1), y: toBN(2) },
p2: { x: toBN(3), y: toBN(4) },
extra: toBN(5),
p1: { x: toBigInt(1), y: toBigInt(2) },
p2: { x: toBigInt(3), y: toBigInt(4) },
extra: toBigInt(5),
});
expect(res).toStrictEqual(result.res);
});

test('Parsing the tuple in response', async () => {
const result = await typeTransformedContract.get_tuple();
const [res] = result;
expect(res).toStrictEqual([toBN(1), toBN(2), toBN(3)]);
expect(res).toStrictEqual([toBigInt(1), toBigInt(2), toBigInt(3)]);
expect(res).toStrictEqual(result.res);
});

test('Parsing the multiple types in response', async () => {
const result = await typeTransformedContract.get_mixed_types();
const [tuple, number, array, point] = result;
expect(tuple).toStrictEqual([toBN(1), toBN(2)]);
expect(number).toStrictEqual(toBN(3));
expect(array).toStrictEqual([toBN(4)]);
expect(point).toStrictEqual({ x: toBN(1), y: toBN(2) });
expect(tuple).toStrictEqual([toBigInt(1), toBigInt(2)]);
expect(number).toStrictEqual(toBigInt(3));
expect(array).toStrictEqual([toBigInt(4)]);
expect(point).toStrictEqual({ x: toBigInt(1), y: toBigInt(2) });
expect(tuple).toStrictEqual(result.tuple);
expect(number).toStrictEqual(result.number);
expect(array).toStrictEqual(result.array);
Expand All @@ -212,9 +207,8 @@ describe('contract module', () => {

describe('class ContractFactory {}', () => {
beforeAll(async () => {
await account.declareDeploy({
await account.declareAndDeploy({
contract: compiledErc20,
classHash: '0x54328a1075b8820eb43caf0caa233923148c983742402dcfc38541dd843d01a',
constructorCalldata,
});
});
Expand Down
9 changes: 4 additions & 5 deletions __tests__/defaultProvider.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BlockNumber, GetBlockResponse, Provider, stark } from '../src';
import { toBN } from '../src/utils/number';
import { toBigInt } from '../src/utils/number';
import { encodeShortString } from '../src/utils/shortString';
import { compiledErc20, erc20ClassHash, getTestAccount, getTestProvider } from './fixtures';

Expand All @@ -19,9 +19,8 @@ describe('defaultProvider', () => {
beforeAll(async () => {
expect(testProvider).toBeInstanceOf(Provider);

const { deploy } = await account.declareDeploy({
const { deploy } = await account.declareAndDeploy({
contract: compiledErc20,
classHash: '0x54328a1075b8820eb43caf0caa233923148c983742402dcfc38541dd843d01a',
constructorCalldata: [encodeShortString('Token'), encodeShortString('ERC20'), wallet],
});

Expand Down Expand Up @@ -79,7 +78,7 @@ describe('defaultProvider', () => {

test('getNonceForAddress()', async () => {
const nonce = await testProvider.getNonceForAddress(erc20ContractAddress);
return expect(toBN(nonce)).toEqual(toBN('0x0'));
return expect(toBigInt(nonce)).toEqual(toBigInt('0x0'));
});

test('getClassAt(contractAddress, blockNumber="latest")', async () => {
Expand Down Expand Up @@ -112,7 +111,7 @@ describe('defaultProvider', () => {

test('with "key" type of BN', () => {
return expect(
testProvider.getStorageAt(erc20ContractAddress, toBN('0x0'))
testProvider.getStorageAt(erc20ContractAddress, toBigInt('0x0'))
).resolves.not.toThrow();
});
});
Expand Down
4 changes: 2 additions & 2 deletions __tests__/fixtures.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import fs from 'fs';
import path from 'path';

import { Account, ProviderInterface, RpcProvider, SequencerProvider, ec, json } from '../src';
import { Account, ProviderInterface, RpcProvider, SequencerProvider, json } from '../src';
import { CompiledContract } from '../src/types';

const readContract = (name: string): CompiledContract =>
Expand Down Expand Up @@ -72,7 +72,7 @@ export const getTestAccount = (provider: ProviderInterface) => {
testAccountPrivateKey = DEFAULT_TEST_ACCOUNT_PRIVATE_KEY;
}

return new Account(provider, testAccountAddress, ec.getKeyPair(testAccountPrivateKey));
return new Account(provider, testAccountAddress, testAccountPrivateKey);
};

const describeIf = (condition: boolean) => (condition ? describe : describe.skip);
Expand Down
11 changes: 6 additions & 5 deletions __tests__/rpcProvider.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Account, GetBlockResponse, RpcProvider, ec } from '../src';
import { getStarkKey, utils } from '@noble/curves/stark';

import { Account, GetBlockResponse, RpcProvider } from '../src';
import { StarknetChainId } from '../src/constants';
import {
compiledOpenZeppelinAccount,
Expand All @@ -15,8 +17,8 @@ describeIfRpc('RPCProvider', () => {

beforeAll(async () => {
expect(account).toBeInstanceOf(Account);
const accountKeyPair = ec.genKeyPair();
accountPublicKey = ec.getStarkKey(accountKeyPair);
const accountKeyPair = utils.randomPrivateKey();
accountPublicKey = getStarkKey(accountKeyPair);
});

test('getChainId', async () => {
Expand Down Expand Up @@ -90,9 +92,8 @@ describeIfRpc('RPCProvider', () => {
let transaction_hash: string;

beforeAll(async () => {
const { deploy } = await account.declareDeploy({
const { deploy } = await account.declareAndDeploy({
contract: compiledOpenZeppelinAccount,
classHash: '0x03fcbf77b28c96f4f2fb5bd2d176ab083a12a5e123adeb0de955d7ee228c9854',
constructorCalldata: [accountPublicKey],
salt: accountPublicKey,
});
Expand Down
Loading

0 comments on commit ec56c29

Please sign in to comment.