Skip to content

Commit

Permalink
feat: Implement wallet port communication enhancement (bring changes …
Browse files Browse the repository at this point in the history
…from relayer) (#18)
  • Loading branch information
jsanmigimeno authored Jun 26, 2024
1 parent fc60b08 commit cb725cc
Show file tree
Hide file tree
Showing 12 changed files with 305 additions and 122 deletions.
2 changes: 1 addition & 1 deletion src/expirer/expirer.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ export class ExpirerService implements OnModuleInit {

underwriterPublicKey: this.walletService.publicKey,
monitorPort: await this.monitorService.attachToMonitor(chainId),
walletPort: await this.walletService.attachToWallet(chainId),
walletPort: await this.walletService.attachToWallet(),
loggerOptions: this.loggerService.loggerOptions
};
}
Expand Down
3 changes: 3 additions & 0 deletions src/expirer/expirer.worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class ExpirerWorker {
this.wallet = new WalletInterface(this.config.walletPort);

[this.evalQueue, this.expirerQueue] = this.initializeQueues(
this.chainId,
this.config.minUnderwriteDuration,
this.config.retryInterval,
this.config.maxTries,
Expand Down Expand Up @@ -106,6 +107,7 @@ class ExpirerWorker {
}

private initializeQueues(
chainId: string,
minUnderwriteDuration: number,
retryInterval: number,
maxTries: number,
Expand All @@ -124,6 +126,7 @@ class ExpirerWorker {
)

const expirerQueue = new ExpireQueue(
chainId,
retryInterval,
maxTries,
wallet,
Expand Down
3 changes: 2 additions & 1 deletion src/expirer/queues/expire-queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { tryErrorToString } from "src/common/utils";
export class ExpireQueue extends ProcessingQueue<ExpireOrder, ExpireOrderResult> {

constructor(
private readonly chainId: string,
retryInterval: number,
maxTries: number,
private readonly wallet: WalletInterface,
Expand Down Expand Up @@ -49,7 +50,7 @@ export class ExpireQueue extends ProcessingQueue<ExpireOrder, ExpireOrderResult>
);

//TODO add 'priority' option to wallet
const txPromise = this.wallet.submitTransaction(txRequest, order)
const txPromise = this.wallet.submitTransaction(this.chainId, txRequest, order)
.then((transactionResult): ExpireOrderResult => {
if (transactionResult.submissionError) {
throw transactionResult.submissionError; //TODO wrap in a 'SubmissionError' type?
Expand Down
1 change: 1 addition & 0 deletions src/underwriter/queues/underwrite-queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ export class UnderwriteQueue extends ProcessingQueue<UnderwriteOrder, Underwrite
};

const txPromise = this.wallet.submitTransaction(
this.chainId,
txRequest,
order,
{ deadline: order.submissionDeadline }
Expand Down
2 changes: 2 additions & 0 deletions src/underwriter/token-handler/approval-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export class ApprovalHandler {
private setAllowances = new Map<TokenAddress, bigint>();

constructor(
private readonly chainId: string,
private readonly tokensConfig: TokensConfig,
private readonly interfaceAddress: string,
private readonly walletPublicKey: string,
Expand Down Expand Up @@ -171,6 +172,7 @@ export class ApprovalHandler {
this.setAllowances.set(assetAddress, newSetAllowance);

const result = await this.wallet.submitTransaction(
this.chainId,
txRequest,
approvalDescription,
{
Expand Down
1 change: 1 addition & 0 deletions src/underwriter/token-handler/token-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ export class TokenHandler {
const normalizedInterfaceAddress = interfaceAddress.toLowerCase();

const handler = new ApprovalHandler(
this.chainId,
this.tokens,
normalizedInterfaceAddress,
this.walletPublicKey,
Expand Down
2 changes: 1 addition & 1 deletion src/underwriter/underwriter.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ export class UnderwriterService implements OnModuleInit {
?? defaultConfig.allowanceBuffer,

walletPublicKey: defaultConfig.walletPublicKey,
walletPort: await this.walletService.attachToWallet(chainId),
walletPort: await this.walletService.attachToWallet(),
loggerOptions: this.loggerService.loggerOptions
};
}
Expand Down
109 changes: 67 additions & 42 deletions src/wallet/transaction-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export class TransactionHelper {
);
}


// Config for EIP 1559 transactions
this.maxFeePerGas = config.maxFeePerGas;
this.maxAllowedPriorityFeePerGas = config.maxAllowedPriorityFeePerGas;
Expand Down Expand Up @@ -120,8 +121,8 @@ export class TransactionHelper {
}

/**
* Update the transaction nonce of the signer.
*/
* Update the transaction nonce of the signer.
*/
async updateTransactionNonce(): Promise<void> {
let i = 1;
while (true) {
Expand Down Expand Up @@ -224,78 +225,102 @@ export class TransactionHelper {
}
}

getFeeDataForTransaction(priority?: boolean): GasFeeOverrides {
const queriedFeeData = this.feeData;
if (queriedFeeData == undefined) {
return {};
getCachedFeeData(): FeeData | undefined {
return this.feeData;
}

getAdjustedFeeData(
priority?: boolean,
): FeeData | undefined {
const feeData = {...this.feeData};
if (feeData == undefined) {
return undefined;
}

const queriedMaxPriorityFeePerGas = queriedFeeData.maxPriorityFeePerGas;
if (queriedMaxPriorityFeePerGas != null) {
// Set fee data for an EIP 1559 transactions
let maxFeePerGas = this.maxFeePerGas;
// Override 'maxFeePerGas' if it is specified on the config.
if (this.maxFeePerGas) {
feeData.maxFeePerGas = this.maxFeePerGas;
}

// Adjust the 'maxPriorityFeePerGas' if present.
if (feeData.maxPriorityFeePerGas != undefined) {
// Adjust the 'maxPriorityFeePerGas' by the adjustment factor
let maxPriorityFeePerGas;
if (this.maxPriorityFeeAdjustmentFactor != undefined) {
maxPriorityFeePerGas = queriedMaxPriorityFeePerGas
feeData.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas
* this.maxPriorityFeeAdjustmentFactor
/ DECIMAL_BASE_BIG_INT;
}

// Apply the max allowed 'maxPriorityFeePerGas'
if (
maxPriorityFeePerGas != undefined &&
this.maxAllowedPriorityFeePerGas != undefined &&
this.maxAllowedPriorityFeePerGas < maxPriorityFeePerGas
this.maxAllowedPriorityFeePerGas < feeData.maxPriorityFeePerGas
) {
maxPriorityFeePerGas = this.maxAllowedPriorityFeePerGas;
}

if (priority) {
if (maxFeePerGas != undefined) {
maxFeePerGas = maxFeePerGas * this.priorityAdjustmentFactor / DECIMAL_BASE_BIG_INT;
}

if (maxPriorityFeePerGas != undefined) {
maxPriorityFeePerGas = maxPriorityFeePerGas * this.priorityAdjustmentFactor / DECIMAL_BASE_BIG_INT;
}
feeData.maxPriorityFeePerGas = this.maxAllowedPriorityFeePerGas;
}
}

return {
maxFeePerGas,
maxPriorityFeePerGas,
};
} else {
// Set traditional gasPrice
const queriedGasPrice = queriedFeeData.gasPrice;
if (queriedGasPrice == null) return {};

// Adjust the 'gasPrice' if present.
if (feeData.gasPrice) {
// Adjust the 'gasPrice' by the adjustment factor
let gasPrice;
if (this.gasPriceAdjustmentFactor != undefined) {
gasPrice = queriedGasPrice
feeData.gasPrice = feeData.gasPrice
* this.gasPriceAdjustmentFactor
/ DECIMAL_BASE_BIG_INT;
}

// Apply the max allowed 'gasPrice'
if (
gasPrice != undefined &&
this.maxAllowedGasPrice != undefined &&
this.maxAllowedGasPrice < gasPrice
this.maxAllowedGasPrice < feeData.gasPrice
) {
gasPrice = this.maxAllowedGasPrice;
feeData.gasPrice = this.maxAllowedGasPrice;
}
}

// Apply the 'priority' adjustment factor
if (priority) {
if (feeData.maxFeePerGas != undefined) {
feeData.maxFeePerGas = feeData.maxFeePerGas
*this.priorityAdjustmentFactor
/ DECIMAL_BASE_BIG_INT;
}

if (feeData.maxPriorityFeePerGas != undefined) {
feeData.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas
*this.priorityAdjustmentFactor
/ DECIMAL_BASE_BIG_INT;
}

if (priority && gasPrice != undefined) {
gasPrice = gasPrice
if (feeData.gasPrice != undefined) {
feeData.gasPrice = feeData.gasPrice
* this.priorityAdjustmentFactor
/ DECIMAL_BASE_BIG_INT;
}
}

return new FeeData(
feeData.gasPrice,
feeData.maxFeePerGas,
feeData.maxPriorityFeePerGas
);
}

getFeeDataForTransaction(priority?: boolean): GasFeeOverrides {
const adjustedFeeData = this.getAdjustedFeeData(priority);
if (adjustedFeeData == undefined) {
return {};
}

if (adjustedFeeData.maxPriorityFeePerGas != undefined) {
// Set fee data for EIP 1559 transactions
return {
maxFeePerGas: adjustedFeeData.maxFeePerGas ?? undefined,
maxPriorityFeePerGas: adjustedFeeData.maxPriorityFeePerGas,
};
} else {
return {
gasPrice,
gasPrice: adjustedFeeData.gasPrice ?? undefined,
};
}
}
Expand Down
79 changes: 68 additions & 11 deletions src/wallet/wallet.interface.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { TransactionReceipt, TransactionRequest, TransactionResponse } from 'ethers';
import { FeeData, TransactionReceipt, TransactionRequest, TransactionResponse } from 'ethers';
import { MessagePort } from 'worker_threads';
import { WalletTransactionOptions, WalletTransactionRequestMessage, WalletTransactionRequestResponse } from './wallet.types';
import { WALLET_WORKER_CRASHED_MESSAGE_ID } from './wallet.service';
import { WALLET_WORKER_CRASHED_MESSAGE_ID, WalletFeeDataMessage, WalletGetFeeDataMessage, WalletMessageType, WalletPortData, WalletTransactionOptions, WalletTransactionRequestMessage, WalletTransactionRequestResponseMessage } from './wallet.types';

export interface TransactionResult<T = any> {
txRequest: TransactionRequest;
Expand All @@ -22,6 +21,7 @@ export class WalletInterface {
}

async submitTransaction<T>(
chainId: string,
transaction: TransactionRequest,
metadata?: T,
options?: WalletTransactionOptions
Expand All @@ -30,22 +30,25 @@ export class WalletInterface {
const messageId = this.getNextPortMessageId();

const resultPromise = new Promise<TransactionResult<T>>(resolve => {
const listener = (data: any) => {
const listener = (data: WalletPortData) => {
if (data.messageId === messageId) {
this.port.off("message", listener);

const walletResponse = data as WalletTransactionRequestResponse<T>;
const walletResponse = data.message as WalletTransactionRequestResponseMessage<T>;

const result = {
txRequest: walletResponse.txRequest,
metadata: walletResponse.metadata,
tx: walletResponse.tx,
txReceipt: walletResponse.txReceipt,
submissionError: data.submissionError,
confirmationError: data.confirmationError
submissionError: walletResponse.submissionError,
confirmationError: walletResponse.confirmationError
};
resolve(result);
} else if (data.messageId === WALLET_WORKER_CRASHED_MESSAGE_ID) {
} else if (
data.messageId === WALLET_WORKER_CRASHED_MESSAGE_ID
&& data.chainId == chainId
) {
this.port.off("message", listener);

const result = {
Expand All @@ -59,13 +62,67 @@ export class WalletInterface {
};
this.port.on("message", listener);

const request: WalletTransactionRequestMessage = {
messageId,
const message: WalletTransactionRequestMessage = {
type: WalletMessageType.TransactionRequest,
txRequest: transaction,
metadata,
options
};
this.port.postMessage(request);

const portData: WalletPortData = {
chainId,
messageId,
message,
}
this.port.postMessage(portData);
});

return resultPromise;
}

async getFeeData(
chainId: string,
priority?: boolean,
): Promise<FeeData> {

const messageId = this.getNextPortMessageId();

const resultPromise = new Promise<FeeData>(resolve => {
const listener = (data: WalletPortData) => {
if (data.messageId === messageId) {
this.port.off("message", listener);

const walletResponse = data.message as WalletFeeDataMessage;

const result = {
gasPrice: walletResponse.gasPrice,
maxFeePerGas: walletResponse.maxFeePerGas,
maxPriorityFeePerGas: walletResponse.maxPriorityFeePerGas,
} as FeeData;
resolve(result);
} else if (
data.messageId === WALLET_WORKER_CRASHED_MESSAGE_ID
&& data.chainId == chainId
) {
this.port.off("message", listener);

const result = {} as FeeData;
resolve(result);
}
};
this.port.on("message", listener);

const message: WalletGetFeeDataMessage = {
type: WalletMessageType.GetFeeData,
priority: priority ?? false,
};

const portData: WalletPortData = {
chainId,
messageId,
message,
}
this.port.postMessage(portData);
});

return resultPromise;
Expand Down
Loading

0 comments on commit cb725cc

Please sign in to comment.