diff --git a/src/connectors/rubicon/rubicon.config.ts b/src/connectors/rubicon/rubicon.config.ts index d77a66ae32..e3763e2249 100644 --- a/src/connectors/rubicon/rubicon.config.ts +++ b/src/connectors/rubicon/rubicon.config.ts @@ -11,16 +11,14 @@ export namespace RubiconCLOBConfig { chainType: string; availableNetworks: Array; url: string; - privateKeys: Record; } export const config: NetworkConfig = { tradingTypes: ['CLOB_SPOT'], chainType: 'EVM', - allowedSlippage: "2/100", + allowedSlippage: configManager.get('allowedSlippage'), availableNetworks: [ { chain: 'ethereum', networks: ['mainnet', 'arbitrum', 'arbitrumSepolia', 'optimism', 'base'] } ], url: "https://gladius.rubicon.finance", - privateKeys: configManager.get('rubicon.privateKeys') }; } diff --git a/src/connectors/rubicon/rubicon.ts b/src/connectors/rubicon/rubicon.ts index 5d998d6d7e..5f24c7f46b 100644 --- a/src/connectors/rubicon/rubicon.ts +++ b/src/connectors/rubicon/rubicon.ts @@ -18,9 +18,11 @@ import { } from '../../services/common-interfaces'; import { Network, RubiconCLOBConfig, tokenList } from './rubicon.config'; import { BigNumber, providers, Wallet } from 'ethers'; -import { formatUnits, parseUnits } from 'ethers/lib/utils'; +import { formatUnits, getAddress, parseUnits } from 'ethers/lib/utils'; import { StaticJsonRpcProvider } from '@ethersproject/providers'; import axios from 'axios'; +import { isFractionString } from '../../services/validators'; +import { percentRegexp } from '../../services/config-manager-v2'; export enum ORDER_STATUS { OPEN = 'open', @@ -102,6 +104,7 @@ export class RubiconCLOB implements CLOBish { private static _instances: { [name: string]: RubiconCLOB }; private provider: StaticJsonRpcProvider; private privateKeys: Record; + private slippage: number; private constructor(chain: string, network: string) { @@ -109,8 +112,14 @@ export class RubiconCLOB implements CLOBish { this._chain = Ethereum.getInstance(network); } else throw Error('Chain not supported.'); + if (!process.env.HUMMINGBOT_WALLET_ADDRESS) throw Error("Env variable HUMMINGBOT_WALLET_ADDRESS not set") + if (!process.env.HUMMINGBOT_WALLET_PK) throw Error("Env variable HUMMINGBOT_WALLET_PK not set") + this.provider = new providers.StaticJsonRpcProvider(this._chain.rpcUrl, this._chain.chainId); - this.privateKeys = RubiconCLOBConfig.config.privateKeys; + this.privateKeys = { + [getAddress(process.env.HUMMINGBOT_WALLET_ADDRESS)]: process.env.HUMMINGBOT_WALLET_PK + } + this.slippage = this.getAllowedSlippage(RubiconCLOBConfig.config.allowedSlippage) } public async loadMarkets() { @@ -410,7 +419,7 @@ export class RubiconCLOB implements CLOBish { req: ClobPostOrderRequest ): Promise<{ txHash: string; id: string }> { - const pk = this.privateKeys[req.address] + const pk = this.privateKeys[getAddress(req.address)] if (!pk) throw new Error(`Key for ${req.address} not found`) const wallet = new Wallet(pk).connect(this.provider) @@ -433,6 +442,13 @@ export class RubiconCLOB implements CLOBish { ? parseUnits(parseFloat(req.amount).toFixed(token.decimals), token.decimals) : parseUnits((parseFloat(req.amount) * parseFloat(req.price)).toFixed(quote.decimals), quote.decimals); + let slippageTolerance = this.getAllowedSlippage() / 100; + + const startingOutputFactor = 1; + const startingOutputAmount = parseFloat(formatUnits(outputAmount, outputToken.decimals)) * startingOutputFactor; + const endingOutputFactor = 1 - slippageTolerance; + const endingOutputAmount = parseFloat(formatUnits(outputAmount, outputToken.decimals)) * endingOutputFactor; + const orderBuilder = new GladiusOrderBuilder(this._chain.chainId); const order = orderBuilder @@ -448,8 +464,8 @@ export class RubiconCLOB implements CLOBish { }) .output({ token: outputToken.address, - startAmount: outputAmount, - endAmount: outputAmount, + startAmount: parseUnits(startingOutputAmount.toFixed(outputToken.decimals), outputToken.decimals), + endAmount: parseUnits(endingOutputAmount.toFixed(outputToken.decimals), outputToken.decimals), recipient: req.address, }) .fillThreshold(inputAmount) @@ -478,7 +494,7 @@ export class RubiconCLOB implements CLOBish { req: ClobDeleteOrderRequest ): Promise<{ txHash: string, id: string }> { - const pk = this.privateKeys[req.address] + const pk = this.privateKeys[getAddress(req.address)] if (!pk) throw new Error(`Key for ${req.address} not found`) const wallet = new Wallet(pk).connect(this.provider) @@ -571,4 +587,18 @@ export class RubiconCLOB implements CLOBish { return givenReferencePrice; } } + + public getAllowedSlippage(allowedSlippageStr?: string): number { + if (allowedSlippageStr != null && isFractionString(allowedSlippageStr)) { + const fractionSplit = allowedSlippageStr.split('/'); + return Number((Number(fractionSplit[0]) / Number(fractionSplit[1]) * 100).toFixed(0)); + } + + const allowedSlippage = RubiconCLOBConfig.config.allowedSlippage; + const matches = allowedSlippage.match(percentRegexp); + if (matches) return Number((Number(matches[1]) / Number(matches[2]) * 100).toFixed(0)); + throw new Error( + 'Encountered a malformed percent string in the config for ALLOWED_SLIPPAGE.' + ); + } }