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

Remove @coinbase/wallet-sdk dependency #290

Merged
merged 3 commits into from
Jan 19, 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
4 changes: 2 additions & 2 deletions react-native/client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@coinbase/wallet-mobile-sdk",
"version": "1.0.11",
"version": "1.0.12",
"description": "Coinbase Wallet Mobile SDK for React Native",
"main": "build/CoinbaseWalletSDK.js",
"types": "build/CoinbaseWalletSDK.d.ts",
Expand All @@ -27,11 +27,11 @@
"license": "Apache-2.0",
"homepage": "https://github.com/coinbase/wallet-mobile-sdk#readme",
"dependencies": {
"@coinbase/wallet-sdk": "3.9.1",
"@metamask/safe-event-emitter": "2.0.0",
"eth-rpc-errors": "4.0.3",
"buffer": "6.0.3",
"bn.js": "5.2.1",
"events": "^3.0.0",
"react-native-mmkv": "2.11.0"
},
"devDependencies": {
Expand Down
22 changes: 17 additions & 5 deletions react-native/client/src/WalletMobileSDKEVMProvider.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import {
RequestArguments,
Web3Provider,
} from "@coinbase/wallet-sdk/dist/provider/Web3Provider";
} from "./types/provider/Web3Provider";
import {
JSONRPCRequest,
JSONRPCResponse,
} from "@coinbase/wallet-sdk/dist/provider/JSONRPC";
} from "./types/provider/JSONRPC";
import {
AddressString,
Callback,
IntNumber,
} from "@coinbase/wallet-sdk/dist/core/type";
} from "./types/core/type";
import { ethErrors } from "eth-rpc-errors";
import {
initiateHandshake,
Expand All @@ -29,8 +29,7 @@ import {
hexStringFromBuffer,
hexStringFromIntNumber,
prepend0x,
} from "@coinbase/wallet-sdk/dist/core/util";
import { EthereumTransactionParams } from "@coinbase/wallet-sdk/dist/relay/walletlink/type/EthereumTransactionParams";
} from "./types/core/util";
import BN from "bn.js";
import { MMKV, NativeMMKV } from "react-native-mmkv";
import SafeEventEmitter from "@metamask/safe-event-emitter";
Expand Down Expand Up @@ -77,6 +76,19 @@ interface WatchAssetParams {
};
}

interface EthereumTransactionParams {
fromAddress: AddressString;
toAddress: AddressString | null;
weiValue: BN;
data: Buffer;
nonce: IntNumber | null;
gasPriceInWei: BN | null;
maxFeePerGas: BN | null; // in wei
maxPriorityFeePerGas: BN | null; // in wei
gasLimit: BN | null;
chainId: IntNumber;
}

export class WalletMobileSDKEVMProvider
extends SafeEventEmitter
implements Web3Provider
Expand Down
38 changes: 38 additions & 0 deletions react-native/client/src/types/core/type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Copyright (c) 2018-2023 Coinbase, Inc. <https://www.coinbase.com/>
// Licensed under the Apache License, version 2.0

interface Tag<T extends string, RealType> {
__tag__: T;
__realType__: RealType;
}

export type OpaqueType<T extends string, U> = U & Tag<T, U>;

export function OpaqueType<T extends Tag<string, unknown>>() {
return (value: T extends Tag<string, infer U> ? U : never): T => value as T;
}

export type HexString = OpaqueType<'HexString', string>;
export const HexString = OpaqueType<HexString>();

export type AddressString = OpaqueType<'AddressString', string>;
export const AddressString = OpaqueType<AddressString>();

export type BigIntString = OpaqueType<'BigIntString', string>;
export const BigIntString = OpaqueType<BigIntString>();

export type IntNumber = OpaqueType<'IntNumber', number>;
export function IntNumber(num: number): IntNumber {
return Math.floor(num) as IntNumber;
}

export type RegExpString = OpaqueType<'RegExpString', string>;
export const RegExpString = OpaqueType<RegExpString>();

export type Callback<T> = (err: Error | null, result: T | null) => void;

