Skip to content

Commit

Permalink
wip: refactor(namada): cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
egasimus committed Jun 10, 2024
1 parent 4f03c4e commit ac0581e
Show file tree
Hide file tree
Showing 25 changed files with 603 additions and 1,418 deletions.
29 changes: 29 additions & 0 deletions packages/namada/Namada.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import NamadaConsole from './NamadaConsole'
import NamadaChain from './NamadaChain'
import NamadaConnection from './NamadaConnection'
import NamadaTransaction from './NamadaTransaction'
import { Decode, initDecoder } from './NamadaDecode'
import * as Identity from './NamadaIdentity'
export {
Decode,
initDecoder,
NamadaConsole as Console,
NamadaChain as Chain,
NamadaConnection as Connection,
NamadaTransaction as Transaction,
Identity
}
export const testnetChainId = NamadaChain.testnetChainId
export const testnetURLs = NamadaChain.testnetURLs
export function connect (...args: Parameters<typeof NamadaChain.connect>) {
return NamadaChain.connect(...args)
}
export function testnet (...args: Parameters<typeof NamadaChain.testnet>) {
return NamadaChain.testnet(...args)
}
export function mainnet (...args: never) {
throw new Error(
'Connection details for Namada mainnet are not built into Fadroma yet. ' +
'You can pass them to Namada.connect function if you have them.'
)
}
133 changes: 133 additions & 0 deletions packages/namada/NamadaBlock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { Block } from '@fadroma/cw'
import type { Chain as Namada } from './Namada'
import { Decode } from './NamadaDecode'
import Transaction, { NamadaUndecodedTransaction } from './NamadaTransaction'

export default class NamadaBlock extends Block {

constructor ({
header, responses, ...properties
}: ConstructorParameters<typeof Block>[0]
& Pick<NamadaBlock, 'header'|'responses'|'chain'>
) {
super(properties)
this.#chain = properties.chain
this.#responses = responses
this.header = header
}

#chain: Namada
get chain (): Namada {
return this.#chain
}

#responses?: {
block: { url: string, response: string }
results: { url: string, response: string }
}
get responses () {
return this.#responses
}

/** Block header. */
header: {
version: object
chainId: string
height: bigint
time: string
lastBlockId: string
lastCommitHash: string
dataHash: string
validatorsHash: string
nextValidatorsHash: string
consensusHash: string
appHash: string
lastResultsHash: string
evidenceHash: string
proposerAddress: string
}

/** Transaction in block. */
declare transactions: Transaction[]

/** Responses from block API endpoints. */

static async fetchByHeight (
{ url, decode = Decode, chain }: {
url: string|URL, decode?: typeof Decode, chain?: Namada
},
{ height, raw }: {
height: number|string|bigint,
raw?: boolean,
}
): Promise<NamadaBlock> {
if (!url) {
throw new Error("Can't fetch block: missing connection URL")
}
// Fetch block and results as undecoded JSON
const blockUrl = `${url}/block?height=${height}`
const resultsUrl = `${url}/block_results?height=${height}`
const [block, results] = await Promise.all([
fetch(blockUrl).then(response=>response.text()),
fetch(resultsUrl).then(response=>response.text()),
])
return this.fromResponses({
block: { url: blockUrl, response: block, },
results: { url: resultsUrl, response: results, },
}, { chain, decode, height })
}

static async fetchByHash (
_1: { url: string|URL, decode?: typeof Decode, chain?: Namada },
_2: { hash: string, raw?: boolean },
): Promise<NamadaBlock> {
throw new Error('NamadaBlock.fetchByHash: not implemented')
}

static fromResponses (
responses: NonNullable<NamadaBlock["responses"]>,
{ decode = Decode, chain, height }: {
decode?: typeof Decode
chain?: Namada,
height?: string|number|bigint
},
): NamadaBlock {
const { id, header, txs } = decode.block(
responses.block.response,
responses.results.response
) as {
id: string,
txs: Partial<Transaction[]>[]
header: NamadaBlock["header"]
}

return new NamadaBlock({
id,
header,

chain: chain!,
height: Number(header.height),
timestamp: header.time,

transactions: txs.map((tx, i)=>{
try {
return Transaction.fromDecoded({
height,
...tx as any
})
} catch (error) {
console.error(error)
console.warn(`Failed to decode transaction #${i} in block ${height}, see above for details.`)
return new NamadaUndecodedTransaction({
error: error as any,
data: tx as any,
})
}
}),

responses
})

}

}
139 changes: 139 additions & 0 deletions packages/namada/NamadaChain.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import * as CW from '@fadroma/cw'
import type { ChainId } from '@hackbg/fadroma'
import NamadaConnection from './NamadaConnection'
import { Decode, initDecoder } from './NamadaDecode'

