feat: add sign in with web3 wallet (#81)

This commit is contained in:
Vojtech Simetka 2022-12-20 13:55:27 +01:00 committed by GitHub
parent a1f0462646
commit 1f40f7ce3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 1452 additions and 16 deletions

1400
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -24,6 +24,7 @@
"eslint": "^8.29.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-svelte3": "^4.0.0",
"ethers": "^5.7.2",
"prettier": "^2.8.1",
"prettier-plugin-svelte": "^2.9.0",
"sass": "^1.56.2",

View File

@ -28,7 +28,7 @@
<div class="subtitle">Public timeline</div>
{#if $profile.key?.publicKey !== undefined}
{#if $profile.signer !== undefined}
<div>
Share freely...
<Button

View File

@ -1,5 +1,5 @@
<script lang="ts">
import { formatAddress, formatDateFromNow } from '$lib/utils'
import { formatDateFromNow } from '$lib/utils'
import type { Post } from '$lib/stores/post'

View File

@ -1,18 +1,24 @@
import { writable, type Writable } from 'svelte/store'
import type { User } from './user'
import { providers } from 'ethers'
type WindowWithEthereum = Window &
typeof globalThis & { ethereum: providers.ExternalProvider | providers.JsonRpcFetchFunc }
export interface Profile {
key?: {
publicKey: string
}
signer?: providers.JsonRpcSigner
error?: Error
profiles: User[]
active?: User
}
export interface ProfileStore extends Writable<Profile> {
setActive: (user: User) => void
getSigner: (network?: providers.Networkish) => Promise<void>
}
export const canConnect = () => Boolean((window as WindowWithEthereum).ethereum)
function createProfileStore(): ProfileStore {
const store = writable<Profile>({ profiles: [], active: undefined })
@ -21,6 +27,20 @@ function createProfileStore(): ProfileStore {
setActive: (user: User) => {
store.update((profile) => ({ ...profile, active: user }))
},
getSigner: async (network) => {
try {
const provider = new providers.Web3Provider(
(window as WindowWithEthereum).ethereum,
network,
)
await provider.send('eth_requestAccounts', [])
const signer = provider.getSigner()
store.update((profile) => ({ ...profile, signer, error: undefined }))
} catch (error) {
store.update((profile) => ({ ...profile, signer: undefined, error: error as Error }))
}
},
}
}

View File

@ -8,7 +8,7 @@
</script>
<div>
<Header loggedin={$profile.key !== undefined} />
<Header loggedin={$profile.signer !== undefined} />
{#each $posts as post}
<Post {post} />

View File

@ -10,13 +10,15 @@
let postText = ''
function submit() {
if (!$profile.key?.publicKey) return
async function submit() {
if (!$profile.signer) return
const address = await $profile.signer.getAddress()
posts.add({
timestamp: Date.now(),
text: postText,
user: { address: $profile.key.publicKey },
user: { address },
})
goto(ROUTES.HOME)
}
@ -31,7 +33,7 @@
label="Post"
icon={SendAltFilled}
on:click={submit}
disabled={!$profile.key?.publicKey}
disabled={!$profile.signer}
/>
</div>
</div>

View File

@ -4,7 +4,7 @@
import Undo from '$lib/components/icons/undo.svelte'
import Wallet from '$lib/components/icons/wallet.svelte'
import Input from '$lib/components/input.svelte'
import { profile } from '$lib/stores/profile'
import { canConnect, profile } from '$lib/stores/profile'
</script>
<div class="header">
@ -16,23 +16,36 @@
variant="primary"
icon={Logout}
label="Logout"
on:click={() => ($profile.key = undefined)}
disabled={!$profile.key}
on:click={() => ($profile.signer = undefined)}
disabled={!$profile.signer}
/>
</div>
<div class="content">
{#if $profile.key?.publicKey === undefined}
{#if !canConnect()}
<span>Your browser does not have web3 wallet access.</span>
{:else if $profile.signer === undefined}
<Button
variant="primary"
icon={Wallet}
label="Connect wallet to post"
on:click={() => ($profile.key = { publicKey: '0x90b1c0A1EeF1fe519AeE75D2Ee04855219923f26' })}
on:click={() => profile.getSigner()}
/>
<span>Connect a wallet to access or create your account.</span>
{#if $profile.error !== undefined}
<span>Failed to connect {$profile.error.message}</span>
{/if}
{:else}
<span>Wallet & Identity</span>
<Input title="Connected wallet">
<span>{$profile.key.publicKey}</span>
<span>
{#await $profile.signer.getAddress()}
loading...
{:then address}
{address}
{:catch error}
{error.message}
{/await}
</span>
</Input>
{/if}
</div>