Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fast Proposal Viewing #10652

Merged
merged 8 commits into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/cli/src/utils/checks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -503,6 +503,8 @@ class CheckBuilder {

if (!allPassed) {
return this.cmd.error("Some checks didn't pass!")
} else {
console.log(`All checks passed`)
}
}

Expand Down
18 changes: 13 additions & 5 deletions packages/sdk/connect/src/connection.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { ensureLeading0x, toChecksumAddress } from '@celo/utils/lib/address'
import { EIP712TypedData, generateTypedDataHash } from '@celo/utils/lib/sign-typed-data-utils'
import { parseSignatureWithoutPrefix, Signature } from '@celo/utils/lib/signatureUtils'
import { Signature, parseSignatureWithoutPrefix } from '@celo/utils/lib/signatureUtils'
import { bufferToHex } from '@ethereumjs/util'
import debugFactory from 'debug'
import Web3 from 'web3'
import { AbiCoder } from './abi-types'
import { assertIsCeloProvider, CeloProvider } from './celo-provider'
import { CeloProvider, assertIsCeloProvider } from './celo-provider'
import {
Address,
Block,
Expand All @@ -32,9 +32,9 @@ import {
outputCeloTxReceiptFormatter,
} from './utils/formatter'
import { hasProperty } from './utils/provider-utils'
import { getRandomId, HttpRpcCaller, RpcCaller } from './utils/rpc-caller'
import { HttpRpcCaller, RpcCaller, getRandomId } from './utils/rpc-caller'
import { TxParamsNormalizer } from './utils/tx-params-normalizer'
import { toTxResult, TransactionResult } from './utils/tx-result'
import { TransactionResult, toTxResult } from './utils/tx-result'
import { ReadOnlyWallet } from './wallet'

const debugGasEstimation = debugFactory('connection:gas-estimation')
Expand All @@ -54,6 +54,7 @@ export interface ConnectionOptions {
*/
export class Connection {
private config: ConnectionOptions
private _chainID: number | undefined
readonly paramsPopulator: TxParamsNormalizer
rpcCaller!: RpcCaller

Expand All @@ -76,6 +77,7 @@ export class Connection {
if (!provider) {
throw new Error('Must have a valid Provider')
}
this._chainID = undefined
try {
if (!(provider instanceof CeloProvider)) {
this.rpcCaller = new HttpRpcCaller(provider)
Expand Down Expand Up @@ -395,10 +397,16 @@ export class Connection {
}
}

// An instance of Connection will only change chain id if provider is changed.
chainId = async (): Promise<number> => {
if (this._chainID) {
return this._chainID
}
// Reference: https://eth.wiki/json-rpc/API#net_version
const response = await this.rpcCaller.call('net_version', [])
return parseInt(response.result.toString(), 10)
const chainID = parseInt(response.result.toString(), 10)
this._chainID = chainID
return chainID
}

getTransactionCount = async (address: Address): Promise<number> => {
Expand Down
47 changes: 31 additions & 16 deletions packages/sdk/contractkit/src/wrappers/Governance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,11 +245,13 @@ export class GovernanceWrapper extends BaseWrapperForGoverning<Governance> {

// simulates proposal.getSupportWithQuorumPadding
async getSupport(proposalID: BigNumber.Value) {
const participation = await this.getParticipationParameters()
const [participation, votes, lockedGold] = await Promise.all([
this.getParticipationParameters(),
this.getVotes(proposalID),
this.contracts.getLockedGold(),
])
const quorum = participation.baseline.times(participation.baselineQuorumFactor)
const votes = await this.getVotes(proposalID)
const total = votes.Yes.plus(votes.No).plus(votes.Abstain)
const lockedGold = await this.contracts.getLockedGold()
// NOTE: this networkWeight is not as governance calculates it,
// but we don't have access to proposal.networkWeight
const networkWeight = await lockedGold.getTotalLockedGold()
Expand Down Expand Up @@ -455,11 +457,18 @@ export class GovernanceWrapper extends BaseWrapperForGoverning<Governance> {
}

async getApprovalStatus(proposalID: BigNumber.Value): Promise<ApprovalStatus> {
const multisig = await this.getApproverMultisig()
const approveTx = await this.approve(proposalID)
const multisigTxs = await multisig.getTransactionDataByContent(this.address, approveTx.txo)
const [multisig, approveTx] = await Promise.all([
this.getApproverMultisig(),
this.approve(proposalID),
])

const [multisigTxs, approvers] = await Promise.all([
multisig.getTransactionDataByContent(this.address, approveTx.txo),
multisig.getOwners() as Promise<Address[]>,
])

const confirmations = multisigTxs ? multisigTxs.confirmations : []
const approvers = await multisig.getOwners()

return {
completion: `${confirmations.length} / ${approvers.length}`,
confirmations,
Expand All @@ -472,9 +481,11 @@ export class GovernanceWrapper extends BaseWrapperForGoverning<Governance> {
* @param proposalID Governance proposal UUID
*/
async getProposalRecord(proposalID: BigNumber.Value): Promise<ProposalRecord> {
const metadata = await this.getProposalMetadata(proposalID)
const proposal = await this.getProposal(proposalID)
const stage = await this.getProposalStage(proposalID)
const [proposal, metadata, stage] = await Promise.all([
this.getProposal(proposalID),
this.getProposalMetadata(proposalID),
this.getProposalStage(proposalID),
])

const record: ProposalRecord = {
proposal,
Expand All @@ -487,13 +498,17 @@ export class GovernanceWrapper extends BaseWrapperForGoverning<Governance> {
if (stage === ProposalStage.Queued) {
record.upvotes = await this.getUpvotes(proposalID)
} else if (stage === ProposalStage.Referendum || stage === ProposalStage.Execution) {
record.approved = true
record.passed = await this.isProposalPassing(proposalID)
record.votes = await this.getVotes(proposalID)
record.approved = await this.isApproved(proposalID)
record.approvals = await this.getApprovalStatus(proposalID)
const [passed, votes, approved, approvals] = await Promise.all([
this.isProposalPassing(proposalID) as Promise<boolean>,
this.getVotes(proposalID),
this.isApproved(proposalID),
this.getApprovalStatus(proposalID),
])
record.passed = passed as boolean
record.votes = votes
record.approved = approved
record.approvals = approvals
}

return record
}

Expand Down
68 changes: 49 additions & 19 deletions packages/sdk/contractkit/src/wrappers/MultiSig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ export interface TransactionData {
executed: boolean
confirmations: string[]
}
export interface TransactionDataWithOutConfirmations {
destination: string
value: BigNumber
data: string
executed: boolean
}

/**
* Contract for handling multisig actions
Expand All @@ -30,11 +36,7 @@ export class MultiSigWrapper extends BaseWrapper<MultiSig> {
* Otherwise, submits the `txObject` to the multisig and add confirmation.
* @param index The index of the pending withdrawal to withdraw.
*/
async submitOrConfirmTransaction(
destination: string,
txObject: CeloTxObject<any>,
value: string = '0'
) {
async submitOrConfirmTransaction(destination: string, txObject: CeloTxObject<any>, value = '0') {
const data = stringToSolidityBytes(txObject.encodeABI())
const transactionCount = await this.contract.methods.getTransactionCount(true, true).call()
let transactionId
Expand Down Expand Up @@ -81,31 +83,59 @@ export class MultiSigWrapper extends BaseWrapper<MultiSig> {
) {
const data = stringToSolidityBytes(txo.encodeABI())
const transactionCount = await this.getTransactionCount(true, true)
// reverse order for recency
for (let transactionId = transactionCount - 1; transactionId >= 0; transactionId--) {
const tx = await this.getTransaction(transactionId)
if (tx.data === data && tx.destination === destination && tx.value.isEqualTo(value)) {
return tx
}
const transactionIndexes = await Promise.all(
Array(transactionCount)
.fill(0)
.map(async (_, index) => {
const tx = await this.getTransaction(index, false)
if (tx.data === data && tx.destination === destination && tx.value.isEqualTo(value)) {
return index
}
return null
})
)
const txID = transactionIndexes.find((index) => index !== null)
if (!txID) {
return
aaronmgdr marked this conversation as resolved.
Show resolved Hide resolved
}
return undefined
const transactionWithConfirmations = await this.getTransaction(txID)
return transactionWithConfirmations
}

async getTransaction(i: number): Promise<TransactionData> {
async getTransaction(i: number): Promise<TransactionData>
async getTransaction(
i: number,
includeConfirmations: false
): Promise<TransactionDataWithOutConfirmations>
async getTransaction(i: number, includeConfirmations = true) {
const { destination, value, data, executed } = await this.contract.methods
.transactions(i)
.call()
const confirmations = []
for (const e of await this.getOwners()) {
if (await this.contract.methods.confirmations(i, e).call()) {
confirmations.push(e)
if (!includeConfirmations) {
return {
destination,
data,
executed,
value: new BigNumber(value),
}
}

const owners = await this.getOwners()
const confirmationsOrEmpties = await Promise.all(
owners.map(async (owner) => {
const confirmation = await this.contract.methods.confirmations(i, owner).call()
if (confirmation) {
return owner
} else {
return null
}
})
)
const confirmations = confirmationsOrEmpties.filter((c) => c !== null) as string[]
return {
confirmations,
destination,
data,
executed,
confirmations,
value: new BigNumber(value),
}
}
Expand Down
25 changes: 18 additions & 7 deletions packages/sdk/explorer/src/block-explorer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,16 @@ export class BlockExplorer {
getContractMappingFromSourcify = async (
address: string
): Promise<ContractMapping | undefined> => {
const cached = this.addressMapping.get(address)
aaronmgdr marked this conversation as resolved.
Show resolved Hide resolved
if (cached) {
return cached
}
const metadata = await fetchMetadata(this.kit.connection, address)
return metadata?.toContractMapping()
const mapping = metadata?.toContractMapping()
if (mapping) {
this.addressMapping.set(address, mapping)
}
return mapping
}

/**
Expand Down Expand Up @@ -369,11 +377,14 @@ export class BlockExplorer {
this.getContractMappingFromSourcifyAsProxy,
]
): Promise<ContractMapping | undefined> {
for (const strategy of strategies) {
const contractMapping = await strategy(address)
if (contractMapping && contractMapping.fnMapping.get(selector)) {
return contractMapping
}
}
const mappings = await Promise.all(
strategies.map(async (strategy) => {
const contractMapping = await strategy(address)
if (contractMapping && contractMapping.fnMapping.get(selector)) {
return contractMapping
}
})
)
return mappings.find((mapping) => mapping !== undefined)
aaronmgdr marked this conversation as resolved.
Show resolved Hide resolved
}
}
Loading
Loading