export default class NamadaChain extends CW.Chain {
decode = Decode

/** Connect to Namada over one or more endpoints. */
static async connect (
properties: Parameters<typeof CW.Chain["connect"]>[0] & {
chainId?: ChainId
decoder?: string|URL|Uint8Array
}
): Promise<NamadaChain> {
if (properties?.decoder) {
await initDecoder(properties.decoder)
} else {
new CW.Console('@fadroma/namada').warn(
"Decoder binary not provided; trying to decode Namada objects will fail."
)
}
properties ??= {} as any
properties.bech32Prefix ??= "tnam"
return await super.connect(properties || ({} as any)) as NamadaChain
}

/** Connect to Namada using `testnetChainId` and `testnetURLs`. */
static testnet (properties: Parameters<typeof NamadaChain["connect"]>[0]) {
return this.connect({
chainId: properties?.chainId || NamadaChain.testnetChainId,
urls: (properties as any)?.url
? [(properties as any).url]
: ((properties as any)?.urls || [...NamadaChain.testnetURLs]),
})
}

/** Default chain ID of testnet. */
static testnetChainId = 'shielded-expedition.88f17d1d14'

/** Default RPC endpoints for testnet. */
static testnetURLs = new Set([
'https://namada-testnet-rpc.itrocket.net',
'https://namada-rpc.stake-machine.com',
'https://namadarpc.songfi.xyz',
'https://rpc.testnet.one',
])

static get Connection () {
return NamadaConnection
}

getConnection (): NamadaConnection {
return this.connections[0] as NamadaConnection
}

authenticate (...args: unknown[]): never {
throw new Error('Transacting on Namada is currently not supported.')
}

fetchPGFParameters () {
return this.getConnection().fetchPGFParametersImpl()
}

fetchPGFStewards () {
return this.getConnection().fetchPGFStewardsImpl()
}

fetchPGFFundings () {
return this.getConnection().fetchPGFFundingsImpl()
}

isPGFSteward (address: string) {
return this.getConnection().isPGFStewardImpl(address)
}

fetchStakingParameters () {
return this.getConnection().fetchStakingParametersImpl()
}

fetchValidatorAddresses () {
return this.getConnection().fetchValidatorAddressesImpl()
}

fetchValidator (address: string) {
return this.getConnection().fetchValidatorImpl(address)
}

fetchValidators (options?: {
details?: boolean,
pagination?: [number, number]
allStates?: boolean,
addresses?: string[],
parallel?: boolean,
parallelDetails?: boolean,
}) {
return this.getConnection().fetchValidators(options)
}

fetchValidatorsConsensus () {
return this.getConnection().fetchValidatorsConsensusImpl()
}

fetchValidatorsBelowCapacity () {
return this.getConnection().fetchValidatorsBelowCapacityImpl()
}

fetchDelegations (address: string) {
return this.getConnection().fetchDelegationsImpl(address)
}

fetchDelegationsAt (address: string, epoch?: number) {
return this.getConnection().fetchDelegationsAtImpl(address, epoch)
}

fetchGovernanceParameters () {
return this.getConnection().fetchGovernanceParametersImpl()
}

fetchProposalCount () {
return this.getConnection().fetchProposalCountImpl()
}

fetchProposalInfo (id: number) {
return this.getConnection().fetchProposalInfoImpl(id)
}

fetchCurrentEpoch () {
return this.getConnection().fetchCurrentEpochImpl()
}

fetchTotalStaked () {
return this.getConnection().fetchTotalStakedImpl()
}

fetchValidatorStake (address: string) {
return this.getConnection().fetchValidatorStakeImpl(address)
}
}
Loading

0 comments on commit ac0581e

Please sign in to comment.