Use user tokens (#72)

This commit is contained in:
Szymon Szlachtowicz 2021-09-15 00:47:14 +02:00 committed by GitHub
parent 983f557fbc
commit 5acbc88487
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 292 additions and 231 deletions

View File

@ -1,27 +1,179 @@
[
{ {
"contractName": "ERC20", "constant": true,
"abi": [ "inputs": [],
"name": "name",
"outputs": [
{ {
"anonymous": false, "name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [ "inputs": [
{ {
"indexed": true, "name": "_spender",
"name": "from",
"type": "address" "type": "address"
}, },
{ {
"indexed": true, "name": "_value",
"name": "to",
"type": "address"
},
{
"indexed": false,
"name": "value",
"type": "uint256" "type": "uint256"
} }
], ],
"name": "Transfer", "name": "approve",
"type": "event" "outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_from",
"type": "address"
},
{
"name": "_to",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transferFrom",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "decimals",
"outputs": [
{
"name": "",
"type": "uint8"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"name": "balance",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [],
"name": "symbol",
"outputs": [
{
"name": "",
"type": "string"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "_to",
"type": "address"
},
{
"name": "_value",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "_owner",
"type": "address"
},
{
"name": "_spender",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"payable": true,
"stateMutability": "payable",
"type": "fallback"
}, },
{ {
"anonymous": false, "anonymous": false,
@ -46,185 +198,25 @@
"type": "event" "type": "event"
}, },
{ {
"constant": true, "anonymous": false,
"inputs": [],
"name": "totalSupply",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "owner",
"type": "address"
}
],
"name": "balanceOf",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": true,
"inputs": [
{
"name": "owner",
"type": "address"
},
{
"name": "spender",
"type": "address"
}
],
"name": "allowance",
"outputs": [
{
"name": "",
"type": "uint256"
}
],
"payable": false,
"stateMutability": "view",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "to",
"type": "address"
},
{
"name": "value",
"type": "uint256"
}
],
"name": "transfer",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "spender",
"type": "address"
},
{
"name": "value",
"type": "uint256"
}
],
"name": "approve",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [ "inputs": [
{ {
"indexed": true,
"name": "from", "name": "from",
"type": "address" "type": "address"
}, },
{ {
"indexed": true,
"name": "to", "name": "to",
"type": "address" "type": "address"
}, },
{ {
"indexed": false,
"name": "value", "name": "value",
"type": "uint256" "type": "uint256"
} }
], ],
"name": "transferFrom", "name": "Transfer",
"outputs": [ "type": "event"
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "spender",
"type": "address"
},
{
"name": "addedValue",
"type": "uint256"
}
],
"name": "increaseAllowance",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
},
{
"constant": false,
"inputs": [
{
"name": "spender",
"type": "address"
},
{
"name": "subtractedValue",
"type": "uint256"
}
],
"name": "decreaseAllowance",
"outputs": [
{
"name": "",
"type": "bool"
}
],
"payable": false,
"stateMutability": "nonpayable",
"type": "function"
}
],
"bytecode": "0x608060405234801561001057600080fd5b506105dd806100206000396000f3fe608060405234801561001057600080fd5b50600436106100a5576000357c01000000000000000000000000000000000000000000000000000000009004806370a082311161007857806370a0823114610166578063a457c2d71461018c578063a9059cbb146101b8578063dd62ed3e146101e4576100a5565b8063095ea7b3146100aa57806318160ddd146100ea57806323b872dd14610104578063395093511461013a575b600080fd5b6100d6600480360360408110156100c057600080fd5b50600160a060020a038135169060200135610212565b604080519115158252519081900360200190f35b6100f2610290565b60408051918252519081900360200190f35b6100d66004803603606081101561011a57600080fd5b50600160a060020a03813581169160208101359091169060400135610296565b6100d66004803603604081101561015057600080fd5b50600160a060020a03813516906020013561035f565b6100f26004803603602081101561017c57600080fd5b5035600160a060020a031661040f565b6100d6600480360360408110156101a257600080fd5b50600160a060020a03813516906020013561042a565b6100d6600480360360408110156101ce57600080fd5b50600160a060020a038135169060200135610475565b6100f2600480360360408110156101fa57600080fd5b50600160a060020a038135811691602001351661048b565b6000600160a060020a038316151561022957600080fd5b336000818152600160209081526040808320600160a060020a03881680855290835292819020869055805186815290519293927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a350600192915050565b60025490565b600160a060020a03831660009081526001602090815260408083203384529091528120546102ca908363ffffffff6104b616565b600160a060020a03851660009081526001602090815260408083203384529091529020556102f98484846104cb565b600160a060020a0384166000818152600160209081526040808320338085529083529281902054815190815290519293927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060019392505050565b6000600160a060020a038316151561037657600080fd5b336000908152600160209081526040808320600160a060020a03871684529091529020546103aa908363ffffffff61059816565b336000818152600160209081526040808320600160a060020a0389168085529083529281902085905580519485525191937f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929081900390910190a350600192915050565b600160a060020a031660009081526020819052604090205490565b6000600160a060020a038316151561044157600080fd5b336000908152600160209081526040808320600160a060020a03871684529091529020546103aa908363ffffffff6104b616565b60006104823384846104cb565b50600192915050565b600160a060020a03918216600090815260016020908152604080832093909416825291909152205490565b6000828211156104c557600080fd5b50900390565b600160a060020a03821615156104e057600080fd5b600160a060020a038316600090815260208190526040902054610509908263ffffffff6104b616565b600160a060020a03808516600090815260208190526040808220939093559084168152205461053e908263ffffffff61059816565b600160a060020a038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b6000828201838110156105aa57600080fd5b939250505056fea165627a7a72305820722c0187518ce2856a424bdba350d5a263c8f98fcb19cb4cc161372bc3b794c90029",
"deployedBytecode": "0x608060405234801561001057600080fd5b50600436106100a5576000357c01000000000000000000000000000000000000000000000000000000009004806370a082311161007857806370a0823114610166578063a457c2d71461018c578063a9059cbb146101b8578063dd62ed3e146101e4576100a5565b8063095ea7b3146100aa57806318160ddd146100ea57806323b872dd14610104578063395093511461013a575b600080fd5b6100d6600480360360408110156100c057600080fd5b50600160a060020a038135169060200135610212565b604080519115158252519081900360200190f35b6100f2610290565b60408051918252519081900360200190f35b6100d66004803603606081101561011a57600080fd5b50600160a060020a03813581169160208101359091169060400135610296565b6100d66004803603604081101561015057600080fd5b50600160a060020a03813516906020013561035f565b6100f26004803603602081101561017c57600080fd5b5035600160a060020a031661040f565b6100d6600480360360408110156101a257600080fd5b50600160a060020a03813516906020013561042a565b6100d6600480360360408110156101ce57600080fd5b50600160a060020a038135169060200135610475565b6100f2600480360360408110156101fa57600080fd5b50600160a060020a038135811691602001351661048b565b6000600160a060020a038316151561022957600080fd5b336000818152600160209081526040808320600160a060020a03881680855290835292819020869055805186815290519293927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a350600192915050565b60025490565b600160a060020a03831660009081526001602090815260408083203384529091528120546102ca908363ffffffff6104b616565b600160a060020a03851660009081526001602090815260408083203384529091529020556102f98484846104cb565b600160a060020a0384166000818152600160209081526040808320338085529083529281902054815190815290519293927f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929181900390910190a35060019392505050565b6000600160a060020a038316151561037657600080fd5b336000908152600160209081526040808320600160a060020a03871684529091529020546103aa908363ffffffff61059816565b336000818152600160209081526040808320600160a060020a0389168085529083529281902085905580519485525191937f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925929081900390910190a350600192915050565b600160a060020a031660009081526020819052604090205490565b6000600160a060020a038316151561044157600080fd5b336000908152600160209081526040808320600160a060020a03871684529091529020546103aa908363ffffffff6104b616565b60006104823384846104cb565b50600192915050565b600160a060020a03918216600090815260016020908152604080832093909416825291909152205490565b6000828211156104c557600080fd5b50900390565b600160a060020a03821615156104e057600080fd5b600160a060020a038316600090815260208190526040902054610509908263ffffffff6104b616565b600160a060020a03808516600090815260208190526040808220939093559084168152205461053e908263ffffffff61059816565b600160a060020a038084166000818152602081815260409182902094909455805185815290519193928716927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef92918290030190a3505050565b6000828201838110156105aa57600080fd5b939250505056fea165627a7a72305820722c0187518ce2856a424bdba350d5a263c8f98fcb19cb4cc161372bc3b794c90029",
"compiler": {
"name": "solc",
"version": "0.5.4+commit.9549d8ff.Emscripten.clang"
}
} }
]