export enum ProviderType {
CoinbaseWallet = 'CoinbaseWallet',
MetaMask = 'MetaMask',
Unselected = '',
}
165 changes: 165 additions & 0 deletions react-native/client/src/types/core/util.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
// Copyright (c) 2018-2023 Coinbase, Inc. <https://www.coinbase.com/>
// Licensed under the Apache License, version 2.0

import BN from 'bn.js';

import { AddressString, BigIntString, HexString, IntNumber, RegExpString } from './type';

const INT_STRING_REGEX = /^[0-9]*$/;
const HEXADECIMAL_STRING_REGEX = /^[a-f0-9]*$/;

export function hexStringToUint8Array(hexString: string): Uint8Array {
return new Uint8Array(hexString.match(/.{1,2}/g)!.map((byte) => parseInt(byte, 16)));
}

export function hexStringFromBuffer(buf: Buffer, includePrefix = false): HexString {
const hex = buf.toString('hex');
return HexString(includePrefix ? `0x${hex}` : hex);
}

export function bigIntStringFromBN(bn: BN): BigIntString {
return BigIntString(bn.toString(10));
}

export function intNumberFromHexString(hex: HexString): IntNumber {
return IntNumber(new BN(ensureEvenLengthHexString(hex, false), 16).toNumber());
}

export function hexStringFromIntNumber(num: IntNumber): HexString {
return HexString(`0x${new BN(num).toString(16)}`);
}

export function has0xPrefix(str: string): boolean {
return str.startsWith('0x') || str.startsWith('0X');
}

export function strip0x(hex: string): string {
if (has0xPrefix(hex)) {
return hex.slice(2);
}
return hex;
}

export function prepend0x(hex: string): string {
if (has0xPrefix(hex)) {
return `0x${hex.slice(2)}`;
}
return `0x${hex}`;
}

export function isHexString(hex: unknown): hex is HexString {
if (typeof hex !== 'string') {
return false;
}
const s = strip0x(hex).toLowerCase();
return HEXADECIMAL_STRING_REGEX.test(s);
}

class InvalidParamsError extends Error {
code = -32602;
constructor(message: string) {
super(message);
}
}

export function ensureHexString(hex: unknown, includePrefix = false): HexString {
if (typeof hex === 'string') {
const s = strip0x(hex).toLowerCase();
if (HEXADECIMAL_STRING_REGEX.test(s)) {
return HexString(includePrefix ? `0x${s}` : s);
}
}
throw new InvalidParamsError(`"${String(hex)}" is not a hexadecimal string`);
}

export function ensureEvenLengthHexString(hex: unknown, includePrefix = false): HexString {
let h = ensureHexString(hex, false);
if (h.length % 2 === 1) {
h = HexString(`0${h}`);
}
return includePrefix ? HexString(`0x${h}`) : h;
}

export function ensureAddressString(str: unknown): AddressString {
if (typeof str === 'string') {
const s = strip0x(str).toLowerCase();
if (isHexString(s) && s.length === 40) {
return AddressString(prepend0x(s));
}
}
throw new InvalidParamsError(`Invalid Ethereum address: ${String(str)}`);
}

export function ensureBuffer(str: unknown): Buffer {
if (Buffer.isBuffer(str)) {
return str;
}
if (typeof str === 'string') {
if (isHexString(str)) {
const s = ensureEvenLengthHexString(str, false);
return Buffer.from(s, 'hex');
}
return Buffer.from(str, 'utf8');
}
throw new InvalidParamsError(`Not binary data: ${String(str)}`);
}

export function ensureIntNumber(num: unknown): IntNumber {
if (typeof num === 'number' && Number.isInteger(num)) {
return IntNumber(num);
}
if (typeof num === 'string') {
if (INT_STRING_REGEX.test(num)) {
return IntNumber(Number(num));
}
if (isHexString(num)) {
return IntNumber(new BN(ensureEvenLengthHexString(num, false), 16).toNumber());
}
}
throw new InvalidParamsError(`Not an integer: ${String(num)}`);
}

export function ensureRegExpString(regExp: unknown): RegExpString {
if (regExp instanceof RegExp) {
return RegExpString(regExp.toString());
}
throw new InvalidParamsError(`Not a RegExp: ${String(regExp)}`);
}

