Skip to content

Commit

Permalink
feat: Add Metamask Astar Snap to native wallet options (#933)
Browse files Browse the repository at this point in the history
* add snap to native wallet options

* Compilation errors fix

* Fix for compilation errors fix

* snap utils

* no extra line

* inject

* extension listed

* 3rd time is the charm

* feat: updated UI logic for the MetaMask snap (#941)

* fix: connect to metamask snap smoothly

* fix: allow the snap only on Shibuya, moved snapUtils to the snap module

* fix: updated loading animation

* fix: display accounts after users add Astar and Polkadot Snap (#949)

* fix: enable MetaMask snap only in dev mode (#952)

* remove console logs

* remove unused code

* remove unused ethereum provider

* Update ModalConnectWallet.vue

* Update useAccount.ts

* fix: enable snap in staging

* fix: build error

* using astar npm

* correct snapId

---------

Co-authored-by: Bobo <bobo.kovacevic@gmail.com>
Co-authored-by: impelcrypto <92044428+impelcrypto@users.noreply.github.com>
Co-authored-by: impelcrypto <impelcrypto@gmail.com>
  • Loading branch information
4 people committed Oct 16, 2023
1 parent 2d23d3a commit 29f1bdc
Show file tree
Hide file tree
Showing 11 changed files with 214 additions and 32 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
"dependencies": {
"@astar-network/astar-sdk-core": "^0.2.5",
"@astar-network/astar-ui": "^0.0.104",
"@astar-network/metamask-astar-adapter": "^0.5.4",
"@astar-network/metamask-astar-types": "^0.6.1",
"@ethersproject/bignumber": "^5.5.0",
"@polkadot/api": "^10.9.1",
"@polkadot/api-contract": "^10.9.1",
Expand Down
10 changes: 9 additions & 1 deletion src/boot/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ import { useExtensions } from 'src/hooks/useExtensions';
import { useMetaExtensions } from 'src/hooks/useMetaExtensions';
import { computed, ref, watchPostEffect } from 'vue';
import Web3 from 'web3';
import { supportWalletObj } from 'src/config/wallets';
import { SupportWallet, supportWalletObj } from 'src/config/wallets';
import { initiatePolkdatodSnap } from 'src/modules/snap';
import { initPolkadotSnap } from '@astar-network/metamask-astar-adapter';

let $api: ApiPromise | undefined;
const $web3 = ref<Web3>();
Expand Down Expand Up @@ -131,6 +133,12 @@ export default boot(async ({ store }) => {
// execute extension process automatically if selectedAddress is linked or mobile device
const wallet = String(localStorage.getItem(SELECTED_WALLET));
const isSubstrateWallet = supportWalletObj.hasOwnProperty(wallet);

if (wallet === SupportWallet.Snap) {
const isSnapInstalled = await initiatePolkdatodSnap();
isSnapInstalled && (await initPolkadotSnap());
}

if (isSubstrateWallet) {
if (selectedAddress !== null || isMobileDevice) {
const { extensions } = useExtensions(api, store);
Expand Down
63 changes: 49 additions & 14 deletions src/components/header/modals/ModalConnectWallet.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
</span>
</div>
<div class="wrapper--wallets">
<div
<button
v-for="(wallet, index) in evmWallets"
:key="index"
class="box__row--wallet box--hover--active"
Expand All @@ -29,7 +29,7 @@
{{ castWalletName(wallet.name) }}
</span>
</div>
</div>
</button>
</div>
</div>
<div>
Expand All @@ -39,12 +39,13 @@
</span>
</div>
<div class="wrapper--wallets">
<div
<button
v-for="(wallet, index) in nativeWallets"
:key="index"
:disabled="checkIsDisabledWallet(wallet.source)"
class="box__row--wallet box--hover--active"
:class="currentWallet === wallet.source && 'border--active'"
@click="setSubstrateWalletModal(wallet.source)"
@click="!checkIsDisabledWallet(wallet.source) && setSubstrateWalletModal(wallet.source)"
>
<div class="box--img">
<img :src="wallet.img" />
Expand All @@ -54,7 +55,7 @@
{{ castWalletName(wallet.name) }}
</span>
</div>
</div>
</button>
</div>
<div v-if="selWallet && isNoExtension" class="box--no-extension">
<div class="title--no-extension">
Expand Down Expand Up @@ -108,7 +109,7 @@
</span>
</div>
<div class="wrapper--wallets">
<div
<button
class="box__row--wallet box--hover--active"
:class="currentWallet === SupportMultisig.Polkasafe && 'border--active'"
@click="setPolkasafeModal()"
Expand All @@ -122,7 +123,7 @@
<div>
<span> PolkaSafe </span>
</div>
</div>
</button>
</div>
</div>
<!-- temporarily disable until we implement account selection UI -->
Expand Down Expand Up @@ -151,22 +152,27 @@
</template>
<script lang="ts">
import { wait } from '@astar-network/astar-sdk-core';
import { initPolkadotSnap } from '@astar-network/metamask-astar-adapter';
import { get } from 'lodash-es';
import { $api } from 'src/boot/api';
import { endpointKey } from 'src/config/chainEndpoints';
import {
SupportMultisig,
SupportWallet,
Wallet,
supportAllWalletsObj,
supportEvmWalletObj,
supportEvmWallets,
SupportWallet,
supportWallets,
Wallet,
SupportMultisig,
} from 'src/config/wallets';
import { useAccount, useNetworkInfo } from 'src/hooks';
import { isMobileDevice } from 'src/hooks/helper/wallet';
import { getInjectedExtensions, isMobileDevice } from 'src/hooks/helper/wallet';
import { useExtensions } from 'src/hooks/useExtensions';
import { initiatePolkdatodSnap } from 'src/modules/snap';
import { useStore } from 'src/store';
import { computed, defineComponent, PropType, ref } from 'vue';
import { endpointKey } from 'src/config/chainEndpoints';
import { SubstrateAccount } from 'src/store/general/state';
import { PropType, computed, defineComponent, ref } from 'vue';
import { productionOrigin } from 'src/links';
export default defineComponent({
props: {
Expand Down Expand Up @@ -205,7 +211,8 @@ export default defineComponent({
},
setup(props) {
const store = useStore();
const { currentAccountName, disconnectAccount, isAccountUnification } = useAccount();
const { currentAccountName, disconnectAccount, isAccountUnification, isSnapEnabled } =
useAccount();
const isClosing = ref<boolean>(false);
const { currentNetworkIdx } = useNetworkInfo();
Expand All @@ -217,10 +224,20 @@ export default defineComponent({
props.setCloseModal();
};
const checkIsDisabledWallet = (source: SupportWallet): boolean => {
if (source === SupportWallet.Snap && window.location.origin === productionOrigin) {
return true;
}
return false;
};
const nativeWallets = computed(() => {
return supportWallets
.map((it) => {
const { isSupportMobileApp, isSupportBrowserExtension } = it;
if (it.source === SupportWallet.Snap) {
return isSnapEnabled.value ? it : undefined;
}
if (isMobileDevice) {
return isSupportMobileApp ? it : undefined;
} else {
Expand Down Expand Up @@ -258,7 +275,24 @@ export default defineComponent({
}
};
const handleMetaMaskSnap = async (): Promise<void> => {
const provider = get(window, supportEvmWalletObj[SupportWallet.MetaMask].ethExtension);
const [address] = (await provider.request({ method: 'eth_requestAccounts' })) as string;
if (!address) return;
const isSnapInstalled = await initiatePolkdatodSnap();
if (isSnapInstalled) {
await initPolkadotSnap();
useExtensions($api!!, store);
const extensions = await getInjectedExtensions(true);
const isExtensionsUpdated = extensions.some((it) => it.name === SupportWallet.Snap);
// Memo: Sync the metamask extension for users who visit our portal first time
!isExtensionsUpdated && (await wait(3000));
}
};
const setSubstrateWalletModal = async (source: string): Promise<void> => {
if (source === SupportWallet.Snap) {
await handleMetaMaskSnap();
}
await closeModal();
props.setWalletModal(source);
};
Expand Down Expand Up @@ -293,6 +327,7 @@ export default defineComponent({
setEvmWalletModal,
disconnectAccount,
setPolkasafeModal,
checkIsDisabledWallet,
setAccountUnificationModal,
currentNetworkIdx,
endpointKey,
Expand Down
13 changes: 13 additions & 0 deletions src/config/wallets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export enum SupportWallet {
HanaEvm = 'hanaEvm',
OneKeyEvm = 'OneKeyEvm',
OneKeyNative = 'OneKey',
Snap = 'Snap',
}

export enum SupportMultisig {
Expand Down Expand Up @@ -53,6 +54,7 @@ export const WalletModalOption = {
HanaEvm: SupportWallet.HanaEvm,
OneKey: SupportWallet.OneKeyNative,
OneKeyEvm: SupportWallet.OneKeyEvm,
Snap: SupportWallet.Snap,
};

export const SubstrateWallets = [
Expand All @@ -67,6 +69,7 @@ export const SubstrateWallets = [
SupportWallet.Wallet3,
SupportWallet.HanaNative,
SupportWallet.OneKeyNative,
SupportWallet.Snap,
];

export interface Wallet {
Expand All @@ -91,6 +94,16 @@ export const supportWalletObj = {
isSupportBrowserExtension: true,
isSupportMobileApp: false,
},
[SupportWallet.Snap]: {
img: require('/src/assets/img/metamask.png'),
name: 'Astar Snap',
source: SupportWallet.Snap,
// Todo: update URLs
walletUrl: 'https://metamask.io/flask/',
guideUrl: 'https://docs.astar.network/docs/build/integrations/wallets/astar-safe',
isSupportBrowserExtension: true,
isSupportMobileApp: false,
},
[SupportWallet.TalismanNative]: {
img: require('/src/assets/img/logo-talisman.svg'),
name: 'Talisman (Native)',
Expand Down
8 changes: 0 additions & 8 deletions src/hooks/types/CustomSignature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,3 @@ export interface EcdsaAddressFormat {
ss58?: string;
h160?: string;
}

declare global {
interface Window {
ethereum?: EthereumProvider;
talismanEth?: EthereumProvider;
SubWallet?: EthereumProvider;
}
}
15 changes: 13 additions & 2 deletions src/hooks/useAccount.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { isValidEvmAddress, toSS58Address, wait } from '@astar-network/astar-sdk-core';
import { endpointKey } from 'src/config/chainEndpoints';
import { LOCAL_STORAGE } from 'src/config/localStorage';
import { SupportMultisig } from 'src/config/wallets';
import { SupportMultisig, SupportWallet } from 'src/config/wallets';
import { Multisig } from 'src/modules/multisig';
import { useStore } from 'src/store';
import { SubstrateAccount } from 'src/store/general/state';
Expand All @@ -11,7 +12,6 @@ import { IAccountUnificationService } from 'src/v2/services';
import { Symbols } from 'src/v2/symbols';
import { computed, ref, watch } from 'vue';
import { useNetworkInfo } from './useNetworkInfo';
import { endpointKey } from 'src/config/chainEndpoints';
import { INftRepository } from 'src/v2/repositories';
import { useNft } from './useNft';
import { NftMetadata } from 'src/v2/models';
Expand All @@ -31,6 +31,7 @@ export const useAccount = () => {
const currentEcdsaAccount = computed(() => store.getters['general/currentEcdsaAccount']);
const substrateAccounts = computed(() => store.getters['general/substrateAccounts']);
const currentAddress = computed(() => store.getters['general/selectedAddress']);
const isSnapEnabled = computed<boolean>(() => currentNetworkIdx.value === endpointKey.SHIBUYA);
const unifiedAccount = computed(() => store.getters['general/getUnifiedAccount']);

const isAccountUnification = computed<boolean>(() => {
Expand Down Expand Up @@ -222,6 +223,15 @@ export const useAccount = () => {
{ immediate: true }
);

const checkIsResetSnap = async (): Promise<void> => {
const storedWallet = String(localStorage.getItem(LOCAL_STORAGE.SELECTED_WALLET));
if (!isSnapEnabled.value && storedWallet === SupportWallet.Snap) {
await disconnectAccount();
window.location.reload();
}
};

watch([currentAddress], checkIsResetSnap, { immediate: true });
watch([unifiedAccount], () => {
if (unifiedAccount.value) {
currentAccountName.value = unifiedAccount.value.name;
Expand All @@ -235,6 +245,7 @@ export const useAccount = () => {
senderSs58Account,
multisig,
isMultisig,
isSnapEnabled,
isAccountUnification,
isH160Formatted,
disconnectAccount,
Expand Down
3 changes: 2 additions & 1 deletion src/hooks/useConnectWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,11 +192,12 @@ export const useConnectWallet = () => {
modalName.value = wallet;
};

const requestExtensionsIfFirstAccess = (wallet: SupportWallet): void => {
const requestExtensionsIfFirstAccess = async (wallet: SupportWallet): Promise<void> => {
// Memo: displays accounts menu for users who use the portal first time
const isSubstrateWallet = supportWalletObj.hasOwnProperty(wallet);
const storedAddress = localStorage.getItem(SELECTED_ADDRESS);
const isFirstAccess = storedAddress === null || storedAddress === ETHEREUM_EXTENSION;

if (isFirstAccess && isSubstrateWallet) {
const { extensions } = useExtensions($api!!, store);
const { metaExtensions, extensionCount } = useMetaExtensions($api!!, extensions)!!;
Expand Down
2 changes: 1 addition & 1 deletion src/hooks/wallet/useAccountUnification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import { useNetworkInfo } from '../useNetworkInfo';
import { IIdentityRepository } from 'src/v2/repositories';
import { UnifiedAccount } from 'src/store/general/state';

const provider = get(window, 'ethereum');
const provider = get(window, 'ethereum') as any;

export interface TransferXc20Token {
assetId: string;
Expand Down
Loading

0 comments on commit 29f1bdc

Please sign in to comment.