Skip to content

fix: make the provider create method generic to enable it when mixins are applied #1370

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

Merged
merged 1 commit into from
Apr 9, 2025
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
43 changes: 29 additions & 14 deletions __tests__/rpcProvider.test.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,26 @@
import { getStarkKey, Signature, utils } from '@scure/starknet';
import { hasMixin } from 'ts-mixer';
import {
contracts,
createBlockForDevnet,
createTestProvider,
describeIfDevnet,
describeIfNotDevnet,
describeIfRpc,
describeIfTestnet,
ETHtokenAddress,
getTestAccount,
waitNextBlock,
} from './config/fixtures';
import { initializeMatcher } from './config/schema';
import typedDataExample from '../__mocks__/typedData/baseExample.json';
import {
Account,
Block,
CallData,
Contract,
FeeEstimate,
LibraryError,
ProviderInterface,
RPC,
RPCResponseParser,
Expand All @@ -19,21 +34,11 @@ import {
import { StarknetChainId } from '../src/global/constants';
import { felt, uint256 } from '../src/utils/calldata/cairo';
import { toBigInt, toHexString } from '../src/utils/num';
import {
contracts,
createBlockForDevnet,
createTestProvider,
describeIfDevnet,
describeIfNotDevnet,
describeIfRpc,
describeIfTestnet,
ETHtokenAddress,
getTestAccount,
waitNextBlock,
} from './config/fixtures';
import { initializeMatcher } from './config/schema';
import { isBoolean } from '../src/utils/typed';
import { isVersion } from '../src/utils/provider';
import { isBoolean } from '../src/utils/typed';
import { RpcProvider as BaseRpcProvider } from '../src/provider/rpc';
import { RpcProvider as ExtendedRpcProvider } from '../src/provider/extensions/default';
import { StarknetId } from '../src/provider/extensions/starknetId';

describeIfRpc('RPCProvider', () => {
let rpcProvider: RpcProvider;
Expand All @@ -53,6 +58,16 @@ describeIfRpc('RPCProvider', () => {
await createBlockForDevnet();
});

test('create should be usable by the base and extended RpcProvider, but not Account', async () => {
const nodeUrl = process.env.TEST_RPC_URL;
const base = await BaseRpcProvider.create({ nodeUrl });
const extended = await ExtendedRpcProvider.create({ nodeUrl });

expect(hasMixin(base, StarknetId)).toBe(false);
expect(hasMixin(extended, StarknetId)).toBe(true);
await expect(Account.create()).rejects.toThrow(LibraryError);
});

test('detect spec version with create', async () => {
const providerTest = await RpcProvider.create({ nodeUrl: process.env.TEST_RPC_URL });
const { channel } = providerTest;
Expand Down
9 changes: 8 additions & 1 deletion src/account/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
UDC,
ZERO,
} from '../global/constants';
import { Provider, ProviderInterface } from '../provider';
import { LibraryError, Provider, ProviderInterface } from '../provider';
import { Signer, SignerInterface } from '../signer';
import {
AccountInvocations,
Expand Down Expand Up @@ -119,6 +119,13 @@ export class Account extends Provider implements AccountInterface {
});
}

/** @deprecated @hidden */
// The deprecation tag is meant to discourage use, not to signal future removal
// it should only be removed if the relationship with the corresponding Provider.create(...) method changes
static async create(): Promise<never> {
throw new LibraryError('Not supported');
}

// provided version or contract based preferred transactionVersion
protected getPreferredVersion(type12: ETransactionVersion, type3: ETransactionVersion) {
if (this.transactionVersion === ETransactionVersion.V3) return type3;
Expand Down
12 changes: 8 additions & 4 deletions src/provider/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,18 +92,22 @@ export class RpcProvider implements ProviderInterface {
* auto configure channel based on provided node
* leave space for other async before constructor
*/
static async create(optionsOrProvider?: RpcProviderOptions) {
// NOTE: the generic T and 'this' reference are used so that the expanded class is generated when a mixin is applied
static async create<T extends RpcProvider>(
this: { new (...args: ConstructorParameters<typeof RpcProvider>): T },
optionsOrProvider?: RpcProviderOptions
): Promise<T> {
const channel = new RPC07.RpcChannel({ ...optionsOrProvider });
const spec = await channel.getSpecVersion();

if (isVersion('0.7', spec)) {
return new RpcProvider({ ...optionsOrProvider, specVersion: '0.7' });
return new this({ ...optionsOrProvider, specVersion: '0.7' }) as T;
}
if (isVersion('0.8', spec)) {
return new RpcProvider({ ...optionsOrProvider, specVersion: '0.8' });
return new this({ ...optionsOrProvider, specVersion: '0.8' }) as T;
}

throw new Error('unable to detect specification version');
throw new LibraryError('Unable to detect specification version');
}

public fetch(method: string, params?: object, id: string | number = 0) {
Expand Down