Skip to content

Commit

Permalink
feat: add rpc provider
Browse files Browse the repository at this point in the history
  • Loading branch information
janek26 committed Jun 28, 2022
1 parent 9d787db commit 315bb74
Show file tree
Hide file tree
Showing 7 changed files with 714 additions and 30 deletions.
144 changes: 144 additions & 0 deletions __tests__/rpcProvider.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { RPCProvider } from '../src';
import { compiledOpenZeppelinAccount } from './fixtures';

const { TEST_RPC_URL } = process.env;

if (!TEST_RPC_URL) {
throw new Error('TEST_RPC_URL is not set');
}

describe('RPCProvider', () => {
let provider: RPCProvider;

beforeAll(async () => {
provider = new RPCProvider({ nodeUrl: TEST_RPC_URL });
});

describe('RPC methods', () => {
test('getChainId', async () => {
const chainId = await provider.getChainId();
expect(chainId).toBe('0x534e5f474f45524c49');
});
test('getBlock - latest', async () => {
const latestBlock = await provider.getBlock();
expect(latestBlock).toHaveProperty('block_hash');
expect(latestBlock).toHaveProperty('parent_hash');
expect(latestBlock).toHaveProperty('block_number');
expect(latestBlock).toHaveProperty('status');
expect(latestBlock).toHaveProperty('sequencer');
expect(latestBlock).toHaveProperty('new_root');
expect(latestBlock).toHaveProperty('new_root');
expect(latestBlock).toHaveProperty('old_root');
expect(latestBlock).toHaveProperty('accepted_time');
expect(latestBlock).toHaveProperty('gas_price');
expect(latestBlock).toHaveProperty('transactions');
});
test('getBlock - Block Hash 0x10a93fa4c6b310e4aaef16347c50c43320474dba75379b35399943239637aeb', async () => {
const block = await provider.getBlock(
'0x10a93fa4c6b310e4aaef16347c50c43320474dba75379b35399943239637aeb'
);
expect(block).toHaveProperty('block_hash');
expect(block).toHaveProperty('parent_hash');
expect(block).toHaveProperty('block_number');
expect(block).toHaveProperty('status');
expect(block).toHaveProperty('sequencer');
expect(block).toHaveProperty('new_root');
expect(block).toHaveProperty('new_root');
expect(block).toHaveProperty('old_root');
expect(block).toHaveProperty('accepted_time');
expect(block).toHaveProperty('gas_price');
expect(block).toHaveProperty('transactions');
});
test('getBlock - Block Number 102634', async () => {
const block = await provider.getBlock(102634);
expect(block).toHaveProperty('block_hash');
expect(block).toHaveProperty('parent_hash');
expect(block).toHaveProperty('block_number');
expect(block).toHaveProperty('status');
expect(block).toHaveProperty('sequencer');
expect(block).toHaveProperty('new_root');
expect(block).toHaveProperty('new_root');
expect(block).toHaveProperty('old_root');
expect(block).toHaveProperty('accepted_time');
expect(block).toHaveProperty('gas_price');
expect(block).toHaveProperty('transactions');
});
test('getStorageAt - latest', async () => {
const storage = await provider.getStorageAt(
'0x01d1f307c073bb786a66e6e042ec2a9bdc385a3373bb3738d95b966d5ce56166',
0
);
expect(typeof storage).toBe('string');
});
test('getStorageAt - Block Hash 0x7104702055c2a5773a870ceada9552ec659d69c18053b14078983f07527dea8', async () => {
const storage = await provider.getStorageAt(
'0x01d1f307c073bb786a66e6e042ec2a9bdc385a3373bb3738d95b966d5ce56166',
0,
'0x7225762c7ff5e7e5f0867f0a8e73594df4f44f05a65375339a76398e8ae3e64'
);
expect(typeof storage).toBe('string');
});
test('getTransaction - Transaction Hash 0x37013e1cb9c133e6fe51b4b371b76b317a480f56d80576730754c1662582348', async () => {
const transaction = await provider.getTransaction(
'0x37013e1cb9c133e6fe51b4b371b76b317a480f56d80576730754c1662582348'
);
expect(transaction).toHaveProperty('txn_hash');
expect(transaction).toHaveProperty('calldata');
expect(transaction).toHaveProperty('entry_point_selector');
expect(transaction).toHaveProperty('contract_address');
});
test('getTransactionReceipt - Transaction Hash 0x37013e1cb9c133e6fe51b4b371b76b317a480f56d80576730754c1662582348', async () => {
const receipt = await provider.getTransactionReceipt(
'0x37013e1cb9c133e6fe51b4b371b76b317a480f56d80576730754c1662582348'
);
expect(receipt).toHaveProperty('txn_hash');
expect(receipt).toHaveProperty('status');
expect(receipt).toHaveProperty('status_data');
expect(receipt).toHaveProperty('messages_sent');
expect(receipt).toHaveProperty('l1_origin_message');
expect(receipt).toHaveProperty('events');
});
test('getCode', async () => {
const code = await provider.getCode(
'0x01d1f307c073bb786a66e6e042ec2a9bdc385a3373bb3738d95b966d5ce56166'
);
expect(code).toHaveProperty('abi');
expect(code).toHaveProperty('bytecode');
});
test('get transaction receipt', async () => {
const transaction = await provider.getTransactionReceipt(
'0x37013e1cb9c133e6fe51b4b371b76b317a480f56d80576730754c1662582348'
);
expect(transaction).toHaveProperty('events');
expect(transaction).toHaveProperty('l1_origin_message');
expect(transaction).toHaveProperty('messages_sent');
expect(transaction).toHaveProperty('status');
expect(transaction).toHaveProperty('status_data');
expect(transaction).toHaveProperty('txn_hash');
});
test('getCode - Contract Address 0x01d1f307c073bb786a66e6e042ec2a9bdc385a3373bb3738d95b966d5ce56166', async () => {
const code = await provider.getCode(
'0x01d1f307c073bb786a66e6e042ec2a9bdc385a3373bb3738d95b966d5ce56166'
);
expect(code).toHaveProperty('abi');
expect(code).toHaveProperty('bytecode');
});
test('callContract', async () => {
expect(
provider.callContract({
contractAddress: '0x9ff64f4ab0e1fe88df4465ade98d1ea99d5732761c39279b8e1374fa943e9b',
entrypoint: 'balance_of',
calldata: ['0x9ff64f4ab0e1fe88df4465ade98d1ea99d5732761c39279b8e1374fa943e9b'],
})
).resolves.not.toThrow();
});
test('deployContract', async () => {
const response = await provider.deployContract({
contract: compiledOpenZeppelinAccount,
});

expect(response).toHaveProperty('transaction_hash');
expect(response).toHaveProperty('address');
});
});
});
4 changes: 2 additions & 2 deletions src/account/default.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import assert from 'minimalistic-assert';

