From 66809dd91e65f60b8955c83a1d92d311d11dfb87 Mon Sep 17 00:00:00 2001 From: Brian Li Date: Tue, 31 Aug 2021 12:38:27 -0700 Subject: [PATCH 01/14] Migrate back to dappKit --- packages/use-contractkit/package.json | 4 +- .../src/connectors/connectors-by-name.ts | 3 +- .../src/connectors/connectors.ts | 48 +++++++ .../src/dappkit-wallet/dappkit.ts | 128 ++++++++++++++++++ .../src/dappkit-wallet/index.ts | 122 +++++++++++++++++ .../src/dappkit-wallet/linking.ts | 31 +++++ .../use-contractkit/src/screens/valora.tsx | 70 ++++++---- 7 files changed, 373 insertions(+), 33 deletions(-) create mode 100644 packages/use-contractkit/src/dappkit-wallet/dappkit.ts create mode 100644 packages/use-contractkit/src/dappkit-wallet/index.ts create mode 100644 packages/use-contractkit/src/dappkit-wallet/linking.ts diff --git a/packages/use-contractkit/package.json b/packages/use-contractkit/package.json index 65580e62..69c04eb8 100644 --- a/packages/use-contractkit/package.json +++ b/packages/use-contractkit/package.json @@ -1,6 +1,6 @@ { - "name": "@celo-tools/use-contractkit", - "version": "1.2.0", + "name": "@poofcash/use-contractkit", + "version": "1.0.0", "private": false, "scripts": { "build": "tsc -b && yarn run build-styles", diff --git a/packages/use-contractkit/src/connectors/connectors-by-name.ts b/packages/use-contractkit/src/connectors/connectors-by-name.ts index 6a29a43e..ee1b0fcc 100644 --- a/packages/use-contractkit/src/connectors/connectors-by-name.ts +++ b/packages/use-contractkit/src/connectors/connectors-by-name.ts @@ -7,6 +7,7 @@ import { MetaMaskConnector, PrivateKeyConnector, UnauthenticatedConnector, + ValoraConnector, WalletConnectConnector, } from './connectors'; @@ -23,7 +24,7 @@ export const CONNECTOR_TYPES: { [WalletTypes.MetaMask]: MetaMaskConnector, [WalletTypes.PrivateKey]: PrivateKeyConnector, [WalletTypes.Unauthenticated]: UnauthenticatedConnector, - [WalletTypes.Valora]: WalletConnectConnector, + [WalletTypes.Valora]: ValoraConnector, [WalletTypes.WalletConnect]: WalletConnectConnector, [WalletTypes.CeloDance]: WalletConnectConnector, [WalletTypes.CeloTerminal]: WalletConnectConnector, diff --git a/packages/use-contractkit/src/connectors/connectors.ts b/packages/use-contractkit/src/connectors/connectors.ts index ad0c5d93..60dd1d43 100644 --- a/packages/use-contractkit/src/connectors/connectors.ts +++ b/packages/use-contractkit/src/connectors/connectors.ts @@ -6,6 +6,7 @@ import { } from '@celo/wallet-walletconnect'; import { BigNumber } from 'bignumber.js'; +import { dappKitConfigKey, DappKitWallet } from '../dappkit-wallet'; import { localStorageKeys, WalletTypes } from '../constants'; import { ChainId, Connector, Network } from '../types'; import { clearPreviousConfig } from '../utils/helpers'; @@ -356,3 +357,50 @@ export class WalletConnectConnector implements Connector { return wallet.close(); } } + +export class ValoraConnector implements Connector { + public initialised = false; + public type = WalletTypes.Valora; + public kit: ContractKit; + public wallet: DappKitWallet; + + get account(): string | null { + const storedConfig = localStorage.getItem(dappKitConfigKey); + let dappKitConfig = storedConfig ? JSON.parse(storedConfig) : null; + if (dappKitConfig) { + return dappKitConfig.phoneNumber; + } + return null; + } + + constructor(private network: Network, dappName: string) { + localStorage.setItem( + localStorageKeys.lastUsedWalletType, + WalletTypes.Valora + ); + localStorage.setItem( + localStorageKeys.lastUsedWalletArguments, + JSON.stringify([dappName]) + ); + + this.wallet = new DappKitWallet(dappName); + this.kit = newKit(network.rpcUrl, this.wallet); + this.wallet.setKit(this.kit); + } + + async initialise(): Promise { + await this.wallet.init(); + + this.kit = newKit(this.network.rpcUrl, this.wallet); + this.kit.defaultAccount = this.wallet.getAccounts()[0]; + this.wallet.setKit(this.kit); + this.initialised = true; + + return this; + } + + close(): void { + localStorage.removeItem(dappKitConfigKey); + return; + } +} diff --git a/packages/use-contractkit/src/dappkit-wallet/dappkit.ts b/packages/use-contractkit/src/dappkit-wallet/dappkit.ts new file mode 100644 index 00000000..423b3c70 --- /dev/null +++ b/packages/use-contractkit/src/dappkit-wallet/dappkit.ts @@ -0,0 +1,128 @@ +import { CeloTx } from '@celo/connect'; +import { ContractKit } from '@celo/contractkit'; +import { + AccountAuthRequest, + AccountAuthResponseSuccess, + DappKitRequestMeta, + DappKitRequestTypes, + DappKitResponseStatus, + parseDappkitResponseDeeplink, + serializeDappKitRequestDeeplink, + SignTxRequest, + SignTxResponseSuccess, + TxToSignParam, +} from '@celo/utils'; + +import Linking from './linking'; + +export { + AccountAuthRequest, + DappKitRequestMeta, + serializeDappKitRequestDeeplink, + SignTxRequest, +} from '@celo/utils'; + +export const valoraLocalStorageKey = 'use-contractkit/dappkit'; +// hack to get around deeplinking issue where new tabs are opened +// and the url hash state is not respected (Note this implementation +// of dappkit doesn't use URL hashes to always force the newtab experience). +const checkUrlValora = (onTrue?: () => any) => { + if (typeof window !== 'undefined') { + const nonHashUrl = window.location.href.replace('/#', ''); + const params = new URL(nonHashUrl).searchParams; + if (params.get('type') && params.get('requestId')) { + localStorage.setItem(valoraLocalStorageKey, nonHashUrl); + onTrue && onTrue(); + } + } +}; + +if (typeof window !== 'undefined') { + checkUrlValora(window.close); +} + +function clearParams() { + const whereQuery = window.location.href.indexOf('?'); + if (whereQuery) { + window.location.href = window.location.href.substring(0, whereQuery); + } +} + +async function waitForResponse() { + for (;;) { + let value = localStorage.getItem(valoraLocalStorageKey); + if (!value) { + checkUrlValora(clearParams); + value = localStorage.getItem(valoraLocalStorageKey); + } + if (value) { + return value; + } + await new Promise((resolve) => setTimeout(resolve, 1000)); + } +} + +export async function waitForAccountAuth( + requestId: string +): Promise { + const url = await waitForResponse(); + const dappKitResponse = parseDappkitResponseDeeplink(url); + if ( + requestId === dappKitResponse.requestId && + dappKitResponse.type === DappKitRequestTypes.ACCOUNT_ADDRESS && + dappKitResponse.status === DappKitResponseStatus.SUCCESS + ) { + return dappKitResponse; + } + + throw new Error('Unable to parse Valora response'); +} + +export async function waitForSignedTxs( + requestId: string +): Promise { + const url = await waitForResponse(); + + const dappKitResponse = parseDappkitResponseDeeplink(url); + if ( + requestId === dappKitResponse.requestId && + dappKitResponse.type === DappKitRequestTypes.SIGN_TX && + dappKitResponse.status === DappKitResponseStatus.SUCCESS + ) { + return dappKitResponse; + } + + console.warn('Unable to parse url', url); + throw new Error('Unable to parse Valora response'); +} + +export function requestAccountAddress(meta: DappKitRequestMeta): void { + localStorage.removeItem(valoraLocalStorageKey); + + const deepLink = serializeDappKitRequestDeeplink(AccountAuthRequest(meta)); + Linking.openURL(deepLink); +} + +export async function requestTxSig( + kit: ContractKit, + txParams: CeloTx[], + meta: DappKitRequestMeta +): Promise { + localStorage.removeItem(valoraLocalStorageKey); + + const baseNonce = await kit.connection.nonce(txParams[0]?.from as string); + const txs = txParams.map((txParam: CeloTx, index: number) => { + const value = txParam.value === undefined ? '0' : txParam.value; + return { + txData: txParam.data, + estimatedGas: txParam.gas ?? 150000, + nonce: baseNonce + index, + feeCurrencyAddress: undefined, + value, + ...txParam, + } as unknown as TxToSignParam; + }); + + const request = SignTxRequest(txs, meta); + Linking.openURL(serializeDappKitRequestDeeplink(request)); +} diff --git a/packages/use-contractkit/src/dappkit-wallet/index.ts b/packages/use-contractkit/src/dappkit-wallet/index.ts new file mode 100644 index 00000000..75a500b2 --- /dev/null +++ b/packages/use-contractkit/src/dappkit-wallet/index.ts @@ -0,0 +1,122 @@ +import { CeloTx, EncodedTransaction, Signer } from '@celo/connect'; +import { ContractKit } from '@celo/contractkit'; +import { EIP712TypedData } from '@celo/utils/lib/sign-typed-data-utils'; +import { RemoteWallet } from '@celo/wallet-remote'; + +import { + requestAccountAddress, + requestTxSig, + waitForAccountAuth, + waitForSignedTxs, +} from './dappkit'; + +export const dappKitConfigKey = 'use-contractkit/dappkitconfig'; + +export class DappKitSigner implements Signer { + constructor(protected account: string) {} + + // eslint-disable-next-line @typescript-eslint/require-await + async signTransaction(): Promise<{ v: number; r: Buffer; s: Buffer }> { + throw new Error('signTransaction unimplemented; use signRawTransaction'); + } + + // eslint-disable-next-line @typescript-eslint/require-await + async signTypedData( + _: EIP712TypedData + ): Promise<{ v: number; r: Buffer; s: Buffer }> { + throw new Error('signTypedData() not supported by DappKit wallet'); + } + + // eslint-disable-next-line @typescript-eslint/require-await + async signPersonalMessage( + _data: string + ): Promise<{ v: number; r: Buffer; s: Buffer }> { + throw new Error('signPersonalMessage() not supported by DappKit wallet'); + } + + getNativeKey = (): string => this.account; + + // eslint-disable-next-line @typescript-eslint/require-await + async decrypt(_ciphertext: Buffer): Promise { + throw new Error('decrypt() not supported by DappKit wallet'); + } + + computeSharedSecret(_publicKey: string): Promise { + throw new Error('computeSharedSecret() not supported by DappKit wallet'); + } +} + +const randomString = () => (Math.random() * 100).toString().slice(0, 6); + +export class DappKitWallet extends RemoteWallet { + private kit?: ContractKit; + + constructor(protected dappName: string) { + super(); + } + + async loadAccountSigners(): Promise> { + const addressToSigner = new Map(); + + const storedConfig = localStorage.getItem(dappKitConfigKey); + let dappKitConfig = storedConfig ? JSON.parse(storedConfig) : null; + if (!dappKitConfig) { + const requestId = `login-${randomString()}`; + requestAccountAddress({ + requestId, + dappName: this.dappName, + callback: window.location.href, + }); + const dappkitResponse = await waitForAccountAuth(requestId); + dappKitConfig = { + address: dappkitResponse.address, + phoneNumber: dappkitResponse.phoneNumber, + }; + localStorage.setItem(dappKitConfigKey, JSON.stringify(dappKitConfig)); + } + + addressToSigner.set( + dappKitConfig.address, + new DappKitSigner(dappKitConfig.address) + ); + return addressToSigner; + } + + setKit(kit: ContractKit): void { + this.kit = kit; + } + + /** + * Override hasAccount for the DappKit wallet as we + * want to always send users to Valora + */ + hasAccount = (): boolean => true; + + /** + * Gets the signer based on the 'from' field in the tx body + * @param txParams Transaction to sign + * @dev overrides WalletBase.signTransaction + */ + override async signTransaction( + txParams: CeloTx + ): Promise { + if (!this.kit) { + throw new Error('Must call setKit before using dappKit wallet'); + } + + const requestId = `signTransaction-${randomString()}`; + await requestTxSig(this.kit, [txParams], { + requestId, + dappName: this.dappName, + callback: window.location.href, + }); + + const dappkitResponse = await waitForSignedTxs(requestId); + const raw = dappkitResponse.rawTxs[0]; + if (!raw) { + throw new Error('Raw TX not present'); + } + + return { raw, tx: undefined as unknown as EncodedTransaction['tx'] }; + } +} diff --git a/packages/use-contractkit/src/dappkit-wallet/linking.ts b/packages/use-contractkit/src/dappkit-wallet/linking.ts new file mode 100644 index 00000000..2a37b97d --- /dev/null +++ b/packages/use-contractkit/src/dappkit-wallet/linking.ts @@ -0,0 +1,31 @@ +import EventEmitter from 'events'; + +class Linking { + protected emitter: EventEmitter; + + constructor() { + this.emitter = new EventEmitter(); + } + + emit(event: string, value: unknown) { + this.emitter.emit(event, value); + } + + addEventListener(event: string, callback: Parameters[1]) { + this.emitter.on(event, callback); + } + + removeEventListener( + event: string, + callback: Parameters[1] + ) { + this.emitter.off(event, callback); + } + + openURL(url: string) { + window.location.href = url; + } +} + +const linking = new Linking(); +export default linking; diff --git a/packages/use-contractkit/src/screens/valora.tsx b/packages/use-contractkit/src/screens/valora.tsx index 6e860e25..9e98126a 100644 --- a/packages/use-contractkit/src/screens/valora.tsx +++ b/packages/use-contractkit/src/screens/valora.tsx @@ -1,45 +1,55 @@ -import QrCode from 'qrcode.react'; -import React from 'react'; -import { isMobile } from 'react-device-detect'; +import React, { useCallback, useEffect } from 'react'; import Loader from 'react-loader-spinner'; +import { AddCeloNetworkButton } from '../components/AddCeloNetworkButton'; +import { UnsupportedChainIdError, ValoraConnector } from '../connectors'; -import { useWalletConnectConnector } from '../connectors/useWalletConnectConnector'; import { Connector } from '../types'; +import { useContractKitInternal } from '../use-contractkit'; interface Props { onSubmit: (connector: Connector) => void; } -const getDeepLink = (uri: string) => { - return `celo://wallet/wc?uri=${uri}`; -}; - export const Valora: React.FC = ({ onSubmit }: Props) => { - const uri = useWalletConnectConnector(onSubmit, isMobile, getDeepLink); + const { + network, + initConnector, + initError: error, + dapp, + } = useContractKitInternal(); - return ( -
-

- Valora -

-
- {`Opening Valora Wallet. If it doesn't open, you can scan this QR code.`} -
+ const initialiseConnection = useCallback(async () => { + const connector = new ValoraConnector(network, dapp.name); + try { + await initConnector(connector); + onSubmit(connector); + } catch (e) { + console.error(e); + } + }, [initConnector, network, onSubmit, dapp.name]); -
- {uri ? ( - - ) : ( -
- -
- )} + useEffect(() => { + void initialiseConnection(); + }, [initialiseConnection]); + + if (error?.name === UnsupportedChainIdError.NAME) { + return ( +
+

+ Please connect to the Celo network to continue. +

+
+ ); + } + + return ( +
+ {error ? ( +

{error.message}

+ ) : ( + + )}
); }; From 646e0e61efd78c0a57268408a1961b54800bfa7f Mon Sep 17 00:00:00 2001 From: Brian Li Date: Tue, 31 Aug 2021 12:42:01 -0700 Subject: [PATCH 02/14] Prioritize CEW and deprioritize CW --- packages/use-contractkit/src/constants.tsx | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/use-contractkit/src/constants.tsx b/packages/use-contractkit/src/constants.tsx index 7eff3af9..0138ee18 100644 --- a/packages/use-contractkit/src/constants.tsx +++ b/packages/use-contractkit/src/constants.tsx @@ -46,6 +46,16 @@ export const PROVIDERS: { listPriority: () => 0, installURL: 'https://valoraapp.com/', }, + [SupportedProviders.CeloExtensionWallet]: { + name: 'Celo Extension Wallet', + description: 'Use a wallet from the the Celo chrome extension', + icon: CHROME_EXTENSION_STORE, + canConnect: () => !!window.celo, + showInList: () => !isMobile, + listPriority: () => 0, + installURL: + 'https://chrome.google.com/webstore/detail/celoextensionwallet/kkilomkmpmkbdnfelcpgckmpcaemjcdh/related', + }, [SupportedProviders.WalletConnect]: { name: 'WalletConnect', description: 'Scan a QR code to connect your wallet', @@ -68,7 +78,7 @@ export const PROVIDERS: { icon: CELO, canConnect: () => true, showInList: () => true, - listPriority: () => (!isMobile ? 0 : 1), + listPriority: () => 1, }, [SupportedProviders.CeloTerminal]: { name: 'Celo Terminal', @@ -104,16 +114,6 @@ export const PROVIDERS: { listPriority: () => 0, installURL: 'https://metamask.app.link/', }, - [SupportedProviders.CeloExtensionWallet]: { - name: 'Celo Extension Wallet', - description: 'Use a wallet from the the Celo chrome extension', - icon: CHROME_EXTENSION_STORE, - canConnect: () => !!window.celo, - showInList: () => !isMobile, - listPriority: () => 1, - installURL: - 'https://chrome.google.com/webstore/detail/celoextensionwallet/kkilomkmpmkbdnfelcpgckmpcaemjcdh/related', - }, [SupportedProviders.Injected]: { name: 'Ethereum Web3', description: 'Connect any Ethereum wallet to Celo', From a6ea7247cbfcb2215604e8054c05f3a394bccb8b Mon Sep 17 00:00:00 2001 From: Brian Li Date: Tue, 31 Aug 2021 12:51:12 -0700 Subject: [PATCH 03/14] v1.0.1 --- packages/use-contractkit/package.json | 2 +- .../src/components/ProviderSelect.tsx | 19 ++++++++++++++++--- packages/use-contractkit/src/constants.tsx | 6 ++++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/packages/use-contractkit/package.json b/packages/use-contractkit/package.json index 69c04eb8..057d4535 100644 --- a/packages/use-contractkit/package.json +++ b/packages/use-contractkit/package.json @@ -1,6 +1,6 @@ { "name": "@poofcash/use-contractkit", - "version": "1.0.0", + "version": "1.0.1", "private": false, "scripts": { "build": "tsc -b && yarn run build-styles", diff --git a/packages/use-contractkit/src/components/ProviderSelect.tsx b/packages/use-contractkit/src/components/ProviderSelect.tsx index 325190ec..23f188ca 100644 --- a/packages/use-contractkit/src/components/ProviderSelect.tsx +++ b/packages/use-contractkit/src/components/ProviderSelect.tsx @@ -1,4 +1,6 @@ import React from 'react'; +import { isMobile } from 'react-device-detect'; +import { SupportedProviders } from '../constants'; import { Provider } from '../types'; @@ -11,6 +13,19 @@ export const ProviderSelect: React.FC = ({ provider, onClick, }: Props) => { + let title = ( +
+ {provider.canConnect() ? provider.name : `Install ${provider.name}`} +
+ ); + if (isMobile && provider.name === SupportedProviders.MetaMask) { + title = ( +
+ {provider.canConnect() ? provider.name : `Open ${provider.name}`} +
+ ); + } + return (
-
- {provider.canConnect() ? provider.name : `Install ${provider.name}`} -
+ {title}
{provider.description}
diff --git a/packages/use-contractkit/src/constants.tsx b/packages/use-contractkit/src/constants.tsx index 0138ee18..2f45f371 100644 --- a/packages/use-contractkit/src/constants.tsx +++ b/packages/use-contractkit/src/constants.tsx @@ -91,7 +91,9 @@ export const PROVIDERS: { }, [SupportedProviders.MetaMask]: { name: 'MetaMask', - description: ( + description: isMobile ? ( + 'Open this app in your Metamask app' + ) : ( <> Use the Metamask browser extension. Celo support is limited.{' '} !!window.ethereum?.isMetaMask, - showInList: () => !isMobile, + showInList: () => true, listPriority: () => 0, installURL: 'https://metamask.app.link/', }, From e76cf47f7530b58af011b2d46fa950aa19b31b42 Mon Sep 17 00:00:00 2001 From: Brian Li Date: Tue, 7 Sep 2021 18:05:07 -0700 Subject: [PATCH 04/14] Fix Valora for desktop --- packages/use-contractkit/package.json | 2 ++ packages/use-contractkit/src/connectors/connectors-by-name.ts | 3 ++- packages/use-contractkit/src/screens/index.ts | 3 ++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/use-contractkit/package.json b/packages/use-contractkit/package.json index 057d4535..7cab2f7a 100644 --- a/packages/use-contractkit/package.json +++ b/packages/use-contractkit/package.json @@ -19,6 +19,7 @@ "readme": "../../readme.md", "license": "MIT", "dependencies": { + "@celo-tools/celo-ethers-wrapper": "^0.0.5", "@celo/contractkit": "1.2.4", "@celo/utils": "1.2.4", "@celo/wallet-base": "1.2.4", @@ -34,6 +35,7 @@ "@walletconnect/client": "2.0.0-beta.0", "@walletconnect/types": "2.0.0-beta.0", "autoprefixer": "^10.2.6", + "ethers": "^5.4.6", "postcss": "^8.3.5", "qrcode.react": "^1.0.1", "react-device-detect": "^1.17.0", diff --git a/packages/use-contractkit/src/connectors/connectors-by-name.ts b/packages/use-contractkit/src/connectors/connectors-by-name.ts index ee1b0fcc..70a003fb 100644 --- a/packages/use-contractkit/src/connectors/connectors-by-name.ts +++ b/packages/use-contractkit/src/connectors/connectors-by-name.ts @@ -1,3 +1,4 @@ +import { isMobile } from 'react-device-detect'; import { WalletTypes } from '../constants'; import { Connector, Network } from '../types'; import { @@ -24,7 +25,7 @@ export const CONNECTOR_TYPES: { [WalletTypes.MetaMask]: MetaMaskConnector, [WalletTypes.PrivateKey]: PrivateKeyConnector, [WalletTypes.Unauthenticated]: UnauthenticatedConnector, - [WalletTypes.Valora]: ValoraConnector, + [WalletTypes.Valora]: isMobile ? ValoraConnector : WalletConnectConnector, [WalletTypes.WalletConnect]: WalletConnectConnector, [WalletTypes.CeloDance]: WalletConnectConnector, [WalletTypes.CeloTerminal]: WalletConnectConnector, diff --git a/packages/use-contractkit/src/screens/index.ts b/packages/use-contractkit/src/screens/index.ts index 31b75fae..1373f023 100644 --- a/packages/use-contractkit/src/screens/index.ts +++ b/packages/use-contractkit/src/screens/index.ts @@ -1,4 +1,5 @@ import React from 'react'; +import { isMobile } from 'react-device-detect'; import { SupportedProviders } from '../constants'; import { Connector } from '../types'; @@ -14,7 +15,7 @@ import { WalletConnect } from './wallet-connect'; export const defaultScreens: { [P in SupportedProviders]: React.FC; } = { - [SupportedProviders.Valora]: Valora, + [SupportedProviders.Valora]: isMobile ? Valora : WalletConnect, [SupportedProviders.MetaMask]: MetaMaskWallet, [SupportedProviders.WalletConnect]: WalletConnect, [SupportedProviders.Ledger]: Ledger, From 598f0abd6b01a7f043317558ee42c3043d0aae9b Mon Sep 17 00:00:00 2001 From: Brian Li Date: Tue, 7 Sep 2021 18:06:53 -0700 Subject: [PATCH 05/14] Update to v1.0.2 --- packages/use-contractkit/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/use-contractkit/package.json b/packages/use-contractkit/package.json index 7cab2f7a..4d19616e 100644 --- a/packages/use-contractkit/package.json +++ b/packages/use-contractkit/package.json @@ -1,6 +1,6 @@ { "name": "@poofcash/use-contractkit", - "version": "1.0.1", + "version": "1.0.2", "private": false, "scripts": { "build": "tsc -b && yarn run build-styles", From 905478102605fe38081d2857e216ef8d57ec8de9 Mon Sep 17 00:00:00 2001 From: Brian Li Date: Tue, 7 Sep 2021 18:20:38 -0700 Subject: [PATCH 06/14] v1.0.3 --- packages/use-contractkit/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/use-contractkit/package.json b/packages/use-contractkit/package.json index 4d19616e..6d2a20e0 100644 --- a/packages/use-contractkit/package.json +++ b/packages/use-contractkit/package.json @@ -1,6 +1,6 @@ { "name": "@poofcash/use-contractkit", - "version": "1.0.2", + "version": "1.0.3", "private": false, "scripts": { "build": "tsc -b && yarn run build-styles", From 1780f91099e5404d1ae331f9c4ec352df571a765 Mon Sep 17 00:00:00 2001 From: Brian Li Date: Tue, 21 Sep 2021 09:40:51 -0700 Subject: [PATCH 07/14] Fix injected connector showing up --- .../src/connectors/connectors.ts | 4 +--- packages/use-contractkit/src/constants.tsx | 20 ++++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/use-contractkit/src/connectors/connectors.ts b/packages/use-contractkit/src/connectors/connectors.ts index 60dd1d43..a2859cba 100644 --- a/packages/use-contractkit/src/connectors/connectors.ts +++ b/packages/use-contractkit/src/connectors/connectors.ts @@ -156,9 +156,7 @@ export class InjectedConnector implements Connector { if (!ethereum) { throw new Error('Ethereum wallet not installed'); } - this.type = ethereum.isMetaMask - ? WalletTypes.MetaMask - : WalletTypes.Injected; + this.type = WalletTypes.Injected; const web3 = new Web3(ethereum); void (await ethereum.request({ method: 'eth_requestAccounts' })); diff --git a/packages/use-contractkit/src/constants.tsx b/packages/use-contractkit/src/constants.tsx index 2f45f371..0baaed5f 100644 --- a/packages/use-contractkit/src/constants.tsx +++ b/packages/use-contractkit/src/constants.tsx @@ -25,7 +25,7 @@ export enum SupportedProviders { CeloTerminal = 'Celo Terminal', CeloWallet = 'Celo Wallet', CeloDance = 'CeloDance', - Injected = 'Injected', + Injected = 'Ethereum Web3', Ledger = 'Ledger', MetaMask = 'MetaMask', PrivateKey = 'Private key', @@ -89,6 +89,16 @@ export const PROVIDERS: { showInList: () => !isMobile, listPriority: () => 1, }, + [SupportedProviders.Injected]: { + name: 'Ethereum Web3', + description: 'Connect any Ethereum wallet to Celo', + icon: ETHEREUM, + canConnect: () => !!window.ethereum, + showInList: () => !!window.ethereum, + // Prioritize if window.ethereum is present but MetaMask is not + listPriority: () => + window.ethereum && !window.ethereum?.isMetaMask ? 0 : 1, + }, [SupportedProviders.MetaMask]: { name: 'MetaMask', description: isMobile ? ( @@ -116,14 +126,6 @@ export const PROVIDERS: { listPriority: () => 0, installURL: 'https://metamask.app.link/', }, - [SupportedProviders.Injected]: { - name: 'Ethereum Web3', - description: 'Connect any Ethereum wallet to Celo', - icon: ETHEREUM, - canConnect: () => !!window.ethereum, - showInList: () => !!window.ethereum && !window.ethereum.isMetaMask, - listPriority: () => 1, - }, [SupportedProviders.PrivateKey]: { name: 'Private Key', description: From 1541bf19f3cce70698db289ba10841ecd5b65e9f Mon Sep 17 00:00:00 2001 From: Brian Li Date: Tue, 21 Sep 2021 09:47:51 -0700 Subject: [PATCH 08/14] v1.0.4 --- packages/use-contractkit/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/use-contractkit/package.json b/packages/use-contractkit/package.json index 6d2a20e0..fbb4641e 100644 --- a/packages/use-contractkit/package.json +++ b/packages/use-contractkit/package.json @@ -1,6 +1,6 @@ { "name": "@poofcash/use-contractkit", - "version": "1.0.3", + "version": "1.0.4", "private": false, "scripts": { "build": "tsc -b && yarn run build-styles", From 502e08e42654f367b6929e76d15bae0bee72ae75 Mon Sep 17 00:00:00 2001 From: Brian Li Date: Thu, 23 Sep 2021 11:00:45 -0700 Subject: [PATCH 09/14] v1.0.5 --- packages/use-contractkit/package.json | 2 +- .../src/components/ProviderSelect.tsx | 8 +++- packages/use-contractkit/src/constants.tsx | 41 ++++++++++++++----- packages/use-contractkit/src/global.d.ts | 1 + packages/use-contractkit/src/screens/index.ts | 1 + packages/use-contractkit/src/walletIcons.tsx | 33 +++++++++++++++ 6 files changed, 73 insertions(+), 13 deletions(-) diff --git a/packages/use-contractkit/package.json b/packages/use-contractkit/package.json index fbb4641e..0b016ca0 100644 --- a/packages/use-contractkit/package.json +++ b/packages/use-contractkit/package.json @@ -1,6 +1,6 @@ { "name": "@poofcash/use-contractkit", - "version": "1.0.4", + "version": "1.0.5", "private": false, "scripts": { "build": "tsc -b && yarn run build-styles", diff --git a/packages/use-contractkit/src/components/ProviderSelect.tsx b/packages/use-contractkit/src/components/ProviderSelect.tsx index 23f188ca..7c77b4a9 100644 --- a/packages/use-contractkit/src/components/ProviderSelect.tsx +++ b/packages/use-contractkit/src/components/ProviderSelect.tsx @@ -18,7 +18,13 @@ export const ProviderSelect: React.FC = ({ {provider.canConnect() ? provider.name : `Install ${provider.name}`}
); - if (isMobile && provider.name === SupportedProviders.MetaMask) { + if ( + isMobile && + [ + SupportedProviders.MetaMask.toString(), + SupportedProviders.imToken.toString(), + ].includes(provider.name) + ) { title = (
{provider.canConnect() ? provider.name : `Open ${provider.name}`} diff --git a/packages/use-contractkit/src/constants.tsx b/packages/use-contractkit/src/constants.tsx index 0baaed5f..7232c759 100644 --- a/packages/use-contractkit/src/constants.tsx +++ b/packages/use-contractkit/src/constants.tsx @@ -6,6 +6,7 @@ import { CELO_DANCE, CHROME_EXTENSION_STORE, ETHEREUM, + IMTOKEN, LEDGER, METAMASK, PRIVATE_KEY, @@ -28,6 +29,7 @@ export enum SupportedProviders { Injected = 'Ethereum Web3', Ledger = 'Ledger', MetaMask = 'MetaMask', + imToken = 'imToken', PrivateKey = 'Private key', Valora = 'Valora', WalletConnect = 'WalletConnect', @@ -89,20 +91,10 @@ export const PROVIDERS: { showInList: () => !isMobile, listPriority: () => 1, }, - [SupportedProviders.Injected]: { - name: 'Ethereum Web3', - description: 'Connect any Ethereum wallet to Celo', - icon: ETHEREUM, - canConnect: () => !!window.ethereum, - showInList: () => !!window.ethereum, - // Prioritize if window.ethereum is present but MetaMask is not - listPriority: () => - window.ethereum && !window.ethereum?.isMetaMask ? 0 : 1, - }, [SupportedProviders.MetaMask]: { name: 'MetaMask', description: isMobile ? ( - 'Open this app in your Metamask app' + 'Open Ubeswap in your Metamask app' ) : ( <> Use the Metamask browser extension. Celo support is limited.{' '} @@ -126,6 +118,33 @@ export const PROVIDERS: { listPriority: () => 0, installURL: 'https://metamask.app.link/', }, + [SupportedProviders.imToken]: { + name: 'imToken', + description: window.ethereum?.isImToken ? ( + 'Open Ubeswap in your imToken app' + ) : ( + <>Connect with imToken + ), + icon: IMTOKEN, + canConnect: () => !!window.ethereum?.isImToken, + showInList: () => isMobile, + listPriority: () => (isMobile ? 0 : 1), + installURL: 'https://token.im/download', + }, + [SupportedProviders.Injected]: { + name: 'Ethereum Web3', + description: 'Connect any Ethereum wallet to Celo', + icon: ETHEREUM, + canConnect: () => !!window.ethereum, + showInList: () => !!window.ethereum, + // Prioritize if window.ethereum is present but MetaMask is not + listPriority: () => + window.ethereum && + !window.ethereum?.isMetaMask && + !window.ethereum?.isImToken + ? 0 + : 1, + }, [SupportedProviders.PrivateKey]: { name: 'Private Key', description: diff --git a/packages/use-contractkit/src/global.d.ts b/packages/use-contractkit/src/global.d.ts index 34855757..e3265cec 100644 --- a/packages/use-contractkit/src/global.d.ts +++ b/packages/use-contractkit/src/global.d.ts @@ -16,6 +16,7 @@ declare global { interface Ethereum extends Exclude { on: AddEthereumEventListener; isMetaMask?: boolean; + isImToken?: boolean; request: EthereumRequest; enable: () => Promise; } diff --git a/packages/use-contractkit/src/screens/index.ts b/packages/use-contractkit/src/screens/index.ts index 1373f023..1e83e359 100644 --- a/packages/use-contractkit/src/screens/index.ts +++ b/packages/use-contractkit/src/screens/index.ts @@ -17,6 +17,7 @@ export const defaultScreens: { } = { [SupportedProviders.Valora]: isMobile ? Valora : WalletConnect, [SupportedProviders.MetaMask]: MetaMaskWallet, + [SupportedProviders.imToken]: MetaMaskWallet, [SupportedProviders.WalletConnect]: WalletConnect, [SupportedProviders.Ledger]: Ledger, [SupportedProviders.CeloWallet]: CeloWallet, diff --git a/packages/use-contractkit/src/walletIcons.tsx b/packages/use-contractkit/src/walletIcons.tsx index 7c34bfb8..76762bad 100644 --- a/packages/use-contractkit/src/walletIcons.tsx +++ b/packages/use-contractkit/src/walletIcons.tsx @@ -523,3 +523,36 @@ export const CELO_DANCE: React.FC> = (props) => ( ); + +export const IMTOKEN: React.FC> = (props) => ( + + + + + + + + + + + + + + +); From b9c7f2a7bc2632b716799f32422b01805cd2b98b Mon Sep 17 00:00:00 2001 From: Brian Li Date: Thu, 23 Sep 2021 11:21:37 -0700 Subject: [PATCH 10/14] v1.0.6 --- packages/use-contractkit/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/use-contractkit/package.json b/packages/use-contractkit/package.json index 0b016ca0..ebbdf8b3 100644 --- a/packages/use-contractkit/package.json +++ b/packages/use-contractkit/package.json @@ -1,6 +1,6 @@ { "name": "@poofcash/use-contractkit", - "version": "1.0.5", + "version": "1.0.6", "private": false, "scripts": { "build": "tsc -b && yarn run build-styles", From 20d2097d41489fa7d436f198456365db3e55d219 Mon Sep 17 00:00:00 2001 From: Brian Li Date: Sun, 26 Sep 2021 17:46:42 -0700 Subject: [PATCH 11/14] v1.0.7-beta --- packages/use-contractkit/package.json | 2 +- .../src/components/AddCeloNetworkButton.tsx | 26 ++++++++++-- .../connectors/useWalletConnectConnector.ts | 4 +- packages/use-contractkit/src/constants.tsx | 40 ++++++++++++++++--- .../src/contract-kit-provider.tsx | 6 +-- packages/use-contractkit/src/types.ts | 6 ++- packages/use-contractkit/src/utils/helpers.ts | 6 +-- 7 files changed, 70 insertions(+), 20 deletions(-) diff --git a/packages/use-contractkit/package.json b/packages/use-contractkit/package.json index ebbdf8b3..c117e963 100644 --- a/packages/use-contractkit/package.json +++ b/packages/use-contractkit/package.json @@ -1,6 +1,6 @@ { "name": "@poofcash/use-contractkit", - "version": "1.0.6", + "version": "1.0.7-beta", "private": false, "scripts": { "build": "tsc -b && yarn run build-styles", diff --git a/packages/use-contractkit/src/components/AddCeloNetworkButton.tsx b/packages/use-contractkit/src/components/AddCeloNetworkButton.tsx index a7f14094..a2f91f31 100644 --- a/packages/use-contractkit/src/components/AddCeloNetworkButton.tsx +++ b/packages/use-contractkit/src/components/AddCeloNetworkButton.tsx @@ -1,6 +1,12 @@ import React from 'react'; -import { Alfajores, Baklava, Mainnet } from '../constants'; +import { + Alfajores, + Baklava, + CeloMainnet, + EthereumMainnet, + Kovan, +} from '../constants'; import { ChainId, Network } from '../types'; const CELO_PARAMS = { @@ -26,10 +32,22 @@ const BAKLAVA_PARAMS = { }, }; +const ETHEREUM_PARAMS = { + chainName: 'Ethereum', + nativeCurrency: { name: 'Ethereum', symbol: 'ETH', decimals: 18 as const }, +}; + +const KOVAN_PARAMS = { + chainName: 'Kovan', + nativeCurrency: { name: 'Ethereum', symbol: 'ETH', decimals: 18 as const }, +}; + const params: { [chain in ChainId]: typeof CELO_PARAMS } = { - [ChainId.Mainnet]: CELO_PARAMS, + [ChainId.CeloMainnet]: CELO_PARAMS, [ChainId.Alfajores]: ALFAJORES_PARAMS, [ChainId.Baklava]: BAKLAVA_PARAMS, + [ChainId.EthereumMainnet]: ETHEREUM_PARAMS, + [ChainId.Kovan]: KOVAN_PARAMS, }; interface AddEthereumChainParameter { @@ -60,9 +78,11 @@ interface Props { } const NETWORKS = { - [ChainId.Mainnet]: Mainnet, + [ChainId.CeloMainnet]: CeloMainnet, [ChainId.Alfajores]: Alfajores, [ChainId.Baklava]: Baklava, + [ChainId.EthereumMainnet]: EthereumMainnet, + [ChainId.Kovan]: Kovan, }; export const AddCeloNetworkButton: React.FC = ({ chainId }: Props) => { diff --git a/packages/use-contractkit/src/connectors/useWalletConnectConnector.ts b/packages/use-contractkit/src/connectors/useWalletConnectConnector.ts index 2fa20bdc..67d99488 100644 --- a/packages/use-contractkit/src/connectors/useWalletConnectConnector.ts +++ b/packages/use-contractkit/src/connectors/useWalletConnectConnector.ts @@ -1,6 +1,6 @@ import { useEffect, useState } from 'react'; -import { Mainnet } from '../constants'; +import { CeloMainnet } from '../constants'; import { Connector } from '../types'; import { useContractKitInternal } from '../use-contractkit'; import { WalletConnectConnector } from './connectors'; @@ -16,7 +16,7 @@ export function useWalletConnectConnector( useEffect(() => { let mounted = true; const initialiseConnection = async () => { - const isMainnet = network.name === Mainnet.name; + const isMainnet = network.name === CeloMainnet.name; const relayProvider = isMainnet ? 'wss://walletconnect.celo.org' : 'wss://walletconnect.celo-networks-dev.org'; diff --git a/packages/use-contractkit/src/constants.tsx b/packages/use-contractkit/src/constants.tsx index 7232c759..fd334e12 100644 --- a/packages/use-contractkit/src/constants.tsx +++ b/packages/use-contractkit/src/constants.tsx @@ -180,7 +180,9 @@ export const images = { export enum NetworkNames { Alfajores = 'Alfajores', Baklava = 'Baklava', - Mainnet = 'Mainnet', + CeloMainnet = 'CeloMainnet', + EthereumMainnet = 'EthereumMainnet', + Kovan = 'Kovan', } export const Alfajores = { @@ -199,12 +201,32 @@ export const Baklava = { chainId: ChainId.Baklava, } as const; -export const Mainnet = { - name: NetworkNames.Mainnet, +export const CeloMainnet = { + name: NetworkNames.CeloMainnet, rpcUrl: 'https://forno.celo.org', graphQl: 'https://explorer.celo.org/graphiql', explorer: 'https://explorer.celo.org', - chainId: ChainId.Mainnet, + chainId: ChainId.CeloMainnet, +} as const; + +export const EthereumMainnet = { + name: NetworkNames.EthereumMainnet, + rpcUrl: + process.env.ETHEREUM_RPC_URL || + process.env.REACT_APP_ETHEREUM_RPC_URL || + '', + graphQl: 'https://blockscout.com/eth/mainnet/graphiql', + explorer: 'https://etherscan.io', + chainId: ChainId.EthereumMainnet, +} as const; + +export const Kovan = { + name: NetworkNames.Kovan, + rpcUrl: + process.env.KOVAN_RPC_URL || process.env.REACT_APP_KOVAN_RPC_URL || '', + graphQl: 'https://blockscout.com/eth/mainnet/graphiql', // TODO: Find graphql for Kovan + explorer: 'https://kovan.etherscan.io', + chainId: ChainId.Kovan, } as const; export enum WalletTypes { @@ -243,9 +265,15 @@ export const getProviderForWallet = ( /** * Default networks to connect to. */ -export const DEFAULT_NETWORKS = [Mainnet, Alfajores, Baklava]; +export const DEFAULT_NETWORKS = [ + CeloMainnet, + Alfajores, + Baklava, + EthereumMainnet, + Kovan, +]; /** * Chain ID of a default network. */ -export type DefaultChainId = ChainId.Mainnet | ChainId.Alfajores; +export type DefaultChainId = ChainId.CeloMainnet | ChainId.Alfajores; diff --git a/packages/use-contractkit/src/contract-kit-provider.tsx b/packages/use-contractkit/src/contract-kit-provider.tsx index f3f223ac..29b3b3bd 100644 --- a/packages/use-contractkit/src/contract-kit-provider.tsx +++ b/packages/use-contractkit/src/contract-kit-provider.tsx @@ -7,7 +7,7 @@ import React, { } from 'react'; import { CONNECTOR_TYPES, UnauthenticatedConnector } from './connectors'; -import { DEFAULT_NETWORKS, Mainnet } from './constants'; +import { DEFAULT_NETWORKS, CeloMainnet } from './constants'; import { Actions, ActionsMap, @@ -49,7 +49,7 @@ type ContractKitContextInterface = readonly [ ]; const initialState = { - connector: new UnauthenticatedConnector(Mainnet), + connector: new UnauthenticatedConnector(CeloMainnet), connectorInitError: null, dapp: { name: 'Celo dApp', @@ -57,7 +57,7 @@ const initialState = { url: 'https://celo.org', icon: 'https://celo.org/favicon.ico', }, - network: Mainnet, + network: CeloMainnet, networks: DEFAULT_NETWORKS, pendingActionCount: 0, address: null, diff --git a/packages/use-contractkit/src/types.ts b/packages/use-contractkit/src/types.ts index 96d83e17..e7a413a2 100644 --- a/packages/use-contractkit/src/types.ts +++ b/packages/use-contractkit/src/types.ts @@ -9,7 +9,9 @@ import { NetworkNames, WalletTypes } from './constants'; export enum ChainId { Alfajores = 44787, Baklava = 62320, - Mainnet = 42220, + CeloMainnet = 42220, + EthereumMainnet = 1, + Kovan = 42, } /** @@ -18,7 +20,7 @@ export enum ChainId { export interface Network { name: NetworkNames; rpcUrl: string; - graphQl: string; + graphQl?: string; explorer: string; chainId: ChainId; } diff --git a/packages/use-contractkit/src/utils/helpers.ts b/packages/use-contractkit/src/utils/helpers.ts index 1e2a2c27..111c48c0 100644 --- a/packages/use-contractkit/src/utils/helpers.ts +++ b/packages/use-contractkit/src/utils/helpers.ts @@ -2,7 +2,7 @@ import { CONNECTOR_TYPES, UnauthenticatedConnector } from '../connectors'; import { DEFAULT_NETWORKS, localStorageKeys, - Mainnet, + CeloMainnet, NetworkNames, WalletTypes, } from '../constants'; @@ -13,7 +13,7 @@ export const loadPreviousConfig = (): { network: Network; connector: Connector; } => { - let lastUsedNetworkName: NetworkNames = Mainnet.name; + let lastUsedNetworkName: NetworkNames = CeloMainnet.name; let lastUsedAddress: string | null = null; let lastUsedWalletType: WalletTypes = WalletTypes.Unauthenticated; let lastUsedWalletArguments: unknown[] = []; @@ -49,7 +49,7 @@ export const loadPreviousConfig = (): { } const lastUsedNetwork = - DEFAULT_NETWORKS.find((n) => n.name === lastUsedNetworkName) ?? Mainnet; + DEFAULT_NETWORKS.find((n) => n.name === lastUsedNetworkName) ?? CeloMainnet; let initialConnector: Connector; if (lastUsedWalletType) { From 967f40e8c35b381d7e670f5cfd20fb42e6e32e7d Mon Sep 17 00:00:00 2001 From: Brian Li Date: Wed, 29 Sep 2021 17:04:39 -0700 Subject: [PATCH 12/14] Rename Kovan ETH --- packages/example/pages/index.tsx | 4 ++-- .../use-contractkit/src/components/AddCeloNetworkButton.tsx | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/example/pages/index.tsx b/packages/example/pages/index.tsx index 732eed5a..885c29c4 100644 --- a/packages/example/pages/index.tsx +++ b/packages/example/pages/index.tsx @@ -3,7 +3,7 @@ import { ensureLeading0x } from '@celo/utils/lib/address'; import { Alfajores, Baklava, - Mainnet, + CeloMainnet, useContractKit, } from '@celo-tools/use-contractkit'; import { BigNumber } from 'bignumber.js'; @@ -27,7 +27,7 @@ function truncateAddress(address: string) { return `${address.slice(0, 8)}...${address.slice(36)}`; } -const networks = [Alfajores, Baklava, Mainnet]; +const networks = [Alfajores, Baklava, CeloMainnet]; export default function Home(): React.ReactElement { const { diff --git a/packages/use-contractkit/src/components/AddCeloNetworkButton.tsx b/packages/use-contractkit/src/components/AddCeloNetworkButton.tsx index a2f91f31..416982cb 100644 --- a/packages/use-contractkit/src/components/AddCeloNetworkButton.tsx +++ b/packages/use-contractkit/src/components/AddCeloNetworkButton.tsx @@ -39,7 +39,11 @@ const ETHEREUM_PARAMS = { const KOVAN_PARAMS = { chainName: 'Kovan', - nativeCurrency: { name: 'Ethereum', symbol: 'ETH', decimals: 18 as const }, + nativeCurrency: { + name: 'Kovan Ethereum', + symbol: 'KETH', + decimals: 18 as const, + }, }; const params: { [chain in ChainId]: typeof CELO_PARAMS } = { From 162a6132a00dce0a77d2aaa027e29af15a5deb34 Mon Sep 17 00:00:00 2001 From: Brian Li Date: Wed, 13 Oct 2021 04:28:17 -0700 Subject: [PATCH 13/14] Rebase on latest UCK upstream --- packages/use-contractkit/src/contract-kit-provider.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/use-contractkit/src/contract-kit-provider.tsx b/packages/use-contractkit/src/contract-kit-provider.tsx index 29b3b3bd..20d03f60 100644 --- a/packages/use-contractkit/src/contract-kit-provider.tsx +++ b/packages/use-contractkit/src/contract-kit-provider.tsx @@ -90,7 +90,7 @@ export const ContractKitProvider: React.FC = ({ connectModal, actionModal, dapp, - network = Mainnet, + network = CeloMainnet, networks = DEFAULT_NETWORKS, }: ContractKitProviderProps) => { const isMountedRef = useIsMounted(); From 2ff89c6e5863248d345ca367f5d2426dec3e749a Mon Sep 17 00:00:00 2001 From: zhanghongtao <1035569003@qq.com> Date: Thu, 21 Oct 2021 10:21:41 +0800 Subject: [PATCH 14/14] Optimize the connection method of celodance on the mobile terminal, and add support for deeplinks. Optimize the connection method of celodance on the mobile terminal, and add support for deeplinks. --- .../src/connectors/connectors-by-name.ts | 2 + .../src/connectors/connectors.ts | 49 +++++++++++- .../src/dappkit-wallet/dappkit.ts | 30 +++++-- .../src/dappkit-wallet/index.ts | 8 +- .../src/screens/celo-dance.tsx | 78 ++++++++++--------- packages/use-contractkit/src/screens/index.ts | 2 +- 6 files changed, 120 insertions(+), 49 deletions(-) diff --git a/packages/use-contractkit/src/connectors/connectors-by-name.ts b/packages/use-contractkit/src/connectors/connectors-by-name.ts index 70a003fb..1c1dbeb4 100644 --- a/packages/use-contractkit/src/connectors/connectors-by-name.ts +++ b/packages/use-contractkit/src/connectors/connectors-by-name.ts @@ -10,6 +10,7 @@ import { UnauthenticatedConnector, ValoraConnector, WalletConnectConnector, + CeloDanceConnector, } from './connectors'; /** @@ -30,4 +31,5 @@ export const CONNECTOR_TYPES: { [WalletTypes.CeloDance]: WalletConnectConnector, [WalletTypes.CeloTerminal]: WalletConnectConnector, [WalletTypes.CeloWallet]: WalletConnectConnector, + [WalletTypes.CeloDance]: isMobile ? CeloDanceConnector : WalletConnectConnector, }; diff --git a/packages/use-contractkit/src/connectors/connectors.ts b/packages/use-contractkit/src/connectors/connectors.ts index a2859cba..4604b7b3 100644 --- a/packages/use-contractkit/src/connectors/connectors.ts +++ b/packages/use-contractkit/src/connectors/connectors.ts @@ -381,7 +381,7 @@ export class ValoraConnector implements Connector { JSON.stringify([dappName]) ); - this.wallet = new DappKitWallet(dappName); + this.wallet = new DappKitWallet(dappName, this.type); this.kit = newKit(network.rpcUrl, this.wallet); this.wallet.setKit(this.kit); } @@ -402,3 +402,50 @@ export class ValoraConnector implements Connector { return; } } + +export class CeloDanceConnector implements Connector { + public initialised = false; + public type = WalletTypes.CeloDance; + public kit: ContractKit; + public wallet: DappKitWallet; + + get account(): string | null { + const storedConfig = localStorage.getItem(dappKitConfigKey); + let dappKitConfig = storedConfig ? JSON.parse(storedConfig) : null; + if (dappKitConfig) { + return dappKitConfig.phoneNumber; + } + return null; + } + + constructor(private network: Network, dappName: string) { + localStorage.setItem( + localStorageKeys.lastUsedWalletType, + WalletTypes.CeloDance + ); + localStorage.setItem( + localStorageKeys.lastUsedWalletArguments, + JSON.stringify([dappName]) + ); + + this.wallet = new DappKitWallet(dappName, this.type); + this.kit = newKit(network.rpcUrl, this.wallet); + this.wallet.setKit(this.kit); + } + + async initialise(): Promise { + await this.wallet.init(); + + this.kit = newKit(this.network.rpcUrl, this.wallet); + this.kit.defaultAccount = this.wallet.getAccounts()[0]; + this.wallet.setKit(this.kit); + this.initialised = true; + + return this; + } + + close(): void { + localStorage.removeItem(dappKitConfigKey); + return; + } +} \ No newline at end of file diff --git a/packages/use-contractkit/src/dappkit-wallet/dappkit.ts b/packages/use-contractkit/src/dappkit-wallet/dappkit.ts index 423b3c70..1f61bf61 100644 --- a/packages/use-contractkit/src/dappkit-wallet/dappkit.ts +++ b/packages/use-contractkit/src/dappkit-wallet/dappkit.ts @@ -6,12 +6,14 @@ import { DappKitRequestMeta, DappKitRequestTypes, DappKitResponseStatus, + DAPPKIT_BASE_HOST, parseDappkitResponseDeeplink, serializeDappKitRequestDeeplink, SignTxRequest, SignTxResponseSuccess, TxToSignParam, } from '@celo/utils'; +import { WalletTypes } from '../constants'; import Linking from './linking'; @@ -22,6 +24,8 @@ export { SignTxRequest, } from '@celo/utils'; +const CELO_DANCE_HOST = 'celo://wallet/dappkit/celodance'; + export const valoraLocalStorageKey = 'use-contractkit/dappkit'; // hack to get around deeplinking issue where new tabs are opened // and the url hash state is not respected (Note this implementation @@ -74,8 +78,11 @@ export async function waitForAccountAuth( ) { return dappKitResponse; } - - throw new Error('Unable to parse Valora response'); + if(requestId.endsWith(WalletTypes.CeloDance)){ + throw new Error('Unable to parse CeloDance response'); + }else{ + throw new Error('Unable to parse Valora response'); + } } export async function waitForSignedTxs( @@ -93,14 +100,22 @@ export async function waitForSignedTxs( } console.warn('Unable to parse url', url); - throw new Error('Unable to parse Valora response'); + if(requestId.endsWith(WalletTypes.CeloDance)){ + throw new Error('Unable to parse CeloDance response'); + }else{ + throw new Error('Unable to parse Valora response'); + } } export function requestAccountAddress(meta: DappKitRequestMeta): void { localStorage.removeItem(valoraLocalStorageKey); const deepLink = serializeDappKitRequestDeeplink(AccountAuthRequest(meta)); - Linking.openURL(deepLink); + if (meta.requestId.endsWith(WalletTypes.CeloDance)) { + Linking.openURL(deepLink.replace(DAPPKIT_BASE_HOST, CELO_DANCE_HOST)); + } else { + Linking.openURL(deepLink); + } } export async function requestTxSig( @@ -124,5 +139,10 @@ export async function requestTxSig( }); const request = SignTxRequest(txs, meta); - Linking.openURL(serializeDappKitRequestDeeplink(request)); + const deepLink = serializeDappKitRequestDeeplink(request); + if (meta.requestId.endsWith(WalletTypes.CeloDance)) { + Linking.openURL(deepLink.replace(DAPPKIT_BASE_HOST, CELO_DANCE_HOST)); + } else { + Linking.openURL(deepLink); + } } diff --git a/packages/use-contractkit/src/dappkit-wallet/index.ts b/packages/use-contractkit/src/dappkit-wallet/index.ts index 75a500b2..bf4f0e6a 100644 --- a/packages/use-contractkit/src/dappkit-wallet/index.ts +++ b/packages/use-contractkit/src/dappkit-wallet/index.ts @@ -2,7 +2,7 @@ import { CeloTx, EncodedTransaction, Signer } from '@celo/connect'; import { ContractKit } from '@celo/contractkit'; import { EIP712TypedData } from '@celo/utils/lib/sign-typed-data-utils'; import { RemoteWallet } from '@celo/wallet-remote'; - +import { WalletTypes } from '../constants'; import { requestAccountAddress, requestTxSig, @@ -51,7 +51,7 @@ const randomString = () => (Math.random() * 100).toString().slice(0, 6); export class DappKitWallet extends RemoteWallet { private kit?: ContractKit; - constructor(protected dappName: string) { + constructor(protected dappName: string, protected walletTypes: WalletTypes) { super(); } @@ -61,7 +61,7 @@ export class DappKitWallet extends RemoteWallet { const storedConfig = localStorage.getItem(dappKitConfigKey); let dappKitConfig = storedConfig ? JSON.parse(storedConfig) : null; if (!dappKitConfig) { - const requestId = `login-${randomString()}`; + const requestId = `login-${randomString()}-${this.walletTypes}`; requestAccountAddress({ requestId, dappName: this.dappName, @@ -104,7 +104,7 @@ export class DappKitWallet extends RemoteWallet { throw new Error('Must call setKit before using dappKit wallet'); } - const requestId = `signTransaction-${randomString()}`; + const requestId = `signTransaction-${randomString()}-${this.walletTypes}`; await requestTxSig(this.kit, [txParams], { requestId, dappName: this.dappName, diff --git a/packages/use-contractkit/src/screens/celo-dance.tsx b/packages/use-contractkit/src/screens/celo-dance.tsx index c213b1a1..fef02d95 100644 --- a/packages/use-contractkit/src/screens/celo-dance.tsx +++ b/packages/use-contractkit/src/screens/celo-dance.tsx @@ -1,53 +1,55 @@ -import QrCode from 'qrcode.react'; -import React from 'react'; -import { isMobile } from 'react-device-detect'; +import React, { useCallback, useEffect } from 'react'; import Loader from 'react-loader-spinner'; -import { CopyText } from '../components'; -import { useWalletConnectConnector } from '../connectors/useWalletConnectConnector'; +import { AddCeloNetworkButton } from '../components/AddCeloNetworkButton'; +import { CeloDanceConnector, UnsupportedChainIdError } from '../connectors'; import { Connector } from '../types'; +import { useContractKitInternal } from '../use-contractkit'; interface Props { onSubmit: (connector: Connector) => void; } -const getDeepLink = (uri: string) => { - return `celo://wallet/wc?uri=${uri}`; -}; - export const CeloDance: React.FC = ({ onSubmit }: Props) => { - const uri = useWalletConnectConnector(onSubmit, isMobile, getDeepLink); + const { + network, + initConnector, + initError: error, + dapp, + } = useContractKitInternal(); - return ( -
-

- CeloDance -

-
- Scan the QR code below or copy-paste the information into your wallet. -
+ const initialiseConnection = useCallback(async () => { + const connector = new CeloDanceConnector(network, dapp.name); + try { + await initConnector(connector); + onSubmit(connector); + } catch (e) { + console.error(e); + } + }, [initConnector, network, onSubmit, dapp.name]); -
- {uri ? ( - <> -
- -
- -
-
- - ) : ( -
- -
- )} + useEffect(() => { + void initialiseConnection(); + }, [initialiseConnection]); + + if (error?.name === UnsupportedChainIdError.NAME) { + return ( +
+

+ Please connect to the Celo network to continue. +

+
+ ); + } + + return ( +
+ {error ? ( +

{error.message}

+ ) : ( + + )}
); }; diff --git a/packages/use-contractkit/src/screens/index.ts b/packages/use-contractkit/src/screens/index.ts index 1e83e359..500ec4c7 100644 --- a/packages/use-contractkit/src/screens/index.ts +++ b/packages/use-contractkit/src/screens/index.ts @@ -21,7 +21,7 @@ export const defaultScreens: { [SupportedProviders.WalletConnect]: WalletConnect, [SupportedProviders.Ledger]: Ledger, [SupportedProviders.CeloWallet]: CeloWallet, - [SupportedProviders.CeloDance]: CeloDance, + [SupportedProviders.CeloDance]: isMobile ? CeloDance : WalletConnect, [SupportedProviders.CeloTerminal]: WalletConnect, [SupportedProviders.CeloExtensionWallet]: CeloExtensionWallet, [SupportedProviders.Injected]: MetaMaskWallet,