Skip to content

Commit

Permalink
fix(RREL-026): avoid using PromiseOrValue type in server (#143)
Browse files Browse the repository at this point in the history
* fix(RREL-026): avoid using PromiseOrValue type in server

* refactor(HttpEnvelopingRequest): await properties

* chore(RREL-026): apply PR suggestions

---------

Co-authored-by: Francisco Tobar <[email protected]>
  • Loading branch information
antomor and franciscotobar authored Apr 4, 2024
1 parent 2963dc2 commit 68ed895
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 73 deletions.
6 changes: 3 additions & 3 deletions src/HttpServer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import type { EnvelopingTxRequest } from '@rsksmart/rif-relay-client';
import bodyParser from 'body-parser';
import cors from 'cors';
import express, { Express, Request, Response } from 'express';
Expand All @@ -8,6 +7,7 @@ import jsonrpc, { Defined } from 'jsonrpc-lite';
import log from 'loglevel';
import configureDocumentation from './DocConfiguration';
import type { RelayServer } from './RelayServer';
import type { HttpEnvelopingRequest } from './definitions/HttpEnvelopingRequest';

export type RootHandlerRequestBody = {
id?: number;
Expand Down Expand Up @@ -256,7 +256,7 @@ export class HttpServer {
try {
const { signedTx, txHash } =
await this._relayServer.createRelayTransaction(
body as EnvelopingTxRequest
body as HttpEnvelopingRequest
);
res.send({ signedTx, txHash });
} catch (e) {
Expand Down Expand Up @@ -321,7 +321,7 @@ export class HttpServer {
async estimateHandler(req: Request, res: Response): Promise<void> {
try {
const estimation = await this._relayServer.estimateMaxPossibleGas(
req.body as EnvelopingTxRequest
req.body as HttpEnvelopingRequest
);
res.send(estimation);
} catch (e) {
Expand Down
52 changes: 24 additions & 28 deletions src/RelayServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ import {
PopulatedTransaction,
BigNumber,
providers,
BigNumberish,
} from 'ethers';
import ow from 'ow';
import {
Expand All @@ -45,7 +44,6 @@ import {
} from './Utils';
import { AmountRequired } from './AmountRequired';
import {
EnvelopingTxRequest,
RelayRequest,
estimateRelayMaxPossibleGas,
isDeployRequest,
Expand All @@ -71,6 +69,7 @@ import {
registerEventHandlers,
} from './events';
import { SERVER_VERSION as version } from './version';
import type { HttpEnvelopingRequest } from './definitions/HttpEnvelopingRequest';

type HubInfo = {
relayWorkerAddress: string;
Expand Down Expand Up @@ -245,7 +244,7 @@ export class RelayServer extends EventEmitter {
};
}

validateInputTypes(envelopingTransaction: EnvelopingTxRequest): void {
validateInputTypes(envelopingTransaction: HttpEnvelopingRequest): void {
if (isDeployTransaction(envelopingTransaction)) {
ow(
envelopingTransaction,
Expand All @@ -259,30 +258,33 @@ export class RelayServer extends EventEmitter {
}
}

async validateInput(envelopingRequest: EnvelopingTxRequest): Promise<void> {
const { metadata, relayRequest } = envelopingRequest;
async validateInput(envelopingRequest: HttpEnvelopingRequest): Promise<void> {
const {
metadata: { relayHubAddress: relayHubAddressFromRequest },
relayRequest,
} = envelopingRequest;

const {
app: { requestMinValidSeconds },
contracts: { relayHubAddress },
} = this.config;

const relayHubAddressValue = await metadata.relayHubAddress;

// Check that the relayHub is the correct one
if (relayHubAddressValue.toLowerCase() !== relayHubAddress.toLowerCase()) {
if (
relayHubAddressFromRequest.toLowerCase() !== relayHubAddress.toLowerCase()
) {
throw new Error(
`Wrong hub address.\nRelay server's hub address: ${this.config.contracts.relayHubAddress}, request's hub address: ${relayHubAddressValue}\n`
`Wrong hub address.\nRelay server's hub address: ${this.config.contracts.relayHubAddress}, request's hub address: ${relayHubAddressFromRequest}\n`
);
}

const feesReceiver = await relayRequest.relayData.feesReceiver;
const feesReceiver = relayRequest.relayData.feesReceiver;
// Check the relayWorker (todo: once migrated to multiple relays, check if exists)
if (feesReceiver.toLowerCase() !== this.feesReceiver.toLowerCase()) {
throw new Error(`Wrong fees receiver address: ${feesReceiver}\n`);
}

const gasPrice = await relayRequest.relayData.gasPrice;
const gasPrice = relayRequest.relayData.gasPrice;
// Check that the gasPrice is initialized & acceptable
if (this.gasPrice.gt(gasPrice)) {
throw new Error(
Expand All @@ -297,11 +299,8 @@ export class RelayServer extends EventEmitter {
);
}

async validateVerifier(
envelopingRequest: EnvelopingTxRequest
): Promise<void> {
const callVerifier = await envelopingRequest.relayRequest.relayData
.callVerifier;
validateVerifier(envelopingRequest: HttpEnvelopingRequest): void {
const callVerifier = envelopingRequest.relayRequest.relayData.callVerifier;
if (!this.isTrustedVerifier(callVerifier)) {
throw new Error(`Invalid verifier: ${callVerifier}`);
}
Expand All @@ -318,10 +317,9 @@ export class RelayServer extends EventEmitter {
}

async validateRequestWithVerifier(
envelopingTransaction: EnvelopingTxRequest
envelopingTransaction: HttpEnvelopingRequest
): Promise<void> {
const verifier = await envelopingTransaction.relayRequest.relayData
.callVerifier;
const verifier = envelopingTransaction.relayRequest.relayData.callVerifier;

if (!this.isTrustedVerifier(verifier)) {
throw new Error('Invalid verifier');
Expand Down Expand Up @@ -380,7 +378,7 @@ export class RelayServer extends EventEmitter {
}

async getMaxPossibleGas(
envelopingTransaction: EnvelopingTxRequest
envelopingTransaction: HttpEnvelopingRequest
): Promise<MaxPossibleGas> {
log.debug(
`Enveloping transaction: ${JSON.stringify(
Expand Down Expand Up @@ -418,7 +416,7 @@ export class RelayServer extends EventEmitter {

async maxPossibleGasWithViewCall(
transaction: PopulatedTransaction,
envelopingRequest: EnvelopingTxRequest,
envelopingRequest: HttpEnvelopingRequest,
gasLimit: BigNumber
): Promise<BigNumber> {
log.debug('Relay Server - Request sent to the worker');
Expand All @@ -434,7 +432,7 @@ export class RelayServer extends EventEmitter {

const { maxPossibleGas } = await maxPossibleGasVerification(
transaction,
gasPrice as BigNumberish,
gasPrice,
gasLimit,
this.workerAddress
);
Expand All @@ -443,7 +441,7 @@ export class RelayServer extends EventEmitter {
}

async estimateMaxPossibleGas(
envelopingRequest: EnvelopingTxRequest
envelopingRequest: HttpEnvelopingRequest
): Promise<RelayEstimation> {
log.debug(
`EnvelopingRequest:${JSON.stringify(envelopingRequest, undefined, 4)}`
Expand Down Expand Up @@ -492,7 +490,7 @@ export class RelayServer extends EventEmitter {
}

async createRelayTransaction(
envelopingTransaction: EnvelopingTxRequest
envelopingTransaction: HttpEnvelopingRequest
): Promise<SignedTransactionDetails> {
log.debug(`dump request params: ${JSON.stringify(envelopingTransaction)}`);
if (!this.isReady()) {
Expand Down Expand Up @@ -557,10 +555,8 @@ export class RelayServer extends EventEmitter {

const provider = getProvider();

const relayHubAddress = await envelopingTransaction.metadata
.relayHubAddress;
const gasPrice = await envelopingTransaction.relayRequest.relayData
.gasPrice;
const relayHubAddress = envelopingTransaction.metadata.relayHubAddress;
const gasPrice = envelopingTransaction.relayRequest.relayData.gasPrice;

const currentBlock = await provider.getBlockNumber();
const details: SendTransactionDetails = {
Expand Down
38 changes: 38 additions & 0 deletions src/definitions/HttpEnvelopingRequest.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import type { Either } from '@rsksmart/rif-relay-client/dist/common/utility.types';
import type { BigNumberish } from 'ethers';
import type {
RelayRequestBody as ClientRelayRequestBody,
DeployRequestBody as ClientDeployRequestBody,
} from '@rsksmart/rif-relay-client';

// IMPORTANT: The types defined here mirror the types defined in the client.
// see EnvelopingTxRequest in the rif-relay-client library

type AwaitedWrapper<T> = { [P in keyof T]: Awaited<T[P]> };

export declare type RelayRequestBody = AwaitedWrapper<ClientRelayRequestBody>;

export declare type DeployRequestBody = AwaitedWrapper<ClientDeployRequestBody>;

export declare type EnvelopingMetadata = {
relayHubAddress: RelayRequestBody['relayHub'];
relayMaxNonce: number;
signature: string;
};

export declare type EnvelopingRequestData = {
gasPrice: BigNumberish;
feesReceiver: string;
callForwarder: string;
callVerifier: string;
};

export declare type EnvelopingRequest = {
request: Either<RelayRequestBody, DeployRequestBody>;
relayData: EnvelopingRequestData;
};

export declare type HttpEnvelopingRequest = {
relayRequest: EnvelopingRequest;
metadata: EnvelopingMetadata;
};
47 changes: 23 additions & 24 deletions src/relayServerUtils.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import {
EnvelopingRequest,
estimateInternalCallGas,
getExchangeRate,
EnvelopingTxRequest,
isDeployRequest,
RelayRequestBody,
} from '@rsksmart/rif-relay-client';
import { BigNumber as BigNumberJs } from 'bignumber.js';
import { constants, BigNumber, type BigNumberish } from 'ethers';
Expand All @@ -29,6 +26,11 @@ import {
import log from 'loglevel';
import { INSUFFICIENT_TOKEN_AMOUNT } from './definitions/errorMessages.const';
import type { AppConfig } from './ServerConfigParams';
import type {
EnvelopingRequest,
HttpEnvelopingRequest,
RelayRequestBody,
} from './definitions/HttpEnvelopingRequest';

const TRANSFER_HASH = 'a9059cbb';
const TRANSFER_FROM_HASH = '23b872dd';
Expand All @@ -48,7 +50,7 @@ async function calculateFee(
maxPossibleGas: BigNumber,
appConfig: AppConfig
): Promise<BigNumberJs> {
if (await isSponsorshipAllowed(relayRequest, appConfig)) {
if (isSponsorshipAllowed(relayRequest, appConfig)) {
return BigNumberJs(0);
}

Expand All @@ -64,7 +66,7 @@ async function calculateFee(
}

const { transferFeePercentage } = appConfig;
const data = await relayRequest.request.data;
const data = relayRequest.request.data;
//Even if transferFeePercentage = 0, it has priority over gas fee
if (transferFeePercentage >= 0 && isTransferOrTransferFrom(data.toString())) {
const transferFee = await calculateFeeFromTransfer(
Expand Down Expand Up @@ -101,8 +103,8 @@ async function calculateFixedUsdFee(
envelopingRequest: EnvelopingRequest,
fixedUsdFee: number
): Promise<BigNumberJs> {
const tokenContract = await envelopingRequest.request.tokenContract;
const gasPrice = await envelopingRequest.relayData.gasPrice;
const tokenContract = envelopingRequest.request.tokenContract;
const gasPrice = envelopingRequest.relayData.gasPrice;

const provider = getProvider();

Expand Down Expand Up @@ -148,8 +150,8 @@ async function calculateFeeFromTransfer(
const valueInDecimal = BigNumberJs('0x' + valueHex);

const feeInToken = valueInDecimal.multipliedBy(transferFeePercentage);
const tokenContract = await envelopingRequest.request.tokenContract;
const gasPrice = await envelopingRequest.relayData.gasPrice;
const tokenContract = envelopingRequest.request.tokenContract;
const gasPrice = envelopingRequest.relayData.gasPrice;

return await convertTokenToGas(feeInToken, tokenContract, gasPrice);
}
Expand All @@ -166,15 +168,15 @@ function calculateFeeFromGas(
);
}

async function isSponsorshipAllowed(
function isSponsorshipAllowed(
envelopingRequest: EnvelopingRequest,
config: AppConfig
): Promise<boolean> {
): boolean {
const { disableSponsoredTx, sponsoredDestinations } = config;

return (
!disableSponsoredTx ||
sponsoredDestinations.includes(await envelopingRequest.request.to)
sponsoredDestinations.includes(envelopingRequest.request.to)
);
}

Expand All @@ -184,8 +186,7 @@ function getMethodHashFromData(data: string) {

async function validateIfGasAmountIsAcceptable({
relayRequest,
}: EnvelopingTxRequest) {
// TODO: For RIF Team
}: HttpEnvelopingRequest) {
// The maxPossibleGas must be compared against the commitment signed with the user.
// The relayServer must not allow a call that requires more gas than it was agreed with the user
// For now, we can call estimateDestinationContractCallGas to get the "ACTUAL" gas required for the
Expand Down Expand Up @@ -213,7 +214,7 @@ async function validateIfGasAmountIsAcceptable({
);

const { gas } = request as RelayRequestBody;
const gasValue = await gas;
const gasValue = gas;
const bigGasFromRequestMaxAgreed = bigMaxEstimatedGasDeviation.multipliedBy(
gasValue.toString()
);
Expand All @@ -227,20 +228,18 @@ async function validateIfGasAmountIsAcceptable({

async function validateIfTokenAmountIsAcceptable(
maxPossibleGas: BigNumber,
envelopingTransaction: EnvelopingTxRequest,
envelopingTransaction: HttpEnvelopingRequest,
appConfig: AppConfig
) {
if (
await isSponsorshipAllowed(envelopingTransaction.relayRequest, appConfig)
) {
if (isSponsorshipAllowed(envelopingTransaction.relayRequest, appConfig)) {
return;
}

const { request, relayData } = envelopingTransaction.relayRequest;

const tokenContract = await request.tokenContract;
const tokenAmount = await request.tokenAmount;
const gasPrice = await relayData.gasPrice;
const tokenContract = request.tokenContract;
const tokenAmount = request.tokenAmount;
const gasPrice = relayData.gasPrice;

const tokenAmountInGas = await convertTokenToGas(
tokenAmount,
Expand Down Expand Up @@ -331,8 +330,8 @@ async function convertGasToTokenAndNative(
relayRequest: EnvelopingRequest,
initialEstimation: BigNumber
) {
const gasPrice = await relayRequest.relayData.gasPrice;
const tokenContractAddress = await relayRequest.request.tokenContract;
const gasPrice = relayRequest.relayData.gasPrice;
const tokenContractAddress = relayRequest.request.tokenContract;

let xRate = '1';
let initialEstimationInNative: BigNumber = initialEstimation.mul(gasPrice);
Expand Down
Loading

0 comments on commit 68ed895

Please sign in to comment.