Skip to content

Commit

Permalink
Merge pull request #128 from DA0-DA0/staking-ui
Browse files Browse the repository at this point in the history
Staking UI
  • Loading branch information
JakeHartnell authored Dec 20, 2021
2 parents a7d74ff + 8bed286 commit 9575bfe
Show file tree
Hide file tree
Showing 10 changed files with 391 additions and 38 deletions.
28 changes: 28 additions & 0 deletions components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react'
import TwitterLogo from 'components/TwitterLogo'
import GitHubLogo from 'components/GitHubLogo'

const POWERED_BY_URL = 'https://junonetwork.io'
const TWITTER_URL = 'https://twitter.com/da0_da0'
const GITHUB_URL = 'https://github.com/DA0-DA0'

export default function Footer() {
return (
<footer className="border-t w-full h-24 flex align-center justify-center flex-col">
<div className="flex items-center justify-center w-full">
Powered by{' '}
<a className="pl-1 link link-primary link-hover" href={POWERED_BY_URL}>
<div>Juno</div>
</a>
</div>
<div className="flex items-center justify-center w-full">
<a href={TWITTER_URL}>
<TwitterLogo />
</a>
<a href={GITHUB_URL}>
<GitHubLogo />
</a>
</div>
</footer>
)
}
27 changes: 2 additions & 25 deletions components/Layout.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
import { ReactNode } from 'react'
import Head from 'next/head'
import Footer from './Footer'
import Nav from './Nav'
import TwitterLogo from 'components/TwitterLogo'
import GitHubLogo from 'components/GitHubLogo'

const PUBLIC_SITE_TITLE = process.env.NEXT_PUBLIC_SITE_TITLE

const POWERED_BY_URL = 'https://junonetwork.io'
const TWITTER_URL = 'https://twitter.com/da0_da0'
const GITHUB_URL = 'https://github.com/DA0-DA0'

export default function Layout({ children }: { children: ReactNode }) {
return (
<div className="flex flex-col items-center justify-center min-h-screen bg-base-100 text-base-content">
Expand All @@ -23,25 +18,7 @@ export default function Layout({ children }: { children: ReactNode }) {
<main className="flex flex-col items-center justify-center w-full flex-1 p-2 md:px-20 text-center">
{children}
</main>
<footer className="border-t w-full h-24 flex align-center justify-center flex-col">
<div className="flex items-center justify-center w-full">
Powered by{' '}
<a
className="pl-1 link link-primary link-hover"
href={POWERED_BY_URL}
>
<div>Juno</div>
</a>
</div>
<div className="flex items-center justify-center w-full">
<a href={TWITTER_URL}>
<TwitterLogo />
</a>
<a href={GITHUB_URL}>
<GitHubLogo />
</a>
</div>
</footer>
<Footer />
</div>
)
}
2 changes: 1 addition & 1 deletion components/TokenBalances.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Cw20CoinVerified } from '@dao-dao/types/contracts/cw3-dao'
import TokenBalance from 'components/TokenBalance'
import Cw20TokenBalance from 'components/Cw20TokenBalance'

