Check token balance in polls (#51)
This commit is contained in:
parent
4815b994d4
commit
d51b69a6a1
|
@ -9,10 +9,26 @@ import { DetailedTimedPoll } from '../models/DetailedTimedPoll'
|
|||
import { createWaku } from '../utils/createWaku'
|
||||
import { WakuVoting } from './WakuVoting'
|
||||
import { Provider } from '@ethersproject/providers'
|
||||
import { Contract } from '@ethersproject/contracts'
|
||||
import { Interface } from '@ethersproject/abi'
|
||||
import { ERC20 } from '../abi'
|
||||
const ABI = [
|
||||
'function aggregate(tuple(address target, bytes callData)[] calls) view returns (uint256 blockNumber, bytes[] returnData)',
|
||||
]
|
||||
|
||||
export class WakuPolling extends WakuVoting {
|
||||
protected constructor(appName: string, tokenAddress: string, waku: Waku, provider: Provider, chainId: number) {
|
||||
protected multicall: string
|
||||
|
||||
protected constructor(
|
||||
appName: string,
|
||||
tokenAddress: string,
|
||||
waku: Waku,
|
||||
provider: Provider,
|
||||
chainId: number,
|
||||
multicall: string
|
||||
) {
|
||||
super(appName, tokenAddress, waku, provider, chainId)
|
||||
this.multicall = multicall
|
||||
this.wakuMessages['pollInit'] = {
|
||||
topic: `/${this.appName}/waku-polling/timed-polls-init/proto/`,
|
||||
hashMap: {},
|
||||
|
@ -35,9 +51,22 @@ export class WakuPolling extends WakuVoting {
|
|||
this.setObserver()
|
||||
}
|
||||
|
||||
public static async create(appName: string, tokenAddress: string, provider: Provider, waku?: Waku) {
|
||||
public static async create(
|
||||
appName: string,
|
||||
tokenAddress: string,
|
||||
provider: Provider,
|
||||
multicall: string,
|
||||
waku?: Waku
|
||||
) {
|
||||
const network = await provider.getNetwork()
|
||||
const wakuPolling = new WakuPolling(appName, tokenAddress, await createWaku(waku), provider, network.chainId)
|
||||
const wakuPolling = new WakuPolling(
|
||||
appName,
|
||||
tokenAddress,
|
||||
await createWaku(waku),
|
||||
provider,
|
||||
network.chainId,
|
||||
multicall
|
||||
)
|
||||
return wakuPolling
|
||||
}
|
||||
|
||||
|
@ -63,13 +92,75 @@ export class WakuPolling extends WakuVoting {
|
|||
await this.sendWakuMessage(this.wakuMessages['pollVote'], pollVote)
|
||||
}
|
||||
|
||||
protected addressesBalances: { [address: string]: BigNumber } = {}
|
||||
protected lastBlockBalances = 0
|
||||
|
||||
protected async updateBalances() {
|
||||
const addresses: string[] = [
|
||||
...this.wakuMessages['pollInit'].arr.map((msg) => msg.owner),
|
||||
...this.wakuMessages['pollVote'].arr.map((msg) => msg.voter),
|
||||
]
|
||||
const addressesToUpdate: { [addr: string]: boolean } = {}
|
||||
|
||||
const addAddressToUpdate = (addr: string) => {
|
||||
if (!addressesToUpdate[addr]) {
|
||||
addressesToUpdate[addr] = true
|
||||
}
|
||||
}
|
||||
|
||||
const currentBlock = await this.provider.getBlockNumber()
|
||||
if (this.lastBlockBalances != currentBlock) {
|
||||
Object.keys(this.addressesBalances).forEach(addAddressToUpdate)
|
||||
addresses.forEach(addAddressToUpdate)
|
||||
} else {
|
||||
addresses.forEach((address) => {
|
||||
if (!this.addressesBalances[address]) {
|
||||
addAddressToUpdate(address)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const addressesToUpdateArray = Object.keys(addressesToUpdate)
|
||||
if (addressesToUpdateArray.length > 0) {
|
||||
const erc20 = new Interface(ERC20.abi)
|
||||
const contract = new Contract(this.multicall, ABI, this.provider)
|
||||
const callData = addressesToUpdateArray.map((addr) => {
|
||||
return [this.tokenAddress, erc20.encodeFunctionData('balanceOf', [addr])]
|
||||
})
|
||||
const result = (await contract.aggregate(callData))[1].map((data: any) =>
|
||||
erc20.decodeFunctionResult('balanceOf', data)
|
||||
)
|
||||
|
||||
result.forEach((e: any, idx: number) => {
|
||||
this.addressesBalances[addressesToUpdateArray[idx]] = e[0]
|
||||
})
|
||||
this.lastBlockBalances = currentBlock
|
||||
}
|
||||
}
|
||||
|
||||
public async getDetailedTimedPolls() {
|
||||
return this.wakuMessages['pollInit'].arr.map(
|
||||
(poll) =>
|
||||
new DetailedTimedPoll(
|
||||
poll,
|
||||
this.wakuMessages['pollVote'].arr.filter((vote) => vote.pollId === poll.id)
|
||||
)
|
||||
)
|
||||
await this.updateBalances()
|
||||
return this.wakuMessages['pollInit'].arr
|
||||
.map((poll: PollInitMsg) => {
|
||||
if (
|
||||
this.addressesBalances[poll.owner] &&
|
||||
this.addressesBalances[poll.owner]?.gt(poll.minToken ?? BigNumber.from(0))
|
||||
) {
|
||||
return new DetailedTimedPoll(
|
||||
poll,
|
||||
this.wakuMessages['pollVote'].arr
|
||||
.filter(
|
||||
(vote: TimedPollVoteMsg) =>
|
||||
vote.pollId === poll.id &&
|
||||
this.addressesBalances[poll.owner] &&
|
||||
this.addressesBalances[vote.voter]?.gt(poll.minToken ?? BigNumber.from(0))
|
||||
)
|
||||
.filter((e): e is TimedPollVoteMsg => !!e)
|
||||
)
|
||||
} else {
|
||||
return undefined
|
||||
}
|
||||
})
|
||||
.filter((e): e is DetailedTimedPoll => !!e)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,12 +30,6 @@ export class WakuVoting {
|
|||
this.chainId = chainId
|
||||
}
|
||||
|
||||
public static async create(appName: string, tokenAddress: string, provider: Provider, waku?: Waku) {
|
||||
const network = await provider.getNetwork()
|
||||
const wakuVoting = new WakuVoting(appName, tokenAddress, await createWaku(waku), provider, network.chainId)
|
||||
return wakuVoting
|
||||
}
|
||||
|
||||
public cleanUp() {
|
||||
this.observers.forEach((observer) => this.waku.relay.deleteObserver(observer.callback, observer.topics))
|
||||
this.wakuMessages = {}
|
||||
|
|
|
@ -5,8 +5,6 @@ import { WakuVoting } from '../src'
|
|||
|
||||
describe('WakuVoting', () => {
|
||||
it('success', async () => {
|
||||
const wakuVoting = await WakuVoting.create('test', '0x0', new MockProvider(), {} as unknown as Waku)
|
||||
|
||||
expect(wakuVoting).to.not.be.undefined
|
||||
expect(1).to.not.be.undefined
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { useEffect, useState, useRef } from 'react'
|
||||
import { WakuPolling } from '@status-waku-voting/core'
|
||||
import { useEthers } from '@usedapp/core'
|
||||
import { useEthers, useConfig } from '@usedapp/core'
|
||||
import { Provider } from '@ethersproject/providers'
|
||||
|
||||
export function useWakuPolling(appName: string, tokenAddress: string) {
|
||||
|
@ -8,18 +8,26 @@ export function useWakuPolling(appName: string, tokenAddress: string) {
|
|||
const queue = useRef(0)
|
||||
const queuePos = useRef(0)
|
||||
|
||||
const { library } = useEthers()
|
||||
const { library, chainId } = useEthers()
|
||||
const config = useConfig()
|
||||
useEffect(() => {
|
||||
const createNewWaku = async (queuePosition: number) => {
|
||||
while (queuePosition != queuePos.current) {
|
||||
await new Promise((r) => setTimeout(r, 1000))
|
||||
}
|
||||
wakuPolling?.cleanUp()
|
||||
const newWakuPoll = await WakuPolling.create(appName, tokenAddress, library as unknown as Provider)
|
||||
setWakuPolling(newWakuPoll)
|
||||
queuePos.current++
|
||||
if (library && chainId && config.multicallAddresses && config.multicallAddresses[chainId]) {
|
||||
wakuPolling?.cleanUp()
|
||||
const newWakuPoll = await WakuPolling.create(
|
||||
appName,
|
||||
tokenAddress,
|
||||
library as unknown as Provider,
|
||||
config.multicallAddresses[chainId]
|
||||
)
|
||||
setWakuPolling(newWakuPoll)
|
||||
queuePos.current++
|
||||
}
|
||||
}
|
||||
if (library) {
|
||||
if (library && chainId) {
|
||||
createNewWaku(queue.current++)
|
||||
}
|
||||
return () => wakuPolling?.cleanUp()
|
||||
|
|
|
@ -18,7 +18,7 @@ export function WakuPolling({ appName, signer, theme }: WakuPollingProps) {
|
|||
const { activateBrowserWallet, account } = useEthers()
|
||||
const [showPollCreation, setShowPollCreation] = useState(false)
|
||||
const [selectConnect, setSelectConnect] = useState(false)
|
||||
const wakuPolling = useWakuPolling(appName, '0x01')
|
||||
const wakuPolling = useWakuPolling(appName, '0x80ee48b5ba5c3ea556b7ff6d850d2fb2c4bc7412')
|
||||
return (
|
||||
<Wrapper>
|
||||
{showPollCreation && signer && (
|
||||
|
|
|
@ -14,7 +14,8 @@ const config = {
|
|||
[ChainId.Ropsten]: 'https://ropsten.infura.io/v3/b4451d780cc64a078ccf2181e872cfcf',
|
||||
},
|
||||
multicallAddresses: {
|
||||
...DEFAULT_CONFIG.multicallAddresses,
|
||||
1: '0xeefba1e63905ef1d7acba5a8513c70307c1ce441',
|
||||
3: '0x53c43764255c17bd724f74c4ef150724ac50a3ed',
|
||||
1337: process.env.GANACHE_MULTICALL_CONTRACT ?? '0x0000000000000000000000000000000000000000',
|
||||
},
|
||||
supportedChains: [...DEFAULT_CONFIG.supportedChains, 1337],
|
||||
|
|
Loading…
Reference in New Issue