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
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
import { Transaction } from "@happychain/transaction-manager"
import type { Transaction, TransactionManager } from "@happychain/transaction-manager"
import type { Address, Hex } from "viem"

export class CommitmentTransactionFactory {
private readonly chainId: number
private readonly transactionManager: TransactionManager
private readonly randomContractAddress: Address
private readonly precommitDelay: bigint

constructor(chainId: number, randomContractAddress: Address, precommitDelay: bigint) {
this.chainId = chainId
constructor(transactionManager: TransactionManager, randomContractAddress: Address, precommitDelay: bigint) {
this.transactionManager = transactionManager
this.randomContractAddress = randomContractAddress
this.precommitDelay = precommitDelay
}

create(timestamp: bigint, commitment: Hex): Transaction {
return new Transaction({
chainId: this.chainId,
return this.transactionManager.createTransaction({
address: this.randomContractAddress,
functionName: "postCommitment",
contractName: "Random",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import { Transaction } from "@happychain/transaction-manager"
import type { Transaction, TransactionManager } from "@happychain/transaction-manager"
import type { Address } from "viem"

export class RevealValueTransactionFactory {
private readonly chainId: number
private readonly transactionManager: TransactionManager
private readonly randomContractAddress: Address

constructor(chainId: number, randomContractAddress: Address) {
this.chainId = chainId
constructor(transactionManager: TransactionManager, randomContractAddress: Address) {
this.transactionManager = transactionManager
this.randomContractAddress = randomContractAddress
}

create(timestamp: bigint, revealedValue: bigint): Transaction {
return new Transaction({
chainId: this.chainId,
return this.transactionManager.createTransaction({
address: this.randomContractAddress,
functionName: "revealValue",
contractName: "Random",
Expand Down
16 changes: 7 additions & 9 deletions packages/randomness-service/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,29 +17,27 @@ class RandomnessService {
private readonly revealValueTransactionFactory: RevealValueTransactionFactory
constructor() {
this.commitmentManager = new CommitmentManager()
this.commitmentTransactionFactory = new CommitmentTransactionFactory(
anvil.id,
env.RANDOM_CONTRACT_ADDRESS,
env.PRECOMMIT_DELAY,
)
this.revealValueTransactionFactory = new RevealValueTransactionFactory(anvil.id, env.RANDOM_CONTRACT_ADDRESS)
this.txm = new TransactionManager({
account: privateKeyToAccount(env.PRIVATE_KEY),
transport: webSocket(),
chain: anvil,
id: "randomness-service",
abis: abis,
gasEstimator: new CustomGasEstimator(),
})

this.commitmentTransactionFactory = new CommitmentTransactionFactory(
this.txm,
env.RANDOM_CONTRACT_ADDRESS,
env.PRECOMMIT_DELAY,
)
this.revealValueTransactionFactory = new RevealValueTransactionFactory(this.txm, env.RANDOM_CONTRACT_ADDRESS)
this.txm.start()
this.txm.addTransactionOriginator(this.onCollectTransactions.bind(this))
}

private async onCollectTransactions(block: LatestBlock): Promise<Transaction[]> {
const transactions: Transaction[] = []

// We try to commit the ramdomness POST_COMMIT_MARGIN to be safe that the transaction is included before the PRECOMMIT_DELAY
// We try to commit the randomness POST_COMMIT_MARGIN to be safe that the transaction is included before the PRECOMMIT_DELAY
const commitmentTimestamp = block.timestamp + env.PRECOMMIT_DELAY + env.POST_COMMIT_MARGIN
const commitment = this.commitmentManager.generateCommitment()

Expand Down
11 changes: 7 additions & 4 deletions packages/transaction-manager/lib/Transaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,6 @@ export interface Attempt {
export const NotFinalizedStatuses = [TransactionStatus.Pending, TransactionStatus.Cancelling]

export interface TransactionConstructorConfig {
/**
* The chain ID where the transaction will be sent
*/
chainId: number
/**
* The address of the contract that will be called
*/
Expand Down Expand Up @@ -84,6 +80,8 @@ export interface TransactionConstructorConfig {
export class Transaction {
readonly intentId: UUID

readonly from: Address

readonly chainId: number

readonly address: Address
Expand Down Expand Up @@ -113,6 +111,7 @@ export class Transaction {

constructor({
intentId,
from,
chainId,
address,
functionName,
Expand All @@ -125,13 +124,16 @@ export class Transaction {
updatedAt,
metadata,
}: TransactionConstructorConfig & {
from: Address
chainId: number
intentId?: UUID
status?: TransactionStatus
attempts?: Attempt[]
createdAt?: Date
updatedAt?: Date
}) {
this.intentId = intentId ?? createUUID()
this.from = from
this.chainId = chainId
this.address = address
this.functionName = functionName
Expand Down Expand Up @@ -187,6 +189,7 @@ export class Transaction {
toDbRow(): Insertable<TransactionTable> {
return {
intentId: this.intentId,
from: this.from,
chainId: this.chainId,
address: this.address,
functionName: this.functionName,
Expand Down
19 changes: 14 additions & 5 deletions packages/transaction-manager/lib/TransactionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { DefaultGasLimitEstimator, type GasEstimator } from "./GasEstimator.js"
import { GasPriceOracle } from "./GasPriceOracle.js"
import { HookManager, type TxmHookHandler, type TxmHookType } from "./HookManager.js"
import { NonceManager } from "./NonceManager.js"
import type { Transaction } from "./Transaction.js"
import { Transaction, type TransactionConstructorConfig } from "./Transaction.js"
import { TransactionCollector } from "./TransactionCollector.js"
import { TransactionRepository } from "./TransactionRepository.js"
import { TransactionSubmitter } from "./TransactionSubmitter.js"
Expand All @@ -26,8 +26,6 @@ export type TransactionManagerConfig = {
account: Account
/** The blockchain network configuration. See {@link Chain} from viem for more details. */
chain: Chain
/** A unique identifier for this TransactionManager instance. */
id: string
/** Optional EIP-1559 parameters. If not provided, defaults to the OP stack's stock parameters. */
eip1559?: EIP1559Parameters
/**
Expand Down Expand Up @@ -107,7 +105,6 @@ export class TransactionManager {
public readonly transactionSubmitter: TransactionSubmitter
public readonly hookManager: HookManager

public readonly id: string
public readonly eip1559: EIP1559Parameters
public readonly baseFeeMargin: bigint
public readonly maxPriorityFeePerGas: bigint
Expand Down Expand Up @@ -142,7 +139,6 @@ export class TransactionManager {
this.transactionSubmitter = new TransactionSubmitter(this)
this.hookManager = new HookManager()

this.id = _config.id
this.eip1559 = _config.eip1559 || opStackDefaultEIP1559Parameters
this.abiManager = new ABIManager(_config.abis)

Expand Down Expand Up @@ -177,6 +173,19 @@ export class TransactionManager {
return this.transactionRepository.getTransaction(txIntentId)
}

/**
* Creates a new transaction.
* @param params - {@link TransactionConstructorConfig}.
* @returns A new transaction.
*/
public createTransaction(params: TransactionConstructorConfig): Transaction {
return new Transaction({
...params,
from: this.viemWallet.account.address,
chainId: this.viemWallet.chain.id,
})
}

public async start(): Promise<void> {
// Start the gas price oracle to prevent other parts of the application from calling `suggestGasForNextBlock` before the gas price oracle has initialized the gas price after processing the first block
const priceOraclePromise = this.gasPriceOracle.start()
Expand Down
3 changes: 3 additions & 0 deletions packages/transaction-manager/lib/TransactionRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export class TransactionRepository {
const transactionRows = await db
.selectFrom("transaction")
.where("status", "in", NotFinalizedStatuses)
.where("from", "=", this.transactionManager.viemWallet.account.address)
.selectAll()
.execute()

Expand All @@ -50,6 +51,7 @@ export class TransactionRepository {
const persistedTransaction = await db
.selectFrom("transaction")
.where("intentId", "=", intentId)
.where("from", "=", this.transactionManager.viemWallet.account.address)
.selectAll()
.executeTakeFirst()

Expand Down Expand Up @@ -131,6 +133,7 @@ export class TransactionRepository {
.deleteFrom("transaction")
.where("status", "not in", NotFinalizedStatuses)
.where("updatedAt", "<", Date.now() - this.transactionManager.finalizedTransactionPurgeTime)
.where("from", "=", this.transactionManager.viemWallet.account.address)
.execute()
}
}
1 change: 1 addition & 0 deletions packages/transaction-manager/lib/db/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { TransactionStatus } from "../Transaction"

export interface TransactionTable {
intentId: UUID
from: Address
chainId: number
address: Address
functionName: string
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export async function up(db) {
await db.schema
.alterTable("transaction")
.addColumn("from", "text", (col) => col.notNull())
.execute()
}