function TokenBalances({
export function TokenBalances({
native,
cw20Balances,
}: {
Expand Down
48 changes: 48 additions & 0 deletions hooks/cw20.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { useState, useEffect } from 'react'
import { useSigningClient } from 'contexts/cosmwasm'
import { BalanceResponse } from '@dao-dao/types/contracts/cw20-gov/balance_response'
import { TokenInfoResponse } from '@dao-dao/types/contracts/cw20-gov/token_info_response'

// Returns cw20 balance info for the connected wallet
export function useCw20WalletBalance(contractAddress: string) {
const [error, setError] = useState<Error | null>(null)
const [loading, setLoading] = useState(false)
const { walletAddress, signingClient } = useSigningClient()
const [balance, setBalance] = useState<BalanceResponse | null>(null)
const [tokenInfo, setTokenInfo] = useState<TokenInfoResponse | null>(null)

useEffect(() => {
if (walletAddress.length === 0 || !signingClient) {
return
}
setLoading(true)
Promise.all([
signingClient?.queryContractSmart(contractAddress, {
balance: {
address: walletAddress,
},
}),
signingClient.queryContractSmart(contractAddress, {
token_info: {},
}),
])
.then((values) => {
const [balance, tokenInfo] = values
setBalance(balance)
setTokenInfo(tokenInfo)
setLoading(false)
})
.catch((e) => {
setError(e.msg)
setLoading(false)
})
}, [contractAddress, signingClient, walletAddress])

return {
walletAddress,
loading,
error,
balance,
tokenInfo,
}
}
12 changes: 9 additions & 3 deletions hooks/proposals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@ import { memoForProposal, Proposal } from 'models/proposal/proposal'
import { messageForProposal } from 'models/proposal/proposalSelectors'
import { defaultExecuteFee } from 'util/fee'

// Returns a list of proposals and pagination methods
export function useProposals(contractAddress: string) {
const { walletAddress, signingClient } = useSigningClient()
const [error, setError] = useState<Error | null>(null)
const [loading, setLoading] = useState(false)
const [proposals, setProposals] = useState<ProposalResponse[]>([])
const [hideLoadMore, setHideLoadMore] = useState(false)
const [loading, setLoading] = useState(false)
const [startBefore, setStartBefore] = useState<number | null>(null)

useEffect(() => {
Expand All @@ -42,21 +44,23 @@ export function useProposals(contractAddress: string) {
}
setProposals((p) => p.concat(response.proposals))
} catch (err) {
setError(err)
setLoading(false)
}
}
sign(signingClient)
}, [walletAddress, signingClient, startBefore, contractAddress])
return { proposals, hideLoadMore, loading, setStartBefore }
return { proposals, hideLoadMore, loading, error, setStartBefore }
}

// Returns proposal info and associated contract methods
export function useProposal(contractAddress: string, proposalId: string) {
const { walletAddress, signingClient } = useSigningClient()
const [error, setError] = useState('')
const [loading, setLoading] = useState(false)
const [votes, setVotes] = useState<VoteInfo[]>([])
const [tally, setTally] = useState<ProposalTallyResponse>()
const [proposal, setProposal] = useState<ProposalResponse | null>(null)
const [error, setError] = useState('')
const [timestamp, setTimestamp] = useState(new Date())
const [transactionHash, setTransactionHash] = useState('')

Expand Down Expand Up @@ -166,6 +170,8 @@ export function useProposal(contractAddress: string, proposalId: string) {
}
}

// Returns an excute method used to create a proposal
// When a proposal is created, it returns a proposalID
export function useCreateProposal(contractAddress: string) {
const { walletAddress, signingClient } = useSigningClient()
const [error, setError] = useState('')
Expand Down
158 changes: 158 additions & 0 deletions hooks/staking.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import { useState, useEffect } from 'react'
import { useSigningClient } from 'contexts/cosmwasm'
import { defaultExecuteFee } from 'util/fee'

// Returns staking info and methods for a cw20-stakable contract
export function useStaking(contractAddress: string) {
const { walletAddress, signingClient } = useSigningClient()
const [error, setError] = useState('')
const [loading, setLoading] = useState(false)

const [stakedBalance, setStakedBalance] = useState({ balance: '0' })
const [claims, setClaims] = useState()
const [delegation, setDelegation] = useState()
const [totalStaked, setTotalStaked] = useState({ total: '0' })

useEffect(() => {
if (walletAddress.length === 0 || !signingClient) {
return
}
setLoading(true)
Promise.all([
signingClient?.queryContractSmart(contractAddress, {
staked_balance_at_height: {
address: walletAddress,
},
}),
signingClient?.queryContractSmart(contractAddress, {
claims: {
address: walletAddress,
},
}),
signingClient?.queryContractSmart(contractAddress, {
delegation: {
address: walletAddress,
},
}),
signingClient?.queryContractSmart(contractAddress, {
total_staked_at_height: {},
}),
])
.then((values) => {
const [stakedBalance, claims, delegation, totalStaked] = values
setStakedBalance(stakedBalance)
setClaims(claims)
setTotalStaked(totalStaked)
setDelegation(delegation)
setLoading(false)
})
.catch((e) => {
setError(e.msg)
setLoading(false)
})
}, [contractAddress, signingClient, walletAddress])

const claim = async () => {
setError('')
await signingClient
?.execute(
walletAddress,
contractAddress,
{
claim: {},
},
defaultExecuteFee
)
.then((response) => {
console.log(response)
setLoading(false)
})
.catch((err) => {
setLoading(false)
setError(err.message)
})
}

const delegateVotes = async (recipient: string) => {
setError('')
await signingClient
?.execute(
walletAddress,
contractAddress,
{
delegate_votes: {
recipient,
},
},
defaultExecuteFee
)
.then((response) => {
console.log(response)
setLoading(false)
})
.catch((err) => {
setLoading(false)
setError(err.message)
})
}

const stake = async (amount: string) => {
setError('')
await signingClient
?.execute(
walletAddress,
contractAddress,
{
stake: {
amount,
},
},
defaultExecuteFee
)
.then((response) => {
console.log(response)
setLoading(false)
})
.catch((err) => {
setLoading(false)
setError(err.message)
})
}

const unstake = async (amount: string) => {
setError('')
await signingClient
?.execute(
walletAddress,
contractAddress,
{
unstake: {
amount,
},
},
defaultExecuteFee
)
.then((response) => {
console.log(response)
setLoading(false)
})
.catch((err) => {
setLoading(false)
setError(err.message)
})
}

return {
walletAddress,
loading,
error,
claim,
claims,
delegateVotes,
delegation,
stake,
stakedBalance,
totalStaked,
unstake,
}
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"dependencies": {
"@cosmjs/cosmwasm-stargate": "^0.27.0-rc2",
"@cosmjs/stargate": "^0.27.0-rc2",
"@dao-dao/types": "^0.0.2",
"@dao-dao/types": "^0.0.3",
"@heroicons/react": "^1.0.5",
"@types/react-json-editor-ajrm": "^2.5.2",
"daisyui": "^1.14.0",
Expand Down
14 changes: 10 additions & 4 deletions pages/dao/[contractAddress]/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import React, { useEffect, useState } from 'react'
import React, { useState } from 'react'
import { ChevronRightIcon } from '@heroicons/react/solid'
import WalletLoader from 'components/WalletLoader'
import { useSigningClient } from 'contexts/cosmwasm'
import { useDaoConfig } from 'hooks/dao'
import type { NextPage } from 'next'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { ConfigResponse } from '@dao-dao/types/contracts/cw3-dao'
import LinkCard from 'components/LinkCard'
import ClipboardText from 'components/ClipboardText'
import TrueFalseIndicator from 'components/TrueFalseIndicator'
import { useTokenConfig } from 'hooks/govToken'
import { convertMicroDenomToDenom } from 'util/conversion'

Expand Down Expand Up @@ -37,6 +34,15 @@ function actions(contractAddress: string) {
</h3>
<p className="mt-4 text-xl">Manage DAO finances.</p>
</LinkCard>
<LinkCard href={`/dao/${contractAddress}/staking`}>
<h3 className="text-2xl font-bold">
Staking{' '}
<ChevronRightIcon className="inline-block w-6 h-6 ml-2 stroke-current" />
</h3>
<p className="mt-4 text-xl">
Stake your tokens to vote and earn rewards.
</p>
</LinkCard>
</>
)
}
Expand Down
Loading

1 comment on commit 9575bfe

@vercel
Copy link

@vercel vercel bot commented on 9575bfe Dec 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.