Skip to content

Instantly share code, notes, and snippets.

@livingrock7
Created August 29, 2021 20:37
Show Gist options
  • Save livingrock7/eefcc8ba8fca76899453c8d58fe97b2d to your computer and use it in GitHub Desktop.
Save livingrock7/eefcc8ba8fca76899453c8d58fe97b2d to your computer and use it in GitHub Desktop.
if (shouldForwardWithERC20Forwarder) {
oracleAggregatorContract = blockchain.getContract(
blockchain.getOracleAggregatorAbi(),
blockchain.getOracleAggregatorContractAddress()
);
erc20ForwarderPreFlightCheck = await preFlightChecksService.getPreFlightChecks(
networkId,
oracleAggregatorContract,
request
);
log.info(
`ERC20Forwarder pre flight check result: ${JSON.stringify(
erc20ForwarderPreFlightCheck
)}`
);
}
if (
shouldForwardWithERC20Forwarder &&
!erc20ForwarderPreFlightCheck.readyToPayGasInTokens
) {
log.error(`Error while pre flight checks for token gas price`);
let result = createResponseBodyV2(
STATUSES.TOKEN_PRICE_UNACCEPTABLE,
`Error while pre flight check : ${erc20ForwarderPreFlightCheck.errorMessage}`,
STATUSES.CONFLICT
);
return result;
}
const appRoot = require("app-root-path");
var log = require(`${appRoot}/config/winston`).logger(module);
const config = require(`${appRoot}/config`);
const cache = require(`${appRoot}/src/services/caching`);
const ethers = require("ethers");
const {
getGasPriceKey,
} = require(`${appRoot}/src/controllers/utils/cache-utils`);
const TOKEN_GAS_PRICE_THRESHOLD_PERCENTAGE =
config.TOKEN_GAS_PRICE_THRESHOLD_PERCENTAGE;
const getPreFlightChecks = async (
networkId,
oracleAggregatorContract,
forwardRequest
) => {
let result = {};
result.readyToPayGasInTokens = false;
try {
let gasPriceFromCache = await cache.get(
getGasPriceKey(networkId, config.networksGasPriceType[networkId])
);
let tokenAddress = forwardRequest.token;
const tokenGasPriceFromRequest = ethers.BigNumber.from(
forwardRequest.tokenGasPrice
);
const tokenPriceCurrent = await oracleAggregatorContract.getTokenPrice(
tokenAddress
);
const tokenOracleDecimals = await oracleAggregatorContract.getTokenOracleDecimals(
tokenAddress
);
/* should probably assume use of high gas price and calculate from different sources on the go (upvest,gasstation,etherscan) and avergae out
same for the oracle vs token price fetch apis - coingecko etc
add robustness for calcs
//todo
*/
const gasPrice = ethers.BigNumber.from(
ethers.utils.parseUnits(gasPriceFromCache.toString(), "wei").toString()
);
const tokenGasPriceCurrent = ethers.BigNumber.from(gasPrice)
.mul(ethers.BigNumber.from(10).pow(tokenOracleDecimals))
.div(tokenPriceCurrent);
if (tokenGasPriceCurrent && tokenPriceCurrent && tokenOracleDecimals) {
log.info(`token price ${tokenPriceCurrent.toString()}`);
log.info(`token oracle decimals ${tokenOracleDecimals.toString()}`);
log.info(`token gas price ${tokenGasPriceCurrent.toString()}`);
var minimumTokenGasPriceAccepted = ethers.BigNumber.from(
TOKEN_GAS_PRICE_THRESHOLD_PERCENTAGE
)
.mul(ethers.BigNumber.from(tokenGasPriceCurrent))
.div(ethers.BigNumber.from(100));
if (tokenGasPriceFromRequest.lte(minimumTokenGasPriceAccepted)) {
log.info("Not favorable to process this transaction");
result.errorMessage =
"$token/ETH pair price has dropped beyond threshold";
} else {
result.readyToPayGasInTokens = true;
}
}
} catch (error) {
log.info("Error while getting data points for pre flight checks");
result.errorMessage = error.toString();
log.error(error);
}
log.info(`ready to pay in ERC20 tokens? ${result.readyToPayGasInTokens}`);
return result;
};
module.exports = { getPreFlightChecks };
const appRoot = require("app-root-path");
var log = require(`${appRoot}/config/winston`).logger(module);
const { STATUSES, createResponseBodyV2 } = require(`${appRoot}/src/middleware`);
const { providerMap } = require(`${appRoot}/src/controllers/provider`);
const preFlightChecksService = require(`${appRoot}/src/services/erc20forwarder`);
const config = require(`${appRoot}/config`);
const network = require(`${appRoot}/src/controllers/blockchain/network`);
const ZERO_ADDRESS = config.ETHEREUM_ZERO_ADDRESS;
const validateForwardRequest = async (
request,
metaTransactionType,
networkId
) => {
let validationResponse = {};
validationResponse.success = true;
validationResponse.code = STATUSES.SUCCESS;
var blockchain = providerMap[networkId];
if (!blockchain) {
validationResponse.success = false;
validationResponse.message = `Network with id ${networkId} is not supported`;
validationResponse.code = STATUSES.UNSUPPORTED_NETWORK;
validationResponse.responseCode = STATUSES.CONFLICT;
return validationResponse;
}
let {
from,
to,
token,
txGas,
tokenGasPrice,
batchId,
batchNonce,
deadline,
data,
} = request;
/**
* cases to check here
* i) typeof tokeGasPrice must be string - Check
* ii) typeof txGas must be number - Check
* iii) unsupported tokens are not allowed (ERC20 Forwarder) - Config aid for supported stable coins
* iv) to address should be registered recipient -
*
* v) deadLine is passed - Check
*/
if (typeof txGas != "number" || typeof tokenGasPrice != "string") {
validationResponse.success = false;
validationResponse.message = `"txGas" should be numeric and "tokenGasPrice" should be a string only in the forward request.`;
validationResponse.code = STATUSES.CONFLICT;
return validationResponse;
}
if (deadline < Math.floor(Date.now() / 1000)) {
validationResponse.success = false;
validationResponse.message = `Deadline is exceeded to forward this transaction through trusted forwarder`;
validationResponse.code = STATUSES.CONFLICT;
return validationResponse;
}
if (metaTransactionType == config.metaTransactionType.ERC20_FORWARDER) {
const oracleAggregatorAddress = blockchain.getOracleAggregatorContractAddress();
const oracleAggregatorABI = blockchain.getOracleAggregatorAbi();
if(!oracleAggregatorAddress || !oracleAggregatorABI) {
return createResponseBodyV2(STATUSES.INTERNAL_SERVER_ERROR, "oracleAggreagator address or ABI is not defined");
}
let oracleAggregatorContract = blockchain.getContract(
oracleAggregatorABI,
oracleAggregatorAddress
);
let erc20ForwarderPreFlightCheck = await preFlightChecksService.getPreFlightChecks(
networkId,
oracleAggregatorContract,
request
);
if (!erc20ForwarderPreFlightCheck.readyToPayGasInTokens) {
validationResponse.success = false;
validationResponse.message = `Error while pre flight checks for token gas price`;
validationResponse.code = STATUSES.CONFLICT;
return validationResponse;
}
} else if (
metaTransactionType == config.metaTransactionType.TRUSTED_FORWARDER
) {
if (token != ZERO_ADDRESS || tokenGasPrice != "0") {
validationResponse.success = false;
validationResponse.message = `token should be zero address and tokenGasPrice should be 0 for meta transaction type 'TRUSTED_FORWARDER'`;
validationResponse.code = STATUSES.CONFLICT;
return validationResponse;
}
}
return validationResponse;
};
module.exports = { validateForwardRequest };
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment