From b9939d3904f503f5c1ae6d446ea185ea5d0755fa Mon Sep 17 00:00:00 2001 From: yjin Date: Wed, 1 Jan 2025 01:28:05 +0900 Subject: [PATCH] feat: Set the provider's network. --- .../sdk/src/core/constants/chains.constant.ts | 1 + packages/sdk/src/core/providers/tm2-wallet.ts | 2 +- packages/sdk/src/core/types/wallet.types.ts | 7 ++ .../providers/gno-wallet/gno-social-wallet.ts | 34 +++-- .../src/providers/gno-wallet/gno-wallet.ts | 117 +++++++++++++++--- 5 files changed, 133 insertions(+), 28 deletions(-) diff --git a/packages/sdk/src/core/constants/chains.constant.ts b/packages/sdk/src/core/constants/chains.constant.ts index 2fe60cc..3a48be9 100644 --- a/packages/sdk/src/core/constants/chains.constant.ts +++ b/packages/sdk/src/core/constants/chains.constant.ts @@ -1 +1,2 @@ export const DEFAULT_RPC_URL = 'https://rpc.gno.land:443'; +export const GNO_ADDRESS_PREFIX = 'g'; diff --git a/packages/sdk/src/core/providers/tm2-wallet.ts b/packages/sdk/src/core/providers/tm2-wallet.ts index b50fd2f..55c7a60 100644 --- a/packages/sdk/src/core/providers/tm2-wallet.ts +++ b/packages/sdk/src/core/providers/tm2-wallet.ts @@ -2,7 +2,7 @@ import { Wallet as TM2Wallet } from '@gnolang/tm2-js-client'; import { WalletProvider } from './wallet'; export interface TM2WalletProvider extends WalletProvider { - connect(rpcUrl?: string): Promise; + connect(): Promise; disconnect(): Promise; diff --git a/packages/sdk/src/core/types/wallet.types.ts b/packages/sdk/src/core/types/wallet.types.ts index de21f55..ba9cf7c 100644 --- a/packages/sdk/src/core/types/wallet.types.ts +++ b/packages/sdk/src/core/types/wallet.types.ts @@ -52,6 +52,7 @@ export enum WalletResponseFailureType { UNADDED_NETWORK = 'UNADDED_NETWORK', UNSUPPORTED_TYPE = 'UNSUPPORTED_TYPE', UNEXPECTED_ERROR = 'UNEXPECTED_ERROR', + NOT_INITIALIZED_NETWORK = 'NOT_INITIALIZED_NETWORK', } export enum WalletResponseRejectType { @@ -203,6 +204,12 @@ const WalletFailureMessageInfo: Record< type: WalletResponseFailureType.UNADDED_NETWORK, message: 'The network has not been added on Adena.', }, + NOT_INITIALIZED_NETWORK: { + code: 4001, + status: WalletResponseStatus.FAILURE, + type: WalletResponseFailureType.NOT_INITIALIZED_NETWORK, + message: 'The network has not been initialized on Wallet.', + }, UNSUPPORTED_TYPE: { code: 4005, status: WalletResponseStatus.FAILURE, diff --git a/packages/sdk/src/providers/gno-wallet/gno-social-wallet.ts b/packages/sdk/src/providers/gno-wallet/gno-social-wallet.ts index e569a07..a43e2b1 100644 --- a/packages/sdk/src/providers/gno-wallet/gno-social-wallet.ts +++ b/packages/sdk/src/providers/gno-wallet/gno-social-wallet.ts @@ -4,7 +4,13 @@ import { CommonPrivateKeyProvider } from '@web3auth/base-provider'; import { Web3AuthNoModal } from '@web3auth/no-modal'; import { OpenloginAdapter } from '@web3auth/openlogin-adapter'; -import { SocialCustomConfigure, SocialGoogleConfigure, SocialTwitterConfigure, SocialType } from '../../core'; +import { + NetworkInfo, + SocialCustomConfigure, + SocialGoogleConfigure, + SocialTwitterConfigure, + SocialType, +} from '../../core'; import { hexToUint8Array } from '../../core/utils/encode.utils'; import { GnoWalletProvider } from './gno-wallet'; @@ -12,13 +18,17 @@ export class GnoSocialWalletProvider extends GnoWalletProvider { private web3auth: Web3AuthNoModal; private socialType: SocialType; - constructor(web3auth: Web3AuthNoModal, socialType: SocialType) { - super(); + constructor(web3auth: Web3AuthNoModal, socialType: SocialType, networks?: NetworkInfo[]) { + super(undefined, networks); this.web3auth = web3auth; this.socialType = socialType; } public async connect(): Promise { + if (!this.currentNetwork) { + return false; + } + const initialized = await this.initWeb3Auth(); if (!initialized) { return false; @@ -32,13 +42,17 @@ export class GnoSocialWalletProvider extends GnoWalletProvider { const privateKey = await this.requestPrivateKey(); const privateKeyBytes = hexToUint8Array(privateKey); - const wallet = await GnoWallet.fromPrivateKey(privateKeyBytes); + const wallet = await GnoWallet.fromPrivateKey(privateKeyBytes, { + addressPrefix: this.currentNetwork.addressPrefix, + }); this.wallet = wallet; return this.connectProvider(); } public disconnect = (): Promise => { + this.disconnectProvider(); + return this.web3auth .logout({ cleanup: true }) .then(() => true) @@ -77,7 +91,7 @@ export class GnoSocialWalletProvider extends GnoWalletProvider { return `${privateKey}`; } - public static createGoogle(config: SocialGoogleConfigure) { + public static createGoogle(config: SocialGoogleConfigure, networks?: NetworkInfo[]) { const socialType = SocialType.GOOGLE; const chainConfig: CustomChainConfig = { displayName: 'Gno.land', @@ -114,10 +128,10 @@ export class GnoSocialWalletProvider extends GnoWalletProvider { }, }); web3auth.configureAdapter(openloginAdapter); - return new GnoSocialWalletProvider(web3auth, socialType); + return new GnoSocialWalletProvider(web3auth, socialType, networks); } - public static createTwitter(config: SocialTwitterConfigure) { + public static createTwitter(config: SocialTwitterConfigure, networks?: NetworkInfo[]) { const socialType = SocialType.TWITTER; const chainConfig: CustomChainConfig = { displayName: 'Gno.land', @@ -158,10 +172,10 @@ export class GnoSocialWalletProvider extends GnoWalletProvider { }, }); web3auth.configureAdapter(openloginAdapter); - return new GnoSocialWalletProvider(web3auth, socialType); + return new GnoSocialWalletProvider(web3auth, socialType, networks); } - public static createEmail(config: SocialCustomConfigure) { + public static createEmail(config: SocialCustomConfigure, networks?: NetworkInfo[]) { const socialType = SocialType.EMAIL; const chainConfig: CustomChainConfig = { displayName: 'Gno.land', @@ -202,6 +216,6 @@ export class GnoSocialWalletProvider extends GnoWalletProvider { }, }); web3auth.configureAdapter(openloginAdapter); - return new GnoSocialWalletProvider(web3auth, socialType); + return new GnoSocialWalletProvider(web3auth, socialType, networks); } } diff --git a/packages/sdk/src/providers/gno-wallet/gno-wallet.ts b/packages/sdk/src/providers/gno-wallet/gno-wallet.ts index 6cb7810..48cb30d 100644 --- a/packages/sdk/src/providers/gno-wallet/gno-wallet.ts +++ b/packages/sdk/src/providers/gno-wallet/gno-wallet.ts @@ -7,45 +7,53 @@ import { uint8ArrayToBase64, } from '@gnolang/tm2-js-client'; -import { BroadcastType, WalletResponseFailureType, WalletResponseSuccessType } from '../../core'; +import { BroadcastType, NetworkInfo, WalletResponseFailureType, WalletResponseSuccessType } from '../../core'; import { TM2WalletProvider } from '../../core/providers/tm2-wallet'; import { AddEstablishResponse, + AddNetworkOptions, AddNetworkResponse, BroadcastTransactionOptions, BroadcastTransactionResponse, GetAccountResponse, GetNetworkResponse, IsConnectedResponse, + OnChangeAccountOptions, OnChangeAccountResponse, + OnChangeNetworkOptions, OnChangeNetworkResponse, SignTransactionOptions, SignTransactionResponse, + SwitchNetworkOptions, SwitchNetworkResponse, } from '../../core/types/methods'; import { encodeTransaction } from '../../core/utils/encode.utils'; import { makeResponseMessage } from '../../core/utils/message.utils'; -import { DEFAULT_RPC_URL } from '../../core/constants/chains.constant'; +import { DEFAULT_RPC_URL, GNO_ADDRESS_PREFIX } from '../../core/constants/chains.constant'; export class GnoWalletProvider implements TM2WalletProvider { protected wallet: TM2Wallet | null; protected rpcUrl: string | null; + protected networks: NetworkInfo[]; + protected currentNetwork: NetworkInfo | null; + protected networkCallback: ((chainId: string) => void) | null; - constructor(wallet?: TM2Wallet) { + constructor(wallet?: TM2Wallet, networks?: NetworkInfo[]) { this.wallet = wallet || null; - this.rpcUrl = null; + this.networks = networks || []; + this.currentNetwork = null; } public getWallet(): TM2Wallet | null { return this.wallet; } - async connect(rpcUrl?: string): Promise { - return this.connectProvider(rpcUrl); + async connect(): Promise { + return this.connectProvider(); } async disconnect(): Promise { - return true; + return this.disconnectProvider(); } async isConnected(): Promise { @@ -93,16 +101,66 @@ export class GnoWalletProvider implements TM2WalletProvider { } } + setNetworks(networks: NetworkInfo[]): void { + this.networks = networks; + } + async getNetwork(): Promise { - throw new Error('not supported'); + const connected = this.wallet !== null; + if (!connected) { + return makeResponseMessage(WalletResponseFailureType.NOT_CONNECTED); + } + + if (!this.currentNetwork) { + return makeResponseMessage(WalletResponseFailureType.NOT_INITIALIZED_NETWORK); + } + + return makeResponseMessage(WalletResponseSuccessType.GET_NETWORK_SUCCESS, this.currentNetwork); } - async switchNetwork(): Promise { - throw new Error('not supported'); + async switchNetwork(options: SwitchNetworkOptions): Promise { + const chainId = options.chainId; + if (!chainId) { + return makeResponseMessage(WalletResponseFailureType.INVALID_FORMAT); + } + + const network = this.networks.find((network) => network.chainId === options.chainId); + if (!network) { + return makeResponseMessage(WalletResponseFailureType.UNADDED_NETWORK); + } + + this.setNetwork(network); + + const connected = this.connectProvider(); + if (!connected) { + return makeResponseMessage(WalletResponseFailureType.NOT_CONNECTED); + } + + return makeResponseMessage(WalletResponseSuccessType.SWITCH_NETWORK_SUCCESS); } - async addNetwork(): Promise { - throw new Error('not supported'); + async addNetwork(options: AddNetworkOptions): Promise { + const { chainId, chainName, rpcUrl } = options; + + if (!chainId || !chainName || !rpcUrl) { + return makeResponseMessage(WalletResponseFailureType.INVALID_FORMAT); + } + + if (rpcUrl.match(/\s/g)) { + return makeResponseMessage(WalletResponseFailureType.INVALID_FORMAT); + } + + const network: NetworkInfo = { + chainId, + networkName: chainName, + rpcUrl: rpcUrl.replace(/\/$/, ''), + addressPrefix: GNO_ADDRESS_PREFIX, + indexerUrl: null, + }; + + this.networks = [...this.networks, network]; + + return makeResponseMessage(WalletResponseSuccessType.ADD_NETWORK_SUCCESS); } async signTransaction(options: SignTransactionOptions): Promise { @@ -131,21 +189,46 @@ export class GnoWalletProvider implements TM2WalletProvider { return makeResponseMessage(WalletResponseSuccessType.TRANSACTION_SUCCESS, transactionResult); } - onChangeAccount(): OnChangeAccountResponse { + onChangeAccount(options: OnChangeAccountOptions): OnChangeAccountResponse { throw new Error('not supported'); } - onChangeNetwork(): OnChangeNetworkResponse { - throw new Error('not supported'); + onChangeNetwork(options: OnChangeNetworkOptions): OnChangeNetworkResponse { + this.networkCallback = options.callback; + } + + protected triggerNetworkCallback(chainId: string): void { + if (!this.networkCallback) { + return; + } + + this.networkCallback(chainId); } - protected connectProvider(rpcUrl?: string): boolean { + protected connectProvider(): boolean { if (!this.wallet) { return false; } - const provider = new JSONRPCProvider(rpcUrl || DEFAULT_RPC_URL); + const rpcUrl = this.currentNetwork?.rpcUrl || DEFAULT_RPC_URL; + const provider = new JSONRPCProvider(rpcUrl); this.wallet.connect(provider); return true; } + + protected disconnectProvider(): boolean { + this.networkCallback = null; + this.networks = []; + this.currentNetwork = null; + this.wallet = null; + + return true; + } + + private setNetwork(network: NetworkInfo): void { + this.currentNetwork = network; + + // Trigger network change callback + this.triggerNetworkCallback(this.currentNetwork.chainId); + } }