import { ZERO } from '../constants';
import { Provider, ProviderInterface } from '../provider';
import { Provider, ProviderOptions } from '../provider';
import { Signer, SignerInterface } from '../signer';
import {
Abi,
Expand Down Expand Up @@ -35,7 +35,7 @@ export class Account extends Provider implements AccountInterface {
public signer: SignerInterface;

constructor(
provider: ProviderInterface,
provider: ProviderOptions,
address: string,
keyPairOrSigner: KeyPair | SignerInterface
) {
Expand Down
34 changes: 18 additions & 16 deletions src/provider/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,14 @@ import { BlockIdentifier, getFormattedBlockIdentifier } from './utils';

type NetworkName = 'mainnet-alpha' | 'goerli-alpha';

type ProviderOptions = { network: NetworkName } | { baseUrl: string };
export type ProviderOptions =
| { network: NetworkName }
| {
baseUrl: string;
feederGatewayUrl?: string;
gatewayUrl?: string;
chainId?: StarknetChainId;
};

function wait(delay: number) {
return new Promise((res) => {
Expand All @@ -55,24 +62,19 @@ export class Provider implements ProviderInterface {

public chainId: StarknetChainId;

constructor(
optionsOrProvider: ProviderOptions | ProviderInterface = { network: 'goerli-alpha' }
) {
if (optionsOrProvider instanceof ProviderInterface) {
constructor(optionsOrProvider: ProviderOptions = { network: 'goerli-alpha' }) {
if ('network' in optionsOrProvider) {
this.baseUrl = Provider.getNetworkFromName(optionsOrProvider.network);
this.chainId = Provider.getChainIdFromBaseUrl(this.baseUrl);
this.feederGatewayUrl = urljoin(this.baseUrl, 'feeder_gateway');
this.gatewayUrl = urljoin(this.baseUrl, 'gateway');
} else {
this.baseUrl = optionsOrProvider.baseUrl;
this.feederGatewayUrl = optionsOrProvider.feederGatewayUrl;
this.gatewayUrl = optionsOrProvider.gatewayUrl;
this.feederGatewayUrl =
optionsOrProvider.feederGatewayUrl ?? urljoin(this.baseUrl, 'feeder_gateway');
this.gatewayUrl = optionsOrProvider.gatewayUrl ?? urljoin(this.baseUrl, 'gateway');
this.chainId =
optionsOrProvider.chainId ?? Provider.getChainIdFromBaseUrl(optionsOrProvider.baseUrl);
} else {
const baseUrl =
'baseUrl' in optionsOrProvider
? optionsOrProvider.baseUrl
: Provider.getNetworkFromName(optionsOrProvider.network);
this.baseUrl = baseUrl;
this.chainId = Provider.getChainIdFromBaseUrl(baseUrl);
this.feederGatewayUrl = urljoin(baseUrl, 'feeder_gateway');
this.gatewayUrl = urljoin(baseUrl, 'gateway');
}
}

Expand Down
1 change: 1 addition & 0 deletions src/provider/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ import { Provider } from './default';
export * from './default';
export * from './errors';
export * from './interface';
export * from './rpcProvider';

export const defaultProvider = new Provider();
27 changes: 16 additions & 11 deletions src/provider/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@ import type {
CallContractResponse,
DeployContractPayload,
GetBlockResponse,
GetBlockResponseRPC,
GetCodeResponse,
GetCodeResponseRPC,
GetContractAddressesResponse,
GetStorageAtResponseRPC,
GetTransactionReceiptResponseRPC,
GetTransactionResponse,
GetTransactionResponseRPC,
GetTransactionStatusResponse,
Invocation,
TransactionReceiptResponse,
Expand All @@ -16,12 +21,6 @@ import type { BigNumberish } from '../utils/number';
import { BlockIdentifier } from './utils';

export abstract class ProviderInterface {
public abstract baseUrl: string;

public abstract feederGatewayUrl: string;

public abstract gatewayUrl: string;

public abstract chainId: StarknetChainId;

/**
Expand Down Expand Up @@ -56,7 +55,9 @@ export abstract class ProviderInterface {
* @param blockIdentifier block identifier
* @returns the block object { block_number, previous_block_number, state_root, status, timestamp, transaction_receipts, transactions }
*/
public abstract getBlock(blockIdentifier?: BlockIdentifier): Promise<GetBlockResponse>;
public abstract getBlock(
blockIdentifier?: BlockIdentifier
): Promise<GetBlockResponse | GetBlockResponseRPC>;

/**
* Gets the code of the deployed contract.
Expand All @@ -70,7 +71,7 @@ export abstract class ProviderInterface {
public abstract getCode(
contractAddress: string,
blockIdentifier?: BlockIdentifier
): Promise<GetCodeResponse>;
): Promise<GetCodeResponse | GetCodeResponseRPC>;

// TODO: add proper type
/**
Expand All @@ -87,7 +88,7 @@ export abstract class ProviderInterface {
contractAddress: string,
key: BigNumberish,
blockIdentifier?: BlockIdentifier
): Promise<object>;
): Promise<object | GetStorageAtResponseRPC>;

/**
* Gets the status of a transaction.
Expand All @@ -107,7 +108,9 @@ export abstract class ProviderInterface {
* @param txHash
* @returns the transacton object { transaction_id, status, transaction, block_number?, block_number?, transaction_index?, transaction_failure_reason? }
*/
public abstract getTransaction(txHash: BigNumberish): Promise<GetTransactionResponse>;
public abstract getTransaction(
txHash: BigNumberish
): Promise<GetTransactionResponse | GetTransactionResponseRPC>;

/**
* Gets the transaction receipt from a tx hash.
Expand All @@ -117,7 +120,9 @@ export abstract class ProviderInterface {
* @param txHash
* @returns the transaction receipt object
*/
public abstract getTransactionReceipt(txHash: BigNumberish): Promise<TransactionReceiptResponse>;
public abstract getTransactionReceipt(
txHash: BigNumberish
): Promise<TransactionReceiptResponse | GetTransactionReceiptResponseRPC>;

/**
* Deploys a given compiled contract (json) to starknet
Expand Down
Loading

0 comments on commit 315bb74

Please sign in to comment.