diff --git a/frontend/src/components/ACLs/allowAll.ts b/frontend/src/components/ACLs/allowAll.ts index 41d04fe..2d89416 100644 --- a/frontend/src/components/ACLs/allowAll.ts +++ b/frontend/src/components/ACLs/allowAll.ts @@ -25,13 +25,16 @@ export const allowAll = defineACL({ values: undefined, } }, - getAclOptions: () => [ - '0x', // Empty bytes is passed - { + getAclOptions: () => ({ + data: '0x', // Empty bytes is passed + options: { address: VITE_CONTRACT_ACL_ALLOWALL, - options: { allowAll: true }, + options: { + allowAll: true, + }, }, - ], + flags: 0n, + }), isThisMine: options => 'allowAll' in options.options, checkPermission: async (pollACL, daoAddress, proposalId, userAddress) => { diff --git a/frontend/src/components/ACLs/allowList.ts b/frontend/src/components/ACLs/allowList.ts index 6aa574e..9429db7 100644 --- a/frontend/src/components/ACLs/allowList.ts +++ b/frontend/src/components/ACLs/allowList.ts @@ -2,7 +2,6 @@ import { defineACL } from './common' import { designDecisions, VITE_CONTRACT_ACL_VOTERALLOWLIST } from '../../constants/config' import { abiEncode, isValidAddress } from '../../utils/poll.utils' import { denyWithReason, useOneOfField, useTextArrayField } from '../InputFields' -import { AclOptions } from '@oasisprotocol/blockvote-contracts' // Split a list of addresses by newLine, comma or space const splitAddresses = (addressSoup: string): string[] => @@ -69,15 +68,18 @@ export const allowList = defineACL({ } }, - getAclOptions: (props): [string, AclOptions] => { + getAclOptions: props => { if (!props.addresses) throw new Error('Internal errors: parameter mismatch, addresses missing.') - return [ - abiEncode(['address[]'], [props.addresses]), - { + return { + data: abiEncode(['address[]'], [props.addresses]), + options: { address: VITE_CONTRACT_ACL_VOTERALLOWLIST, - options: { allowList: true }, + options: { + allowList: true, + }, }, - ] + flags: 0n, + } }, isThisMine: options => 'allowList' in options.options, diff --git a/frontend/src/components/ACLs/common.ts b/frontend/src/components/ACLs/common.ts index 56154f7..97f5f03 100644 --- a/frontend/src/components/ACLs/common.ts +++ b/frontend/src/components/ACLs/common.ts @@ -24,8 +24,14 @@ export type ACL = Ch * Compose the ACL options when creating a poll */ getAclOptions: - | ((config: ConfigInputValues, statusUpdater?: StatusUpdater) => [string, Options]) - | ((config: ConfigInputValues, statusUpdater?: StatusUpdater) => Promise<[string, Options]>) + | (( + config: ConfigInputValues, + statusUpdater?: StatusUpdater, + ) => { data: string; options: Options; flags: bigint }) + | (( + config: ConfigInputValues, + statusUpdater?: StatusUpdater, + ) => Promise<{ data: string; options: Options; flags: bigint }>) /** * Attempt to recognize if this ACL is managing a given poll, based on ACL options diff --git a/frontend/src/components/ACLs/tokenHolder.tsx b/frontend/src/components/ACLs/tokenHolder.tsx index f263638..8638e9c 100644 --- a/frontend/src/components/ACLs/tokenHolder.tsx +++ b/frontend/src/components/ACLs/tokenHolder.tsx @@ -1,12 +1,5 @@ import { defineACL } from './common' -import { - DecisionWithReason, - deny, - denyWithReason, - useLabel, - useOneOfField, - useTextField, -} from '../InputFields' +import { DecisionWithReason, denyWithReason, useLabel, useOneOfField, useTextField } from '../InputFields' import { abiEncode, getLocalContractDetails, isValidAddress } from '../../utils/poll.utils' import { configuredExplorerUrl, @@ -15,6 +8,7 @@ import { VITE_CONTRACT_ACL_TOKENHOLDER, } from '../../constants/config' import { StringUtils } from '../../utils/string.utils' +import { FLAG_WEIGHT_LOG10, FLAG_WEIGHT_ONE } from '../../types' export const tokenHolder = defineACL({ value: 'acl_tokenHolder', @@ -83,33 +77,50 @@ export const tokenHolder = defineACL({ { value: 'weight_perWallet', label: '1 vote per wallet', - enabled: deny('Coming soon'), }, { value: 'weight_perToken', label: 'According to token distribution', }, + { + value: 'weight_perLog10Token', + label: 'According to log10(token distribution)', + }, ], + initialValue: 'weight_perToken', disableIfOnlyOneVisibleChoice: designDecisions.disableSelectsWithOnlyOneVisibleOption, } as const) + const weightToFlags = (selection: typeof voteWeighting.value): bigint => { + switch (selection) { + case 'weight_perWallet': + return FLAG_WEIGHT_ONE + case 'weight_perToken': + return 0n + case 'weight_perLog10Token': + return FLAG_WEIGHT_LOG10 + } + } + return { fields: [contractAddress, [tokenName, tokenSymbol], voteWeighting], values: { tokenAddress: contractAddress.value, + flags: weightToFlags(voteWeighting.value), }, } }, getAclOptions: props => { if (!props.tokenAddress) throw new Error('Internal errors: parameter mismatch, addresses missing.') - return [ - abiEncode(['address'], [props.tokenAddress]), - { + return { + data: abiEncode(['address'], [props.tokenAddress]), + options: { address: VITE_CONTRACT_ACL_TOKENHOLDER, options: { token: props.tokenAddress }, }, - ] + flags: props.flags, + } }, isThisMine: options => 'token' in options.options, diff --git a/frontend/src/components/ACLs/xchain.tsx b/frontend/src/components/ACLs/xchain.tsx index b1a6f62..edbd90c 100644 --- a/frontend/src/components/ACLs/xchain.tsx +++ b/frontend/src/components/ACLs/xchain.tsx @@ -3,7 +3,6 @@ import { addMockValidation, Choice, DecisionWithReason, - deny, denyWithReason, useLabel, useOneOfField, @@ -35,6 +34,7 @@ import classes from './index.module.css' import { BytesLike, getUint } from 'ethers' import { ReactNode, useMemo } from 'react' import { StringUtils } from '../../utils/string.utils' +import { FLAG_WEIGHT_LOG10, FLAG_WEIGHT_ONE } from '../../types' export const xchain = defineACL({ value: 'acl_xchain', @@ -244,17 +244,31 @@ export const xchain = defineACL({ { value: 'weight_perWallet', label: '1 vote per wallet', - enabled: deny('Coming soon'), }, { value: 'weight_perToken', label: 'According to token distribution', }, + { + value: 'weight_perLog10Token', + label: 'According to log10(token distribution)', + }, ], hideDisabledChoices: designDecisions.hideDisabledSelectOptions, disableIfOnlyOneVisibleChoice: designDecisions.disableSelectsWithOnlyOneVisibleOption, } as const) + const weightToFlags = (selection: typeof voteWeighting.value): bigint => { + switch (selection) { + case 'weight_perWallet': + return FLAG_WEIGHT_ONE + case 'weight_perToken': + return 0n + case 'weight_perLog10Token': + return FLAG_WEIGHT_LOG10 + } + } + return { fields: [ chain, @@ -271,10 +285,11 @@ export const xchain = defineACL({ contractAddress: contractAddress.value, slotNumber: slotNumber.value, blockHash: blockHash.value, + flags: weightToFlags(voteWeighting.value), }, } }, - getAclOptions: async ({ chainId, contractAddress, slotNumber, blockHash }, updateStatus) => { + getAclOptions: async ({ chainId, contractAddress, slotNumber, blockHash, flags }, updateStatus) => { const showStatus = updateStatus ?? ((message?: string | undefined) => console.log(message)) const rpc = xchainRPC(chainId) showStatus('Getting block header RLP') @@ -293,16 +308,17 @@ export const xchain = defineACL({ }, } - return [ - abiEncode( + return { + data: abiEncode( ['tuple(tuple(bytes32,address,uint256),bytes,bytes)'], [[[blockHash, contractAddress, slotNumber], headerRlpBytes, rlpAccountProof]], ), - { + options: { address: VITE_CONTRACT_ACL_STORAGEPROOF, options, }, - ] + flags, + } }, isThisMine: options => 'xchain' in options.options, diff --git a/frontend/src/pages/CreatePollPage/useCreatePollForm.ts b/frontend/src/pages/CreatePollPage/useCreatePollForm.ts index 6cabc2b..e123f96 100644 --- a/frontend/src/pages/CreatePollPage/useCreatePollForm.ts +++ b/frontend/src/pages/CreatePollPage/useCreatePollForm.ts @@ -327,7 +327,11 @@ export const useCreatePollForm = () => { setIsCreating(true) try { const aclConfigValues = currentAclConfig.values - const [aclData, aclOptions] = await currentAcl.getAclOptions( + const { + data: aclData, + options: aclOptions, + flags: pollFlags, + } = await currentAcl.getAclOptions( aclConfigValues as never, // TODO: why is this conversion necessary? logger, ) @@ -338,6 +342,7 @@ export const useCreatePollForm = () => { isHidden: hidden.value, aclData, aclOptions, + pollFlags, subsidizeAmount: gasFree.value ? parseEther(amountOfSubsidy.value) : undefined, publishVotes: resultDisplayType.value === 'percentages_and_votes', publishVoters: resultDisplayType.value === 'percentages_and_voters', diff --git a/frontend/src/utils/poll.utils.ts b/frontend/src/utils/poll.utils.ts index df740dc..8542885 100644 --- a/frontend/src/utils/poll.utils.ts +++ b/frontend/src/utils/poll.utils.ts @@ -129,6 +129,7 @@ export type CreatePollProps = { isHidden: boolean aclData: string aclOptions: AclOptions + pollFlags: bigint subsidizeAmount: bigint | undefined publishVotes: boolean publishVoters: boolean @@ -168,6 +169,7 @@ export const createPoll = async ( answers, aclData, aclOptions, + pollFlags: extraFlags, isHidden, subsidizeAmount, publishVotes, @@ -191,7 +193,7 @@ export const createPoll = async ( // console.log('Compiling poll', poll) - let pollFlags: bigint = 0n + let pollFlags: bigint = extraFlags if (poll.options.publishVoters) pollFlags |= FLAG_PUBLISH_VOTERS if (poll.options.publishVotes) pollFlags |= FLAG_PUBLISH_VOTES