Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
49 changes: 48 additions & 1 deletion typescript/src/chain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@ import {
DecomposedRawTransaction,
TransactionHash,
} from "./bitcoin"
import { DepositScriptParameters, RevealedDeposit } from "./deposit"
import {
DepositRevealedEvent,
DepositScriptParameters,
RevealedDeposit,
} from "./deposit"
import { Hex } from "./hex"
import { RedemptionRequest } from "./redemption"

/**
Expand All @@ -18,10 +23,52 @@ export interface Identifier {
identifierHex: string
}

/**
* Represents a generic chain event.
*/
export interface Event {
/**
* Block number of the event emission.
*/
blockNumber: number
/**
* Block hash of the event emission.
*/
blockHash: Hex
/**
* Transaction hash within which the event was emitted.
*/
transactionHash: Hex
}

/**
* Represents a generic function to get events emitted on the chain.
*/
export interface GetEventsFunction<T extends Event> {
/**
* Get emitted events.
* @param fromBlock Block number from which events should be queried.
* If not defined a block number of a contract deployment is used.
* @param toBlock Block number to which events should be queried.
* If not defined the latest block number will be used.
* @param filterArgs Arguments for events filtering.
* @returns Array of found events.
*/
(fromBlock?: number, toBlock?: number, ...filterArgs: Array<any>): Promise<
T[]
>
}

/**
* Interface for communication with the Bridge on-chain contract.
*/
export interface Bridge {
/**
* Get emitted DepositRevealed events.
* @see GetEventsFunction
*/
getDepositRevealedEvents: GetEventsFunction<DepositRevealedEvent>

/**
* Submits a deposit sweep transaction proof to the on-chain contract.
* @param sweepTx - Sweep transaction data.
Expand Down
13 changes: 12 additions & 1 deletion typescript/src/deposit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@ import {
TransactionHash,
isPublicKeyHashLength,
} from "./bitcoin"
import { Bridge, Identifier } from "./chain"
import { Bridge, Event, Identifier } from "./chain"

const { opcodes } = bcoin.script.common

// TODO: Replace all properties that are expected to be un-prefixed hexadecimal
// strings with a Hex type.

/**
* Represents a deposit.
*/
Expand Down Expand Up @@ -98,6 +101,14 @@ export type RevealedDeposit = Pick<
treasuryFee: BigNumber
}

/**
* Represents an event emitted on deposit reveal to the on-chain bridge.fp
*/
export type DepositRevealedEvent = Deposit & {
fundingTxHash: TransactionHash
fundingOutputIndex: number
} & Event

/**
* Submits a deposit by creating and broadcasting a Bitcoin P2(W)SH
* deposit transaction.
Expand Down
75 changes: 74 additions & 1 deletion typescript/src/ethereum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,19 @@ import {
BigNumber,
constants,
Contract as EthersContract,
Event as EthersEvent,
providers,
Signer,
utils,
} from "ethers"
import { BlockTag as EthersBlockTag } from "@ethersproject/abstract-provider"
import BridgeDeployment from "@keep-network/tbtc-v2/artifacts/Bridge.json"
import WalletRegistryDeployment from "@keep-network/ecdsa/artifacts/WalletRegistry.json"
import { DepositScriptParameters, RevealedDeposit } from "./deposit"
import {
DepositScriptParameters,
RevealedDeposit,
DepositRevealedEvent,
} from "./deposit"
import { RedemptionRequest } from "./redemption"
import {
compressPublicKey,
Expand All @@ -22,6 +28,7 @@ import {

import type { Bridge as ContractBridge } from "../typechain/Bridge"
import type { WalletRegistry as ContractWalletRegistry } from "../typechain/WalletRegistry"
import { Hex } from "./hex"

/**
* Contract deployment artifact.
Expand Down Expand Up @@ -118,6 +125,31 @@ class EthereumContract<T extends EthersContract> {
this._deployedAtBlockNumber =
config.deployedAtBlockNumber ?? deployment.receipt.blockNumber
}

/**
* Get events emitted by the Ethereum contract.
* @param eventName Name of the event.
* @param fromBlock Block number from which events should be queried. Optional
* parameter, by default block number of the contract deployment is used.
* @param toBlock Block number to which events should be queried. Optional
* parameter, by efault the latest block is used.
* @param filterArgs Arguments for events filtering.
* @returns Array of found events.
*/
async getEvents(
eventName: string,
fromBlock?: EthersBlockTag,
toBlock?: EthersBlockTag,
...filterArgs: Array<any>
): Promise<EthersEvent[]> {
// TODO: Test if we need a workaround for querying events from big range in chunks,
// see: https://github.com/keep-network/tbtc-monitoring/blob/e169357d7b8c638d4eaf73d52aa8f53ee4aebc1d/src/lib/ethereum-helper.js#L44-L73
return await this._instance.queryFilter(
this._instance.filters[eventName](...filterArgs),
fromBlock ?? this._deployedAtBlockNumber,
toBlock ?? "latest"
)
}
}