export function ensureBN(val: unknown): BN {
if (val !== null && (BN.isBN(val) || isBigNumber(val))) {
return new BN((val as any).toString(10), 10);
}
if (typeof val === 'number') {
return new BN(ensureIntNumber(val));
}
if (typeof val === 'string') {
if (INT_STRING_REGEX.test(val)) {
return new BN(val, 10);
}
if (isHexString(val)) {
return new BN(ensureEvenLengthHexString(val, false), 16);
}
}
throw new InvalidParamsError(`Not an integer: ${String(val)}`);
}

export function ensureParsedJSONObject<T extends object>(val: unknown): T {
if (typeof val === 'string') {
return JSON.parse(val) as T;
}

if (typeof val === 'object') {
return val as T;
}

throw new InvalidParamsError(`Not a JSON string or an object: ${String(val)}`);
}

export function isBigNumber(val: unknown): boolean {
if (val == null || typeof (val as any).constructor !== 'function') {
return false;
}
const { constructor } = val as any;
return typeof constructor.config === 'function' && typeof constructor.EUCLID === 'number';
}
58 changes: 58 additions & 0 deletions react-native/client/src/types/provider/JSONRPC.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Copyright (c) 2018-2023 Coinbase, Inc. <https://www.coinbase.com/>
// Licensed under the Apache License, version 2.0

export type JSONRPCMethod =
// synchronous or asynchronous
| 'eth_accounts'
| 'eth_coinbase'
| 'net_version'
| 'eth_chainId'
| 'eth_uninstallFilter' // synchronous

// asynchronous only
| 'eth_requestAccounts'
| 'eth_sign'
| 'eth_ecRecover'
| 'personal_sign'
| 'personal_ecRecover'
| 'eth_signTransaction'
| 'eth_sendRawTransaction'
| 'eth_sendTransaction'
| 'eth_signTypedData_v1'
| 'eth_signTypedData_v2'
| 'eth_signTypedData_v3'
| 'eth_signTypedData_v4'
| 'eth_signTypedData'
| 'walletlink_arbitrary' // compatibility
| 'wallet_addEthereumChain'
| 'wallet_switchEthereumChain'
| 'wallet_watchAsset'

// asynchronous pub/sub
| 'eth_subscribe'
| 'eth_unsubscribe'

// asynchronous filter methods
| 'eth_newFilter'
| 'eth_newBlockFilter'
| 'eth_newPendingTransactionFilter'
| 'eth_getFilterChanges'
| 'eth_getFilterLogs';

export interface JSONRPCRequest<T = any> {
jsonrpc: '2.0';
id: number;
method: string;
params: T;
}

export interface JSONRPCResponse<T = any, U = any> {
jsonrpc: '2.0';
id: number;
result?: T;
error?: {
code: number;
message: string;
data?: U;
} | null;
}
32 changes: 32 additions & 0 deletions react-native/client/src/types/provider/Web3Provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright (c) 2018-2023 Coinbase, Inc. <https://www.coinbase.com/>
// Licensed under the Apache License, version 2.0

import { Callback } from '../core/type';
import { JSONRPCRequest, JSONRPCResponse } from './JSONRPC';

export interface Web3Provider {
send(request: JSONRPCRequest): JSONRPCResponse;
send(request: JSONRPCRequest[]): JSONRPCResponse[];
send(request: JSONRPCRequest, callback: Callback<JSONRPCResponse>): void;
send(request: JSONRPCRequest[], callback: Callback<JSONRPCResponse[]>): void;
send<T = unknown>(method: string, params?: unknown[] | unknown): Promise<T>;

sendAsync(request: JSONRPCRequest, callback: Callback<JSONRPCResponse>): void;
sendAsync(request: JSONRPCRequest[], callback: Callback<JSONRPCResponse[]>): void;

request<T>(args: RequestArguments): Promise<T>;

host: string;
connected: boolean;
chainId: string;
supportsSubscriptions(): boolean;
disconnect(): boolean;
}

export interface RequestArguments {
/** The RPC method to request. */
method: string;

/** The params of the RPC method, if any. */
params?: unknown;
}
Loading