commit 324ac2cddc9f47552560eae172cf1ff7c17b1379
parent 4c0ddde83d652c0fa578976c0292b5a66c3b894b
Author: William Muli <willi.wambu@gmail.com>
Date: Sun, 18 Jun 2023 12:41:35 +0300
Added balance and token vote details
Diffstat:
6 files changed, 159 insertions(+), 97 deletions(-)
diff --git a/src/client.ts b/src/client.ts
@@ -1,12 +1,12 @@
import { createPublicClient, createWalletClient, custom, http } from 'viem'
-import { localhost } from '@wagmi/chains'
+import type { Chain } from '@wagmi/chains'
-export const walletClient = () => createWalletClient({
- chain: localhost,
+export const walletClient = (chain: Chain) => createWalletClient({
+ chain,
transport: custom(window.ethereum)
})
-export const publicClient = () => createPublicClient({
- chain: localhost,
+export const publicClient = (chain: Chain) => createPublicClient({
+ chain ,
transport: http()
})
\ No newline at end of file
diff --git a/src/components/Nav.svelte b/src/components/Nav.svelte
@@ -1,16 +1,58 @@
<script lang="ts">
import { onMount } from "svelte"
- import { connectionDetails, configuredChain } from "../store";
- import { walletClient } from "../client"
+ import { PUBLIC_ERC20_CONTRACT_ADDRESS } from "$env/static/public"
+ import { connectionDetails, configuredChain, voteToken, votingConfig } from "../store";
+ import { publicClient, walletClient } from "../client"
import { NavOptions } from "../options/nav-options";
import { reduceAddress } from "../utils/reduce-address"
- import type { RequestAddressesReturnType } from "viem"
-
+ import { formatEther, formatUnits, getContract, type RequestAddressesReturnType } from "viem"
+ import { erc20TokenAbi } from "../shared/erc20-token-abi"
+
let networkModalOpen: boolean = false
+ let tokenModalOpen: boolean = false
+ let balance: bigint
+
+ $: ({ name, symbol, decimals, balance: erc20Balance } = $voteToken)
+ $: ({ isConnected, userAddress } = $connectionDetails)
+ $: ({ contractAddress, erc20ContractAddress } = $votingConfig)
+
+ $: {
+ if($configuredChain && userAddress) {
+ publicClient($configuredChain)
+ .getBalance({
+ address: userAddress
+ })
+ .then(bal => balance = bal)
+ .catch(err => console.error(err))
+
+ const contract = getContract({
+ address: PUBLIC_ERC20_CONTRACT_ADDRESS as `0x${string}`,
+ publicClient: publicClient($configuredChain),
+ walletClient: walletClient($configuredChain),
+ abi: erc20TokenAbi
+ })
+
+ contract.read.balanceOf([userAddress] as [`0x${string}`])
+ .then(balance => voteToken.update(current => ({...current, balance })))
+ .catch(err => console.error(err))
+
+ contract.read.name()
+ .then(name => voteToken.update(current => ({...current, name })))
+ .catch(err => console.error(err))
+
+ contract.read.symbol()
+ .then(symbol => voteToken.update(current => ({...current, symbol })))
+ .catch(err => console.error(err))
+
+ contract.read.decimals()
+ .then(decimals => voteToken.update(current => ({...current, decimals })))
+ .catch(err => console.error(err))
+ }
+ }
const connectWallet = async () => {
if (window.ethereum) {
- const accounts = await walletClient().requestAddresses()
+ const accounts = await walletClient($configuredChain).requestAddresses()
if (accounts.length > 0) {
updateConnectionDetails(true, accounts)
@@ -24,7 +66,7 @@
onMount(async () => {
if (window.ethereum) {
- const accounts = await walletClient().getAddresses()
+ const accounts = await walletClient($configuredChain).getAddresses()
if (accounts.length > 0) {
updateConnectionDetails(true, accounts)
@@ -73,24 +115,36 @@
{/each}
</div>
<div>
- <button class="btn btn-primary btn-md normal-case text-white" on:click={() => networkModalOpen = true}>Network Details</button>
+ <button class="btn btn-secondary text-white normal-case" on:click={() => tokenModalOpen = true}>
+ {name} Bal: {erc20Balance && decimals && `${formatUnits(erc20Balance, decimals)} ${symbol}`}
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
+ <path stroke-linecap="round" stroke-linejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
+ </svg>
+ </button>
+ <button
+ class="btn btn-primary btn-md normal-case text-white"
+ on:click={() => networkModalOpen = true}>
+ Network Details
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
+ <path stroke-linecap="round" stroke-linejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5" />
+ </svg>
+ </button>
<button
class="btn btn-md btn-primary text-white"
on:click={connectWallet}
>
- {$connectionDetails.isConnected ? reduceAddress($connectionDetails.userAddress) : 'Connect wallet'}
+ {isConnected && userAddress ? reduceAddress(userAddress) : 'Connect wallet'}
</button
>
</div>
</div>
- <!-- You can open the modal using ID.showModal() method -->
<dialog id="networkDetails" class="modal" open={networkModalOpen}>
<div class="modal-box ">
<button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2" on:click={() => networkModalOpen = false}>✕</button>
<h3 class="font-semibold text-lg">Network Details</h3>
<div class="divider my-1"></div>
- <div class="flex flex-row items-start gap-5 ">
+ <div class="flex flex-row items-start gap-5">
<div class="">
<p class="py-2 font-normal">Network Name</p>
<p class="py-2 font-normal">RPC Endpoint</p>
@@ -107,10 +161,34 @@
<p class="py-2 font-light">{$configuredChain.nativeCurrency.name}</p>
<p class="py-2 font-light">{$configuredChain.nativeCurrency.symbol}</p>
<p class="py-2 font-light">{$configuredChain.nativeCurrency.decimals}</p>
-
</div>
</div>
</div>
</dialog>
+
+ <dialog id="networkDetails" class="modal" open={tokenModalOpen}>
+ <div class="modal-box w-11/12">
+ <button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2" on:click={() => tokenModalOpen = false}>✕</button>
+ <h3 class="font-semibold text-lg">Token Vote Details</h3>
+ <div class="divider my-1"></div>
+ <ul>
+ <li class="font-normal">
+ Current Network: <span class="font-light">{$configuredChain.name}</span>
+ </li>
+ <li class="font-normal">
+ Your current balance: <span class="font-light">{balance ? formatEther(balance) : ''} {$configuredChain.nativeCurrency.symbol}</span>
+ </li>
+ <li class="font-normal">Vote Contract Address: <span class="font-light">{contractAddress}</span></li>
+ <li class="font-normal">
+ ERC20 Contract Address <span class="font-light">{erc20ContractAddress}</span>
+ </li>
+ <li class="font-normal">{name} Balance:
+ <span class="font-light">
+ {erc20Balance && decimals && `${formatUnits(erc20Balance, decimals)} ${symbol}`}
+ </span>
+ </li>
+ </ul>
+ </div>
+ </dialog>
</nav>
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
@@ -1,73 +1,47 @@
<script lang="ts">
- import { onMount } from 'svelte'
- import { formatEther, getContract, parseEther, type RequestAddressesReturnType, stringToHex } from 'viem'
+ import { getContract, parseEther, stringToHex } from 'viem'
import { walletClient, publicClient } from '../client'
import Nav from '../components/Nav.svelte'
import '../app.css'
import { PUBLIC_ERC20_CONTRACT_ADDRESS, PUBLIC_VOTE_CONTRACT_ADDRESS } from '$env/static/public'
- import { erc20TokenAbi, gitableAbi } from '../shared/erc20-token-abi'
+ import { erc20TokenAbi } from '../shared/erc20-token-abi'
import { voteContractAbi } from '../shared/token-vote-abi'
- import { configuredChain, votingConfig } from '../store'
-
- let userAddress: `0x${string}` | undefined
- let balance: bigint | undefined
- let isConnected: boolean = false
- // $configuredChain
-
- // console.log($configuredChain)
- configuredChain.subscribe(value => console.log(value))
- votingConfig.subscribe(value => console.log(value))
-
- const setup = async (accounts: RequestAddressesReturnType) => {
- userAddress = accounts[0]
- try {
- balance = await publicClient().getBalance({
- address: userAddress
- })
- isConnected = true
-
-
- } catch (error) {
- console.error(error)
- }
- }
-
- const connectWallet = async () => {
- if (window.ethereum) {
- const accounts = await walletClient().requestAddresses()
-
- if (accounts.length > 0) {
- await setup(accounts)
- }
- }
- }
+ import { configuredChain, connectionDetails, voteToken } from '../store'
const sendTransaction = async () => {
- if (!userAddress || !window.ethereum) return
- await walletClient().sendTransaction({
- account: userAddress,
+ if (!$connectionDetails.userAddress || !window.ethereum) return
+ await walletClient($configuredChain).sendTransaction({
+ account: $connectionDetails.userAddress,
to: '0x0000000000000000000000000000000000000000',
value: parseEther('0.000001')
})
}
- const checkBalance = async () => {
- if (!userAddress) return
-
- const ethBalance = await publicClient().getBalance({
- address: userAddress as `0x${string}`
- })
-
- console.log({ ethBalance })
-
- const contract = getContract({
- address: PUBLIC_ERC20_CONTRACT_ADDRESS as `0x${string}`,
- publicClient: publicClient(),
- walletClient: walletClient(),
- abi: erc20TokenAbi
- })
- const result = await contract.read.balanceOf([userAddress] as [`0x${string}`])
- console.log(result)
+ $: {
+ if ($connectionDetails.userAddress && configuredChain) {
+ const contract = getContract({
+ address: PUBLIC_ERC20_CONTRACT_ADDRESS as `0x${string}`,
+ publicClient: publicClient($configuredChain),
+ walletClient: walletClient($configuredChain),
+ abi: erc20TokenAbi
+ })
+
+ contract.read.balanceOf([$connectionDetails.userAddress] as [`0x${string}`])
+ .then(balance => voteToken.update(current => ({...current, balance })))
+ .catch(err => console.log(err))
+
+ contract.read.name()
+ .then(name => voteToken.update(current => ({...current, name })))
+ .catch(err => console.error(err))
+
+ contract.read.symbol()
+ .then(symbol => voteToken.update(current => ({...current, symbol })))
+ .catch(err => console.error(err))
+
+ contract.read.decimals()
+ .then(decimals => voteToken.update(current => ({...current, decimals })))
+ .catch(err => console.error(err))
+ }
}
const createProposal = async () => {
@@ -75,22 +49,22 @@
const blockWait = 100
const targetVote = 500000
- const { request } = await publicClient().simulateContract({
+ const { request } = await publicClient($configuredChain).simulateContract({
address: PUBLIC_VOTE_CONTRACT_ADDRESS as `0x${string}`,
abi: voteContractAbi,
functionName: 'propose',
args: [description, BigInt(blockWait), targetVote],
- account: userAddress
+ account: $connectionDetails.userAddress
})
- const result = await walletClient().writeContract(request)
+ const result = await walletClient($configuredChain).writeContract(request)
console.log(result)
}
const getCurrentProposal = async () => {
const contract = getContract({
address: PUBLIC_ERC20_CONTRACT_ADDRESS as `0x${string}`,
- publicClient: publicClient(),
- walletClient: walletClient(),
+ publicClient: publicClient($configuredChain),
+ walletClient: walletClient($configuredChain),
abi: voteContractAbi
})
const result = await contract.read.getProposal([BigInt(1)])
@@ -98,21 +72,11 @@
}
</script>
-<Nav on:click={connectWallet} />
-{#if isConnected}
- <p class="text-xl text-green-600">
- Successfully connected with account: <strong>{userAddress}</strong>
- </p>
- <button class="btn btn-sm" on:click={sendTransaction}>Send transaction</button>
- <button class="btn bt-sm" on:click={checkBalance}>Check balance</button>
- <button class="btn" on:click={createProposal}>Create proposal</button>
- <button class="btn" on:click={getCurrentProposal}>Get current proposal</button>
- <ul>
- <li>Current Network: {walletClient().chain.name}</li>
- <li>Your current balance: {balance && formatEther(balance)} eth</li>
- </ul>
-{:else}
- <button class="btn" on:click={connectWallet}>Connect with Wallet </button>
+<Nav />
+{#if $connectionDetails.isConnected}
+ <button class="btn mt-1" on:click={sendTransaction}>Send transaction</button>
+ <button class="btn mt-1" on:click={createProposal}>Create proposal</button>
+ <button class="btn mt-1" on:click={getCurrentProposal}>Get current proposal</button>
{/if}
<slot />
diff --git a/src/shared/types.ts b/src/shared/types.ts
@@ -5,5 +5,12 @@ export interface VotingConfig {
export interface ConnectionDetails {
isConnected: boolean
- userAddress: string
+ userAddress: `0x${string}`
+}
+
+export interface VoteToken {
+ balance: bigint
+ name: string
+ symbol: string
+ decimals: number
}
\ No newline at end of file
diff --git a/src/store.ts b/src/store.ts
@@ -11,7 +11,7 @@ import {
PUBLIC_VOTE_CONTRACT_ADDRESS,
PUBLIC_ERC20_CONTRACT_ADDRESS
} from '$env/static/public'
-import type { ConnectionDetails, VotingConfig } from './shared/types'
+import type { VoteToken, ConnectionDetails, VotingConfig } from './shared/types'
import { LOCAL_STORAGE_KEYS } from './shared/localstorage-keys'
const createChain = () => {
@@ -40,7 +40,6 @@ const createChain = () => {
if (browser) {
localValue = JSON.parse(localStorage.getItem(LOCAL_STORAGE_KEYS.CHAIN_CONFIG) || '{}')
}
- console.log({localValue})
const { subscribe, update } = writable<Chain>(localValue || initialChain)
@@ -76,7 +75,20 @@ export const createVotingConfig = () => {
export const createConnectionDetails = () => {
const { subscribe, update } = writable<ConnectionDetails>({
isConnected: false,
- userAddress: ''
+ userAddress: '' as `0x${string}`
+ })
+
+ return {
+ subscribe,
+ update
+ }
+}
+export const createVoteToken = () => {
+ const { subscribe, update } = writable<VoteToken>({
+ name: '',
+ symbol: '',
+ decimals: 0,
+ balance: BigInt(0)
})
return {
@@ -88,3 +100,4 @@ export const createConnectionDetails = () => {
export const configuredChain = createChain()
export const votingConfig = createVotingConfig()
export const connectionDetails = createConnectionDetails()
+export const voteToken = createVoteToken()
diff --git a/src/utils/amout.ts b/src/utils/amout.ts