Skip to content

Commit

Permalink
feat: evm and substrate wallet connection (#72)
Browse files Browse the repository at this point in the history
<!--- Provide a general summary of your changes in the Title above -->

## Description

While evm side could be considered complete, on substrate side, we are
missing wallet selector and account selector components.

## Related Issue Or Context

<!--- If suggesting a new feature or change, please discuss it in an
issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps
to reproduce -->
<!--- Otherwise, describe context and motivation for change here -->

Closes: #<issue>

## How Has This Been Tested? Testing details.

<!--- Please describe in detail how you tested your changes. -->
<!--- Include details of your testing environment, and the tests you ran
to -->
<!--- see how your change affects other areas of the code, etc. -->

## Types of changes

<!--- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->

- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation

## Checklist:

<!--- Go over all the following points, and put an `x` in all the boxes
that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->

- [ ] I have commented my code, particularly in hard-to-understand
areas.
- [ ] I have ensured that all acceptance criteria (or expected behavior)
from issue are met
- [ ] I have updated the documentation locally and in sygma-docs.
- [ ] I have added tests to cover my changes.
- [ ] I have ensured that all the checks are passing and green, I've
signed the CLA bot

---------

Signed-off-by: Marin Petrunic <[email protected]>
Co-authored-by: Filip Štoković <[email protected]>
Co-authored-by: Nicolás Riquelme Guzmán <[email protected]>
  • Loading branch information
3 people authored Feb 6, 2024
1 parent d512f58 commit ccf2049
Show file tree
Hide file tree
Showing 29 changed files with 3,923 additions and 499 deletions.
5 changes: 5 additions & 0 deletions packages/widget/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,15 @@
"@ethersproject/transactions": "^5.7.0",
"@lit/context": "^1.1.0",
"@lit/reactive-element": "^2.0.3",
"@polkadot-onboard/core": "^1.1.0",
"@polkadot-onboard/injected-wallets": "^1.1.0",
"@polkadot/api": "^10.11.2",
"@polkadot/extension-dapp": "^0.46.6",
"@polkadot/keyring": "^12.6.2",
"@polkadot/util": "^12.6.2",
"@web3-onboard/core": "^2.21.2",
"@web3-onboard/injected-wallets": "^2.10.11",
"@web3-onboard/walletconnect": "^2.5.3",
"ethers": "5.7.2",
"events": "^3.3.0",
"lit": "3.0.0"
Expand Down
15 changes: 15 additions & 0 deletions packages/widget/src/assets/icons/greenCircleIcon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { html } from 'lit';

const greenCircleIcon = html`
<svg
xmlns="http://www.w3.org/2000/svg"
width="5"
height="6"
viewBox="0 0 5 6"
fill="none"
>
<circle cx="2.5" cy="2.82764" r="2.5" fill="#86EFAC" />
</svg>
`;

export default greenCircleIcon;
40 changes: 40 additions & 0 deletions packages/widget/src/assets/icons/plusIcon.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { html } from 'lit';

const plusIcon = html`
<svg
xmlns="http://www.w3.org/2000/svg"
width="14"
height="14"
viewBox="0 1 14 14"
fill="none"
>
<g clip-path="url(#clip0_318_443)">
<path
d="M7 3.74438V11.9111"
stroke="#A1A1AA"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M2.91663 7.82764H11.0833"
stroke="#A1A1AA"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</g>
<defs>
<clipPath id="clip0_318_443">
<rect
width="14"
height="14"
fill="white"
transform="translate(0 0.827637)"
/>
</clipPath>
</defs>
</svg>
`;

export default plusIcon;
110 changes: 110 additions & 0 deletions packages/widget/src/components/buttons/connect-wallet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import type { Domain } from '@buildwithsygma/sygma-sdk-core';
import { consume } from '@lit/context';
import type { HTMLTemplateResult, PropertyValues } from 'lit';
import { html } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { when } from 'lit/directives/when.js';
import plusIcon from '../../assets/icons/plusIcon';
import type { WalletContext } from '../../context';
import { walletContext } from '../../context';
import { WalletController } from '../../controllers';
import { shortAddress } from '../../utils';
import { BaseComponent } from '../base-component/base-component';
import greenCircleIcon from '../../assets/icons/greenCircleIcon';
import { styles } from './styles';

@customElement('sygma-connect-wallet-btn')
export class ConnectWalletButton extends BaseComponent {
static styles = styles;

@property({
type: Object,
attribute: true,
hasChanged: (value: Domain, old: Domain) => {
return value?.id !== old?.id;
}
})
sourceNetwork?: Domain;

@property({
type: String
})
dappUrl?: string;

@consume({ context: walletContext, subscribe: true })
@state()
private wallets!: WalletContext;

private walletController = new WalletController(this);

updated(changedProperties: PropertyValues): void {
super.updated(changedProperties);
if (changedProperties.has('sourceNetwork')) {
this.walletController.sourceNetworkUpdated(this.sourceNetwork);
}
}

private onConnectClicked = (): void => {
if (this.sourceNetwork) {
this.walletController.connectWallet(this.sourceNetwork, {
dappUrl: this.dappUrl
});
}
};

private onDisconnectClicked = (): void => {
this.walletController.disconnectWallet();
};

private isWalletConnected(): boolean {
return !!this.wallets.evmWallet || !!this.wallets.substrateWallet;
}

render(): HTMLTemplateResult {
const evmWallet = this.wallets.evmWallet;
const substrateWallet = this.wallets.substrateWallet;
//TODO: this is wrong we need to enable user to select account
const substrateAccount = substrateWallet?.accounts[0];
return html` <div class="connectWalletContainer">
${when(
!!evmWallet?.address,
() =>
html`<span class="walletAddress" title=${evmWallet?.address ?? ''}
>${greenCircleIcon} ${shortAddress(evmWallet?.address ?? '')}</span
>`
)}
${when(
!!substrateAccount,
() =>
html`<span
class="walletAddress"
title=${substrateAccount?.address ?? ''}
>${greenCircleIcon} ${substrateAccount?.name}
${shortAddress(substrateAccount?.address ?? '')}</span
>`
)}
${when(
this.isWalletConnected(),
() =>
html`<button
@click=${this.onDisconnectClicked}
class="connectWalletButton"
>
Disconnect
</button>`,
() =>
html`<button
@click=${this.onConnectClicked}
class="connectWalletButton"
>
${plusIcon} Connect Wallet
</button>`
)}
</div>`;
}
}
declare global {
interface HTMLElementTagNameMap {
'sygma-connect-wallet-btn': ConnectWalletButton;
}
}
1 change: 1 addition & 0 deletions packages/widget/src/components/buttons/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { ConnectWalletButton } from './connect-wallet';
39 changes: 39 additions & 0 deletions packages/widget/src/components/buttons/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { css } from 'lit';

export const styles = css`
:host {
display: flex;
justify-content: flex-end;
align-items: center;
}
.connectWalletContainer {
display: flex;
flex-direction: row;
gap: 0.5rem;
align-items: center;
}
.walletAddress,
.connectWalletButton {
font-size: 0.875rem;
font-weight: 500;
color: var(--zinc-700);
line-height: 0.9375rem;
display: flex;
align-items: center;
gap: 0.25rem;
}
.connectWalletButton {
padding: 0.375rem 0.5rem;
border-radius: 2.5rem;
background-color: var(--zinc-100);
border: 1px solid var(--gray-100);
cursor: pointer;
}
.connectWalletButton:hover {
background-image: linear-gradient(rgb(0 0 0/3%) 0 0);
}
`;
1 change: 1 addition & 0 deletions packages/widget/src/components/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { AmountSelector } from './amount-selector';
export { NetworkSelector } from './network-selector';
export { ConnectWalletButton } from './buttons';
export { AddressInput } from './address-input';
1 change: 0 additions & 1 deletion packages/widget/src/components/network-selector/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ export const styles = css`
border-radius: 1.5rem;
border: 0.0625rem solid #e4e4e7;
display: flex;
width: 100%;
max-width: 19.625rem;
max-height: 4.625rem;
padding: 0.75rem 1rem;
Expand Down
6 changes: 6 additions & 0 deletions packages/widget/src/context/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export {
walletContext,
WalletUpdateEvent,
WalletContextProvider
} from './wallet';
export type { EvmWallet, WalletContext } from './wallet';
69 changes: 69 additions & 0 deletions packages/widget/src/context/wallet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { createContext, provide } from '@lit/context';
import type { Account, UnsubscribeFn } from '@polkadot-onboard/core';
import type { Signer } from '@polkadot/api/types';
import type { EIP1193Provider } from '@web3-onboard/core';
import type { HTMLTemplateResult } from 'lit';
import { html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { BaseComponent } from '../components/base-component/base-component';

export interface EvmWallet {
address: string;
provider: EIP1193Provider;
}

export interface SubstrateWallet {
signer: Signer;
accounts: Account[];
unsubscribeSubstrateAccounts?: UnsubscribeFn;
disconnect?: () => Promise<void>;
}

export interface WalletContext {
evmWallet?: EvmWallet;
substrateWallet?: SubstrateWallet;
}

declare global {
interface HTMLElementEventMap {
walletUpdate: WalletUpdateEvent;
}
}

export const walletContext = createContext<WalletContext>(
Symbol('sygma-wallet-context')
);

export class WalletUpdateEvent extends CustomEvent<WalletContext> {
constructor(update: Partial<WalletContext>) {
super('walletUpdate', { detail: update, composed: true, bubbles: true });
}
}

@customElement('sygma-wallet-context-provider')
export class WalletContextProvider extends BaseComponent {
//TODO: add properties to allow widget to pass external provider/signers.

@provide({ context: walletContext })
private walletContext: WalletContext = {};

connectedCallback(): void {
super.connectedCallback();
this.addEventListener('walletUpdate', (event: WalletUpdateEvent) => {
this.walletContext = {
...this.walletContext,
...event.detail
};
});
}

protected render(): HTMLTemplateResult {
return html`<slot></slot>`;
}
}

declare global {
interface HTMLElementTagNameMap {
'sygma-wallet-context-provider': WalletContextProvider;
}
}
Loading

0 comments on commit ccf2049

Please sign in to comment.