diff --git a/packages/namada/NamadaChain.ts b/packages/namada/NamadaChain.ts index a49fb67a3d..666faf7930 100644 --- a/packages/namada/NamadaChain.ts +++ b/packages/namada/NamadaChain.ts @@ -80,6 +80,7 @@ export default class NamadaChain extends CW.Chain { return this.getConnection().fetchValidatorAddressesImpl() } fetchValidators (options?: { + epoch?: string|number|bigint, details?: boolean, pagination?: [number, number] allStates?: boolean, @@ -125,13 +126,16 @@ export default class NamadaChain extends CW.Chain { fetchValidator (address: string) { return this.getConnection().fetchValidatorImpl(address) } - fetchValidatorStake (address: string) { - return this.getConnection().fetchValidatorStakeImpl(address) + fetchValidatorStake (address: string, epoch?: number|string|bigint) { + return this.getConnection().fetchValidatorStakeImpl(address, epoch) + } + fetchBondWithSlashing (validator: string, delegator: string, epoch?: number|string|bigint) { + return this.getConnection().fetchBondWithSlashingImpl(validator, delegator, epoch) } fetchDelegations (address: string) { return this.getConnection().fetchDelegationsImpl(address) } - fetchDelegationsAt (address: string, epoch?: number) { + fetchDelegationsAt (address: string, epoch?: number|string|bigint) { return this.getConnection().fetchDelegationsAtImpl(address, epoch) } fetchGovernanceParameters () { @@ -155,7 +159,7 @@ export default class NamadaChain extends CW.Chain { fetchEpochDuration () { return this.getConnection().fetchEpochDurationImpl() } - fetchTotalStaked () { - return this.getConnection().fetchTotalStakedImpl() + fetchTotalStaked (epoch?: number|string|bigint) { + return this.getConnection().fetchTotalStakedImpl(epoch) } } diff --git a/packages/namada/NamadaConnection.ts b/packages/namada/NamadaConnection.ts index f0563db3b9..b96360a46a 100644 --- a/packages/namada/NamadaConnection.ts +++ b/packages/namada/NamadaConnection.ts @@ -113,6 +113,7 @@ export default class NamadaConnection extends CW.Connection { return PoS.fetchValidator(this, address) } fetchValidatorsImpl (options?: { + epoch?: string|number|bigint, details?: boolean, pagination?: [number, number] allStates?: boolean, @@ -134,14 +135,17 @@ export default class NamadaConnection extends CW.Connection { fetchDelegationsImpl (address: string) { return PoS.fetchDelegations(this, address) } - fetchDelegationsAtImpl (address: string, epoch?: number) { + fetchDelegationsAtImpl (address: string, epoch?: number|string|bigint) { return PoS.fetchDelegationsAt(this, address, epoch) } - fetchTotalStakedImpl () { - return PoS.fetchTotalStaked(this) + fetchTotalStakedImpl (epoch?: number|string|bigint) { + return PoS.fetchTotalStaked(this, epoch) } - fetchValidatorStakeImpl (address: string) { - return PoS.fetchValidatorStake(this, address) + fetchValidatorStakeImpl (address: string, epoch?: number|string|bigint) { + return PoS.fetchValidatorStake(this, address, epoch) + } + fetchBondWithSlashingImpl (validator: string, delegator: string, epoch?: number|string|bigint) { + return PoS.fetchBondWithSlashing(this, validator, delegator, epoch) } } diff --git a/packages/namada/NamadaGov.ts b/packages/namada/NamadaGov.ts index e6d9c5effc..62f6bf14ee 100644 --- a/packages/namada/NamadaGov.ts +++ b/packages/namada/NamadaGov.ts @@ -21,7 +21,7 @@ export async function fetchProposalInfo ( ): Promise { const proposalResponse = await connection.abciQuery(`/vp/governance/proposal/${id}`) if (proposalResponse[0] === 0) return null - const [ votesResponse, resultResponse ] = await Promise.all([ + const [ votesResponse, resultResponse ] = await Promise.all([ `/vp/governance/proposal/${id}/votes`, `/vp/governance/stored_proposal_result/${id}`, ].map(x=>connection.abciQuery(x))) @@ -32,7 +32,6 @@ export async function fetchProposalInfo ( const result = (resultResponse[0] === 0) ? null : decodeResultResponse(connection.decode.gov_result(resultResponse.slice(1)) as Required>) - return { id: BigInt(id), proposal, votes, result } } @@ -65,7 +64,7 @@ const decodeResultResponse = ( ): NamadaGovernanceProposalResult => ({ ...decoded, turnout: String(turnout), - turnoutPercent: (decoded.totalVotingPower! > 0) ? percent(turnout, decoded.totalVotingPower!) : '0', + turnoutPercent: (decoded.totalVotingPower! > 0) ? percent2(turnout, decoded.totalVotingPower!) : '0', yayPercent: (turnout > 0) ? percent(decoded.totalYayPower!, turnout) : '0', nayPercent: (turnout > 0) ? percent(decoded.totalNayPower!, turnout) : '0', abstainPercent: (turnout > 0) ? percent(decoded.totalAbstainPower!, turnout) : '0', @@ -102,7 +101,9 @@ interface NamadaGovernanceProposalResult { } const percent = (a: string|number|bigint, b: string|number|bigint) => - ((Number(BigInt(a) * 1000000n / BigInt(b)) / 10000).toFixed(2) + '%').padStart(7) + ((Number(BigInt(a) * 1000000n / BigInt(b)) / 10000).toFixed(2) + '%') +const percent2 = (a: string|number|bigint, b: string|number|bigint) => + ((Number(BigInt(a) * 1000000n / BigInt(b)) / 1000000).toFixed(2) + '%') export { NamadaGovernanceProposal as Proposal, diff --git a/packages/namada/NamadaPoS.ts b/packages/namada/NamadaPoS.ts index 088bf15978..c2b489a5fc 100644 --- a/packages/namada/NamadaPoS.ts +++ b/packages/namada/NamadaPoS.ts @@ -14,8 +14,10 @@ export async function fetchStakingParameters (connection: NamadaConnection) { return connection.decode.pos_parameters(binary) } -export async function fetchTotalStaked (connection: NamadaConnection) { - const binary = await connection.abciQuery("/vp/pos/total_stake") +export async function fetchTotalStaked (connection: NamadaConnection, epoch?: number|bigint|string) { + let query = "/vp/pos/total_stake" + if (epoch) query += `/${epoch}` + const binary = await connection.abciQuery(query) return decode(u64, binary) } @@ -62,6 +64,7 @@ export { NamadaValidator as Validator } export async function fetchValidators ( connection: NamadaConnection, options: Partial[1]> & { + epoch?: number|string|bigint tendermintMetadata?: 'parallel'|'sequential'|boolean namadaMetadata?: 'parallel'|'sequential'|boolean } = {} @@ -72,7 +75,7 @@ export async function fetchValidators ( // This is the full list of validators known to the chain. // However, it contains no other data than the identifier. // The rest we will have to piece together ourselves. - const namadaAddresses = await fetchValidatorAddresses(connection) + const namadaAddresses = await fetchValidatorAddresses(connection, options?.epoch) for (const namadaAddress of namadaAddresses) { validatorsByNamadaAddress[namadaAddress] = new NamadaValidator({ chain: connection.chain, @@ -185,13 +188,14 @@ export async function fetchValidators ( } /** Generator implementation of fetchValidators. */ -export async function * fetchValidatorsIter ( - connection: NamadaConnection, - options?: { parallel?: boolean, addresses?: string[] } -) { - const namadaAddresses = options?.addresses?.length - ? options.addresses - : await fetchValidatorAddresses(connection) +export async function * fetchValidatorsIter (connection: NamadaConnection, options?: { + epoch?: number|string|bigint, + parallel?: boolean, + addresses?: string[] +}) { + const { addresses = [], epoch, parallel = false } = options || {} + const namadaAddresses = addresses?.length + ? addresses : await fetchValidatorAddresses(connection, epoch) const tendermintMetadata = (await Staking.getValidators(connection)).reduce((vs, v)=> Object.assign(vs, {[v.publicKey]: v}), {}) as Record validator.state = connection.decode.pos_validator_state(binary)) .catch(warn(`Failed to provide validator state for ${addr}`)), - () => connection.abciQuery(`/vp/pos/validator/stake/${addr}`) + () => connection.abciQuery( + `/vp/pos/validator/stake/${addr}` + (epoch ? `/${epoch}` : ``) + ) .then(binary => binary[0] && (validator.stake = decode(u256, binary.slice(1)))) .catch(warn(`Failed to provide validator stake for ${addr}`)), @@ -237,22 +243,26 @@ export async function * fetchValidatorsIter ( warn(`Failed to decode validator public key for ${addr}`) ) ] - await optionallyParallel(options?.parallel, requests) + await optionallyParallel(parallel, requests) yield validator } } -export async function fetchValidatorAddresses (connection: NamadaConnection): Promise { - const binary = await connection.abciQuery("/vp/pos/validator/addresses") +export async function fetchValidatorAddresses ( + connection: NamadaConnection, epoch?: number|string|bigint +): Promise { + let query = "/vp/pos/validator/addresses" + if (epoch) query = query + `/${epoch}` + const binary = await connection.abciQuery(query) return connection.decode.addresses(binary) } -export async function fetchValidatorDetails ( - connection: NamadaConnection, - options?: { parallel?: boolean, validator?: Partial } -) { - const validator = options?.validator || {} - +export async function fetchValidatorDetails (connection: NamadaConnection, options?: { + epoch?: number|string|bigint, + parallel?: boolean, + validator?: Partial +}) { + const { epoch, validator = {}, parallel = false } = options || {} if (!validator.namadaAddress) { if (!validator.address) { throw new Error('missing tendermint or namada address for validator') @@ -274,10 +284,10 @@ export async function fetchValidatorDetails ( () => connection.abciQuery(`/vp/pos/validator/commission/${v}`) .then(binary => validator.commission = connection.decode.pos_commission_pair(binary)) .catch(warn(`Failed to provide validator commission pair for ${v}`)), - () => connection.abciQuery(`/vp/pos/validator/state/${v}`) + () => connection.abciQuery(`/vp/pos/validator/state/${v}` + (epoch?`/${epoch}`:'')) .then(binary => validator.state = connection.decode.pos_validator_state(binary)) .catch(warn(`Failed to provide validator state for ${v}`)), - () => connection.abciQuery(`/vp/pos/validator/stake/${v}`) + () => connection.abciQuery(`/vp/pos/validator/stake/${v}` + (epoch?`/${epoch}`:'')) .then(binary => binary[0] && (validator.stake = decode(u256, binary.slice(1)))) .catch(warn(`Failed to provide validator stake for ${v}`)), () => connection.abciQuery(`/vp/pos/validator/consensus_key/${v}`) @@ -328,8 +338,14 @@ export async function fetchValidator (connection: NamadaConnection, namadaAddres }).fetchDetails() } -export async function fetchValidatorStake (connection: NamadaConnection, address: Address) { - const totalStake = await connection.abciQuery(`/vp/pos/validator/stake/${address}`) +export async function fetchValidatorStake ( + connection: NamadaConnection, + address: Address, + epoch?: number|bigint|string +) { + let query = `/vp/pos/validator/stake/${address}` + if (epoch) query += `/${epoch}` + const totalStake = await connection.abciQuery(query) return decode(u256, totalStake) } @@ -339,7 +355,9 @@ export async function fetchDelegations (connection: NamadaConnection, address: A } export async function fetchDelegationsAt ( - connection: NamadaConnection, address: Address, epoch?: number + connection: NamadaConnection, + address: Address, + epoch?: number|string|bigint ): Promise> { let query = `/vp/pos/delegations_at/${address}` epoch = Number(epoch) @@ -349,3 +367,15 @@ export async function fetchDelegationsAt ( const binary = await connection.abciQuery(query) return connection.decode.address_to_amount(binary) as Record } + +export async function fetchBondWithSlashing ( + connection: NamadaConnection, + validator: Address, + delegator: Address, + epoch?: number|bigint|string +) { + let query = `/vp/pos/bond_with_slashing/${validator}/${delegator}` + if (epoch) query += `/${epoch}` + const totalStake = await connection.abciQuery(query) + return decode(u256, totalStake) +}