View File

@ -25,12 +25,13 @@ type WakuMessageStores = {
export class WakuMessaging { export class WakuMessaging {
protected appName: string protected appName: string
protected waku: Waku | undefined protected waku: Waku | undefined
public tokenAddress: string protected token: Contract
protected provider: Provider protected provider: Provider
protected chainId = 0 protected chainId = 0
protected wakuMessages: WakuMessageStores = {} protected wakuMessages: WakuMessageStores = {}
protected observers: { callback: (msg: WakuMessage) => void; topics: string[] }[] = [] protected observers: { callback: (msg: WakuMessage) => void; topics: string[] }[] = []
protected multicall: Contract protected multicall: Contract
public tokenDecimals: number | undefined
protected constructor( protected constructor(
appName: string, appName: string,
@ -41,10 +42,10 @@ export class WakuMessaging {
waku?: Waku waku?: Waku
) { ) {
this.appName = appName this.appName = appName
this.tokenAddress = tokenAddress
this.waku = waku this.waku = waku
this.provider = provider this.provider = provider
this.chainId = chainId this.chainId = chainId
this.token = new Contract(tokenAddress, ERC20, this.provider)
this.multicall = new Contract(multicall, ABI, this.provider) this.multicall = new Contract(multicall, ABI, this.provider)
} }
@ -54,6 +55,8 @@ export class WakuMessaging {
} }
protected async setObserver() { protected async setObserver() {
this.tokenDecimals = await this.token.decimals()
this.waku = await createWaku(this.waku) this.waku = await createWaku(this.waku)
await Promise.all( await Promise.all(
Object.values(this.wakuMessages).map(async (msgObj) => { Object.values(this.wakuMessages).map(async (msgObj) => {
@ -100,7 +103,7 @@ export class WakuMessaging {
} }
} }
protected addressesBalances: { [address: string]: BigNumber } = {} protected addressesBalances: { [address: string]: BigNumber | undefined } = {}
protected lastBlockBalances = 0 protected lastBlockBalances = 0
protected async updateBalances(newAddress?: string) { protected async updateBalances(newAddress?: string) {
@ -136,18 +139,27 @@ export class WakuMessaging {
const addressesToUpdateArray = Object.keys(addressesToUpdate) const addressesToUpdateArray = Object.keys(addressesToUpdate)
if (addressesToUpdateArray.length > 0) { if (addressesToUpdateArray.length > 0) {
const erc20 = new Interface(ERC20.abi) const erc20 = this.token.interface
const callData = addressesToUpdateArray.map((addr) => { const callData = addressesToUpdateArray.map((addr) => {
return [this.tokenAddress, erc20.encodeFunctionData('balanceOf', [addr])] return [this.token.address, erc20.encodeFunctionData('balanceOf', [addr])]
})
const result = (await this.multicall.aggregate(callData))[1].map((data: any) => {
try {
return erc20.decodeFunctionResult('balanceOf', data)
} catch {
return undefined
}
}) })
const result = (await this.multicall.aggregate(callData))[1].map((data: any) =>
erc20.decodeFunctionResult('balanceOf', data)
)
result.forEach((e: any, idx: number) => { result.forEach((e: any, idx: number) => {
this.addressesBalances[addressesToUpdateArray[idx]] = e[0] this.addressesBalances[addressesToUpdateArray[idx]] = e ? e[0] : undefined
}) })
this.lastBlockBalances = currentBlock this.lastBlockBalances = currentBlock
} }
} }
public async getTokenBalance(address: string) {
await this.updateBalances(address)
return this.addressesBalances[address] ?? undefined
}
} }

View File

@ -7,13 +7,16 @@ import { NotificationItem } from './NotificationItem'
import { WakuVoting } from '@status-waku-voting/core' import { WakuVoting } from '@status-waku-voting/core'
import { VotingEmpty } from './VotingEmpty' import { VotingEmpty } from './VotingEmpty'
import { VotingRoom } from '@status-waku-voting/core/dist/esm/src/types/PollType' import { VotingRoom } from '@status-waku-voting/core/dist/esm/src/types/PollType'
import { useTokenBalance } from '@status-waku-voting/react-components'
type ProposalProps = { type ProposalProps = {
wakuVoting: WakuVoting wakuVoting: WakuVoting
account: string | null | undefined
} }
export function Proposal({ wakuVoting }: ProposalProps) { export function Proposal({ wakuVoting, account }: ProposalProps) {
const [votes, setVotes] = useState<VotingRoom[]>([]) const [votes, setVotes] = useState<VotingRoom[]>([])
const tokenBalance = useTokenBalance(account, wakuVoting)
useEffect(() => { useEffect(() => {
const interval = setInterval(async () => { const interval = setInterval(async () => {
@ -26,11 +29,11 @@ export function Proposal({ wakuVoting }: ProposalProps) {
return ( return (
<ProposalWrapper> <ProposalWrapper>
{votes && votes?.length === 0 ? ( {votes && votes?.length === 0 ? (
<VotingEmpty wakuVoting={wakuVoting} theme={blueTheme} /> <VotingEmpty wakuVoting={wakuVoting} theme={blueTheme} availableAmount={tokenBalance} />
) : ( ) : (
<ProposalVotesWrapper> <ProposalVotesWrapper>
<ProposalHeader theme={blueTheme} wakuVoting={wakuVoting} /> <ProposalHeader theme={blueTheme} wakuVoting={wakuVoting} availableAmount={tokenBalance} />
<ProposalList theme={blueTheme} wakuVoting={wakuVoting} votes={votes} /> <ProposalList theme={blueTheme} wakuVoting={wakuVoting} votes={votes} availableAmount={tokenBalance} />
</ProposalVotesWrapper> </ProposalVotesWrapper>
)} )}

View File

@ -11,15 +11,16 @@ interface ProposalCardProps {
mobileVersion?: boolean mobileVersion?: boolean
theme: Theme theme: Theme
hideModalFunction?: (val: boolean) => void hideModalFunction?: (val: boolean) => void
availableAmount: number
} }
export function ProposalCard({ theme, votingRoom, mobileVersion }: ProposalCardProps) { export function ProposalCard({ theme, votingRoom, mobileVersion, availableAmount }: ProposalCardProps) {
const history = useHistory() const history = useHistory()
return ( return (
<Card onClick={() => mobileVersion && history.push(`/votingRoom/${votingRoom.id.toString()}`)}> <Card onClick={() => mobileVersion && history.push(`/votingRoom/${votingRoom.id.toString()}`)}>
<ProposalInfo votingRoom={votingRoom} /> <ProposalInfo votingRoom={votingRoom} />
<ProposalVote votingRoom={votingRoom} theme={theme} /> <ProposalVote votingRoom={votingRoom} theme={theme} availableAmount={availableAmount} />
</Card> </Card>
) )
} }

View File

@ -11,9 +11,10 @@ import { BigNumber } from 'ethers'
type ProposalHeaderProps = { type ProposalHeaderProps = {
theme: Theme theme: Theme
wakuVoting: WakuVoting wakuVoting: WakuVoting
availableAmount: number
} }
export function ProposalHeader({ theme, wakuVoting }: ProposalHeaderProps) { export function ProposalHeader({ theme, wakuVoting, availableAmount }: ProposalHeaderProps) {
const { activateBrowserWallet, account, library } = useEthers() const { activateBrowserWallet, account, library } = useEthers()
const [selectConnect, setSelectConnect] = useState(false) const [selectConnect, setSelectConnect] = useState(false)
const [showProposeModal, setShowProposeModal] = useState(false) const [showProposeModal, setShowProposeModal] = useState(false)
@ -41,7 +42,7 @@ export function ProposalHeader({ theme, wakuVoting }: ProposalHeaderProps) {
text={text} text={text}
setText={setText} setText={setText}
setTitle={setTitle} setTitle={setTitle}
availableAmount={6524354} availableAmount={availableAmount}
setShowProposeVoteModal={setNext} setShowProposeVoteModal={setNext}
/> />
</Modal> </Modal>
@ -52,7 +53,7 @@ export function ProposalHeader({ theme, wakuVoting }: ProposalHeaderProps) {
wakuVoting={wakuVoting} wakuVoting={wakuVoting}
title={title} title={title}
text={text} text={text}
availableAmount={6524354} availableAmount={availableAmount}
setShowModal={setShowProposeVoteModal} setShowModal={setShowProposeVoteModal}
setText={setText} setText={setText}
setTitle={setTitle} setTitle={setTitle}

View File

@ -10,14 +10,23 @@ type ProposalListProps = {
theme: Theme theme: Theme
wakuVoting: WakuVoting wakuVoting: WakuVoting
votes: VotingRoom[] votes: VotingRoom[]
availableAmount: number
} }
export function ProposalList({ theme, wakuVoting, votes }: ProposalListProps) { export function ProposalList({ theme, wakuVoting, votes, availableAmount }: ProposalListProps) {
const ref = useRef<HTMLHeadingElement>(null) const ref = useRef<HTMLHeadingElement>(null)
const mobileVersion = useMobileVersion(ref, 600) const mobileVersion = useMobileVersion(ref, 600)
return ( return (
<List ref={ref}> <List ref={ref}>
{votes.map((votingRoom) => { {votes.map((votingRoom) => {
return <ProposalCard votingRoom={votingRoom} theme={theme} key={votingRoom.id} mobileVersion={mobileVersion} /> return (
<ProposalCard
votingRoom={votingRoom}
theme={theme}
key={votingRoom.id}
mobileVersion={mobileVersion}
availableAmount={availableAmount}
/>
)
})} })}
</List> </List>
) )

View File

@ -13,10 +13,11 @@ import { VotingRoom } from '@status-waku-voting/core/dist/esm/src/types/PollType
interface ProposalVoteProps { interface ProposalVoteProps {
theme: Theme theme: Theme
votingRoom: VotingRoom votingRoom: VotingRoom
availableAmount: number
hideModalFunction?: (val: boolean) => void hideModalFunction?: (val: boolean) => void
} }
export function ProposalVote({ votingRoom, theme, hideModalFunction }: ProposalVoteProps) { export function ProposalVote({ votingRoom, theme, availableAmount, hideModalFunction }: ProposalVoteProps) {
const { account } = useEthers() const { account } = useEthers()
const [showVoteModal, setShowVoteModal] = useState(false) const [showVoteModal, setShowVoteModal] = useState(false)
const [showConfirmModal, setShowConfirmModal] = useState(false) const [showConfirmModal, setShowConfirmModal] = useState(false)
@ -41,7 +42,7 @@ export function ProposalVote({ votingRoom, theme, hideModalFunction }: ProposalV
<Modal heading={votingRoom.question} setShowModal={setShowVoteModal} theme={theme}> <Modal heading={votingRoom.question} setShowModal={setShowVoteModal} theme={theme}>
<VoteModal <VoteModal
votingRoom={votingRoom} votingRoom={votingRoom}
availableAmount={65245346} availableAmount={availableAmount}
selectedVote={selectedVoted} selectedVote={selectedVoted}
proposingAmount={proposingAmount} proposingAmount={proposingAmount}
setShowConfirmModal={setNext} setShowConfirmModal={setNext}

View File

@ -3,6 +3,7 @@ import styled from 'styled-components'
import { ProposingBtn } from './Buttons' import { ProposingBtn } from './Buttons'
import { TextArea } from './Input' import { TextArea } from './Input'
import { blueTheme } from '@status-waku-voting/react-components/dist/esm/src/style/themes' import { blueTheme } from '@status-waku-voting/react-components/dist/esm/src/style/themes'
import { BigNumber } from 'ethers'
interface ProposeModalProps { interface ProposeModalProps {
availableAmount: number availableAmount: number

View File

@ -10,9 +10,10 @@ import { WakuVoting } from '@status-waku-voting/core'
type VotingEmptyProps = { type VotingEmptyProps = {
theme: Theme theme: Theme
wakuVoting: WakuVoting wakuVoting: WakuVoting
availableAmount: number
} }
export function VotingEmpty({ wakuVoting, theme }: VotingEmptyProps) { export function VotingEmpty({ wakuVoting, theme, availableAmount }: VotingEmptyProps) {
const { account, activateBrowserWallet } = useEthers() const { account, activateBrowserWallet } = useEthers()
const [selectConnect, setSelectConnect] = useState(false) const [selectConnect, setSelectConnect] = useState(false)
const [showProposeModal, setShowProposeModal] = useState(false) const [showProposeModal, setShowProposeModal] = useState(false)
@ -45,7 +46,7 @@ export function VotingEmpty({ wakuVoting, theme }: VotingEmptyProps) {
text={text} text={text}
setText={setText} setText={setText}
setTitle={setTitle} setTitle={setTitle}
availableAmount={6524354} availableAmount={availableAmount}
setShowProposeVoteModal={setNext} setShowProposeVoteModal={setNext}
/> />
</Modal> </Modal>
@ -56,7 +57,7 @@ export function VotingEmpty({ wakuVoting, theme }: VotingEmptyProps) {
wakuVoting={wakuVoting} wakuVoting={wakuVoting}
title={title} title={title}
text={text} text={text}
availableAmount={6524354} availableAmount={availableAmount}
setShowModal={setShowProposeVoteModal} setShowModal={setShowProposeVoteModal}
setText={setText} setText={setText}
setTitle={setTitle} setTitle={setTitle}

View File

@ -11,9 +11,10 @@ import { VotingRoom } from '@status-waku-voting/core/dist/esm/src/types/PollType
type ProposalMainMobileProps = { type ProposalMainMobileProps = {
wakuVoting: WakuVoting wakuVoting: WakuVoting
availableAmount: number
} }
export function ProposalMainMobile({ wakuVoting }: ProposalMainMobileProps) { export function ProposalMainMobile({ wakuVoting, availableAmount }: ProposalMainMobileProps) {
const [votes, setVotes] = useState<VotingRoom[]>([]) const [votes, setVotes] = useState<VotingRoom[]>([])
useEffect(() => { useEffect(() => {
@ -26,11 +27,11 @@ export function ProposalMainMobile({ wakuVoting }: ProposalMainMobileProps) {
return ( return (
<ProposalWrapper> <ProposalWrapper>
{votes && votes?.length === 0 ? ( {votes && votes?.length === 0 ? (
<VotingEmpty wakuVoting={wakuVoting} theme={blueTheme} /> <VotingEmpty wakuVoting={wakuVoting} theme={blueTheme} availableAmount={availableAmount} />
) : ( ) : (
<ProposalVotesWrapper> <ProposalVotesWrapper>
<ProposalHeaderMobile theme={blueTheme} /> <ProposalHeaderMobile theme={blueTheme} />
<ProposalList theme={blueTheme} wakuVoting={wakuVoting} votes={votes} /> <ProposalList theme={blueTheme} wakuVoting={wakuVoting} votes={votes} availableAmount={availableAmount} />
</ProposalVotesWrapper> </ProposalVotesWrapper>
)} )}
<NotificationItem text={'Proposal you finalized will be settled after 10 confirmations.'} address={'#'} /> <NotificationItem text={'Proposal you finalized will be settled after 10 confirmations.'} address={'#'} />

View File

@ -6,23 +6,28 @@ import { ProposalVoteMobile } from './ProposalVoteMobile'
import { ProposeMobile } from './ProposeMobile' import { ProposeMobile } from './ProposeMobile'
import { ProposalMainMobile } from './ProposalMainMobile' import { ProposalMainMobile } from './ProposalMainMobile'
import { WakuVoting } from '@status-waku-voting/core' import { WakuVoting } from '@status-waku-voting/core'
import { useTokenBalance } from '@status-waku-voting/react-components'
type ProposalMobileProps = { type ProposalMobileProps = {
wakuVoting: WakuVoting wakuVoting: WakuVoting
account: string | null | undefined
} }
export function ProposalMobile({ wakuVoting }: ProposalMobileProps) { export function ProposalMobile({ wakuVoting, account }: ProposalMobileProps) {
const tokenBalance = useTokenBalance(account, wakuVoting)
return ( return (
<BrowserRouter> <BrowserRouter>
<ProposalWrapper> <ProposalWrapper>
<Switch> <Switch>
<Route exact path="/" render={() => <Redirect to="/proposal" />} /> <Route exact path="/" render={() => <Redirect to="/proposal" />} />
<Route exact path="/votingRoom/:id"> <Route exact path="/votingRoom/:id">
<ProposalVoteMobile wakuVoting={wakuVoting} availableAmount={123} /> <ProposalVoteMobile wakuVoting={wakuVoting} availableAmount={tokenBalance} />
</Route>
<Route exact path="/creation">
<ProposeMobile availableAmount={tokenBalance} />
</Route> </Route>
<Route exact path="/creation" component={ProposeMobile} />
<Route exact path="/proposal"> <Route exact path="/proposal">
<ProposalMainMobile wakuVoting={wakuVoting} /> <ProposalMainMobile wakuVoting={wakuVoting} availableAmount={tokenBalance} />
</Route> </Route>
</Switch> </Switch>
</ProposalWrapper> </ProposalWrapper>

View File

@ -36,7 +36,7 @@ export function ProposalVoteMobile({ wakuVoting, availableAmount }: ProposalVote
</VoteChartWrap> </VoteChartWrap>
{!voteWinner && ( {!voteWinner && (
<VotePropose <VotePropose
availableAmount={65245346} availableAmount={availableAmount}
setProposingAmount={setProposingAmount} setProposingAmount={setProposingAmount}
proposingAmount={proposingAmount} proposingAmount={proposingAmount}
/> />

View File

@ -75,7 +75,7 @@ export function ProposeMobile({ availableAmount }: ProposeVoteModalProps) {
<VoteProposeWrap> <VoteProposeWrap>
<VotePropose <VotePropose
availableAmount={65245555} availableAmount={availableAmount}
setProposingAmount={setProposingAmount} setProposingAmount={setProposingAmount}
proposingAmount={proposingAmount} proposingAmount={proposingAmount}
/> />

View File

@ -40,7 +40,12 @@ function Proposals() {
account={account} account={account}
deactivate={deactivate} deactivate={deactivate}
/> />
{waku && (mobileVersion ? <ProposalMobile wakuVoting={waku} /> : <Proposal wakuVoting={waku} />)} {waku &&
(mobileVersion ? (
<ProposalMobile wakuVoting={waku} account={account} />
) : (
<Proposal wakuVoting={waku} account={account} />
))}
</Wrapper> </Wrapper>
) )
} }

View File

@ -32,7 +32,8 @@
"dependencies": { "dependencies": {
"ethers": "^5.4.4", "ethers": "^5.4.4",
"react": "^17.0.2", "react": "^17.0.2",
"styled-components": "^5.3.0" "styled-components": "^5.3.0",
"@status-waku-voting/core": "^0.1.0"
}, },
"devDependencies": { "devDependencies": {
"@types/chai": "^4.2.21", "@types/chai": "^4.2.21",

View File

@ -0,0 +1,26 @@
import { WakuMessaging } from '@status-waku-voting/core'
import { BigNumber } from 'ethers'
import React, { useEffect, useState } from 'react'
export function useTokenBalance(address: string | null | undefined, wakuVoting: WakuMessaging) {
const [tokenBalance, setTokenBalance] = useState(0)
useEffect(() => {
const updateBalances = async () => {
if (address) {
const tokenDecimals = wakuVoting.tokenDecimals
if (tokenDecimals) {
const balance = (await wakuVoting.getTokenBalance(address))?.div(BigNumber.from(10).pow(tokenDecimals))
if (balance && !balance.eq(tokenBalance)) {
setTokenBalance(balance.toNumber())
}
}
}
}
setTimeout(updateBalances, 1000)
const interval = setInterval(updateBalances, 10000)
return () => clearInterval(interval)
}, [address])
return tokenBalance
}

View File

@ -16,7 +16,9 @@ import statusIcon from './assets/svg/status.svg'
import themes, { Theme } from './style/themes' import themes, { Theme } from './style/themes'
import { useRefSize } from './hooks/useRefSize' import { useRefSize } from './hooks/useRefSize'
import { useMobileVersion } from './hooks/useMobileVersion' import { useMobileVersion } from './hooks/useMobileVersion'
import { useTokenBalance } from './hooks/useTokenBalance'
export { export {
useTokenBalance,
useMobileVersion, useMobileVersion,
useRefSize, useRefSize,
Modal, Modal,