/**
Expand All @@ -132,6 +164,47 @@ export class Bridge
super(config, BridgeDeployment)
}

// eslint-disable-next-line valid-jsdoc
/**
* @see {ChainBridge#getDepositRevealedEvents}
*/
async getDepositRevealedEvents(
fromBlock?: number,
toBlock?: number,
...filterArgs: Array<any>
): Promise<DepositRevealedEvent[]> {
const events: EthersEvent[] = await this.getEvents(
"DepositRevealed",
fromBlock,
toBlock,
...filterArgs
)

return events.map<DepositRevealedEvent>((event) => {
return {
blockNumber: BigNumber.from(event.blockNumber).toNumber(),
blockHash: Hex.from(event.blockHash),
transactionHash: Hex.from(event.transactionHash),
fundingTxHash: TransactionHash.from(
event.args!.fundingTxHash
).reverse(),
fundingOutputIndex: BigNumber.from(
event.args!.fundingOutputIndex
).toNumber(),
depositor: new Address(event.args!.depositor),
amount: BigNumber.from(event.args!.amount),
blindingFactor: Hex.from(event.args!.blindingFactor).toString(),
walletPublicKeyHash: Hex.from(event.args!.walletPubKeyHash).toString(),
refundPublicKeyHash: Hex.from(event.args!.refundPubKeyHash).toString(),
refundLocktime: Hex.from(event.args!.refundLocktime).toString(),
vault:
event.args!.vault === constants.AddressZero
? undefined
: new Address(event.args!.vault),
}
})
}

// eslint-disable-next-line valid-jsdoc
/**
* @see {ChainBridge#pendingRedemptions}
Expand Down
40 changes: 39 additions & 1 deletion typescript/test/utils/mock-bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,15 @@ import {
} from "../../src/bitcoin"
import { BigNumberish, BigNumber, utils, constants } from "ethers"
import { RedemptionRequest } from "../redemption"
import { Deposit, RevealedDeposit } from "../../src/deposit"
import {
Deposit,
DepositRevealedEvent,
RevealedDeposit,
} from "../../src/deposit"
import { computeHash160, TransactionHash } from "../../src/bitcoin"
import { depositSweepWithNoMainUtxoAndWitnessOutput } from "../data/deposit-sweep"
import { Address } from "../../src/ethereum"
import { Hex } from "../../src/hex"

interface DepositSweepProofLogEntry {
sweepTx: DecomposedRawTransaction
Expand Down Expand Up @@ -81,6 +88,37 @@ export class MockBridge implements Bridge {
this._activeWalletPublicKey = activeWalletPublicKey
}

getDepositRevealedEvents(
fromBlock?: number,
toBlock?: number,
...filterArgs: Array<any>
): Promise<DepositRevealedEvent[]> {
const deposit = depositSweepWithNoMainUtxoAndWitnessOutput.deposits[0]

return new Promise<DepositRevealedEvent[]>((resolve, _) => {
resolve([
{
blockNumber: 32142,
blockHash: Hex.from(
"0xe43552af34efab0828278b91e0f984e4b9769abf85beaed41eee4c25c822a619"
),
transactionHash: Hex.from(
"0xdc6c041baaf1cc5bebca5aab02d0488e885a3687541ef012d9beb53141f73419"
),
fundingTxHash: deposit.utxo.transactionHash,
fundingOutputIndex: deposit.utxo.outputIndex,
depositor: deposit.data.depositor,
amount: deposit.utxo.value,
blindingFactor: deposit.data.blindingFactor,
walletPublicKeyHash: deposit.data.walletPublicKeyHash,
refundPublicKeyHash: deposit.data.refundPublicKeyHash,
refundLocktime: deposit.data.refundLocktime,
vault: new Address(constants.AddressZero),
},
])
})
}

submitDepositSweepProof(
sweepTx: DecomposedRawTransaction,
sweepProof: Proof,
Expand Down