Skip to content

Commit

Permalink
Merge branch 'hummingbot:main' into development-merged
Browse files Browse the repository at this point in the history
  • Loading branch information
chasevoorhees authored Jan 12, 2024
2 parents 29ebf90 + 74a9158 commit da50036
Show file tree
Hide file tree
Showing 17 changed files with 1,021 additions and 836 deletions.
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "hummingbot-gateway",
"version": "dev-1.23.0",
"version": "1.23.0",
"description": "Middleware that helps Hummingbot clients access standardized DEX API endpoints on different blockchain networks",
"main": "index.js",
"license": "Apache-2.0",
Expand Down Expand Up @@ -117,7 +117,7 @@
"@types/bs58": "^4.0.1",
"@types/express": "^4.17.12",
"@types/fs-extra": "^9.0.13",
"@types/jest": "^27.4.1",
"@types/jest": "^29.5.11",
"@types/js-yaml": "^4.0.2",
"@types/level": "^6.0.0",
"@types/lodash": "^4.14.178",
Expand All @@ -144,7 +144,7 @@
"eslint-plugin-standard": "^4.0.1",
"google-protobuf": "^3.2.0",
"hardhat": "^2.13.0",
"jest": "^27.3.1",
"jest": "^29.7.0",
"jest-extended": "^0.11.5",
"jsbi": "^3.2.0",
"mock-ethers-provider": "^1.0.2",
Expand All @@ -155,7 +155,7 @@
"react-dom": "^18",
"rimraf": "^3.0.2",
"supertest": "^6.1.6",
"ts-jest": "^27.0.5",
"ts-jest": "^29.1.1",
"ts-node": "^10.0.0",
"typescript": "^5.3.2",
"viem": "^0.3.x"
Expand Down
2 changes: 1 addition & 1 deletion src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ export const startSwagger = async () => {

export const startGateway = async () => {
const port = ConfigManagerV2.getInstance().get('server.port');
const gateway_version="dev-1.23.0"; // gateway version
const gateway_version="1.23.0"; // gateway version
if (!ConfigManagerV2.getInstance().get('server.id')) {
ConfigManagerV2.getInstance().set(
'server.id',
Expand Down
21 changes: 19 additions & 2 deletions src/chains/xrpl/xrpl.controllers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
XRPLBalanceResponse,
XRPLPollRequest,
XRPLPollResponse,
BalanceRecord,
} from './xrpl.requests';

import {
Expand Down Expand Up @@ -48,9 +49,24 @@ export class XRPLController {

const xrplBalances = await xrplish.getAllBalance(wallet);

const balances: Record<string, string> = {};
const xrplSubtractedBalances = await xrplish.subtractBalancesWithOpenOffers(
xrplBalances,
wallet
);

const balances: Record<string, BalanceRecord> = {};
xrplBalances.forEach((balance) => {
balances[balance.currency] = balance.value;
balances[balance.currency] = {
total_balance: balance.value,
available_balance: balance.value,
};
});

xrplSubtractedBalances.forEach((balance) => {
balances[balance.currency] = {
...balances[balance.currency],
available_balance: balance.value,
};
});

return {
Expand All @@ -69,6 +85,7 @@ export class XRPLController {
validateXRPLPollRequest(req);

const initTime = Date.now();
await xrplish.ensureConnection();
const currentLedgerIndex = await xrplish.getCurrentLedgerIndex();
const txData = await xrplish.getTransaction(req.txHash);
const txStatus = await xrplish.getTransactionStatusCode(txData);
Expand Down
7 changes: 6 additions & 1 deletion src/chains/xrpl/xrpl.requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ export interface XRPLBalanceResponse {
timestamp: number;
latency: number;
address: string;
balances: Record<string, string>;
balances: Record<string, BalanceRecord>;
}

export interface BalanceRecord {
total_balance: string;
available_balance: string;
}

export type TokenBalance = {
Expand Down
121 changes: 118 additions & 3 deletions src/chains/xrpl/xrpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
PathFindStream,
TxResponse,
TransactionMetadata,
AccountOffersResponse,
dropsToXrp,
} from 'xrpl';
import axios from 'axios';
import { promises as fs } from 'fs';
Expand All @@ -25,6 +27,7 @@ import { XRPLOrderStorage } from './xrpl.order-storage';
import { OrderTracker } from './xrpl.order-tracker';
import { ReferenceCountingCloseable } from '../../services/refcounting-closeable';
import { XRPLController } from './xrpl.controllers';
import { convertHexToString } from '../../connectors/xrpl/xrpl.utils';

export type XRPTokenInfo = {
id: number;
Expand All @@ -39,7 +42,9 @@ export type MarketInfo = {
id: number;
marketId: string;
baseIssuer: string;
baseCode: string;
quoteIssuer: string;
quoteCode: string;
baseTokenID: number;
quoteTokenID: number;
};
Expand All @@ -58,7 +63,7 @@ export class XRPL implements XRPLish {

protected tokenList: XRPTokenInfo[] = [];
protected marketList: MarketInfo[] = [];
private _tokenMap: Record<string, XRPTokenInfo[]> = {};
private _tokenMap: Record<string, XRPTokenInfo[]> = {}; // TODO: tokenMap should be identified by code and issuer to prevent duplicate codes
private _marketMap: Record<string, MarketInfo[]> = {};

private _client: Client;
Expand All @@ -71,6 +76,8 @@ export class XRPL implements XRPLish {
private _marketListSource: string;
private _tokenListType: TokenListType;
private _marketListType: MarketListType;
private _reserveBaseXrp: number;
private _reserveIncrementXrp: number;

private _ready: boolean = false;
private initializing: boolean = false;
Expand All @@ -91,6 +98,8 @@ export class XRPL implements XRPLish {
this._tokenListType = <TokenListType>config.network.tokenListType;
this._marketListSource = config.network.marketListSource;
this._marketListType = <MarketListType>config.network.marketListType;
this._reserveBaseXrp = 0;
this._reserveIncrementXrp = 0;

this._client = new Client(this.rpcUrl, {
timeout: config.requestTimeout,
Expand Down Expand Up @@ -119,6 +128,10 @@ export class XRPL implements XRPLish {
);
this._orderStorage.declareOwnership(this._refCountingHandle);
this.controller = XRPLController;

this.onDisconnected(async (_code: number) => {
this.ensureConnection();
});
}

public static getInstance(network: string): XRPL {
Expand Down Expand Up @@ -189,6 +202,7 @@ export class XRPL implements XRPLish {
if (!this.ready() && !this.initializing) {
this.initializing = true;
await this.ensureConnection();
await this.getReserveInfo();
await this.loadTokens(this._tokenListSource, this._tokenListType);
await this.loadMarkets(this._marketListSource, this._marketListType);
await this.getFee();
Expand Down Expand Up @@ -270,7 +284,14 @@ export class XRPL implements XRPLish {
}

public getTokenForSymbol(code: string): XRPTokenInfo[] | undefined {
return this._tokenMap[code] ? this._tokenMap[code] : undefined;
let query = code;

// Special case for SOLO on mainnet
if (code === 'SOLO') {
query = '534F4C4F00000000000000000000000000000000';
}

return this._tokenMap[query] ? this._tokenMap[query] : undefined;
}

public getWalletFromSeed(seed: string): Wallet {
Expand Down Expand Up @@ -339,6 +360,24 @@ export class XRPL implements XRPLish {
return balance;
}

async getNativeAvailableBalance(wallet: Wallet): Promise<string> {
await this.ensureConnection();

const AccountInfoResponse = await this._client.request({
command: 'account_info',
account: wallet.address,
});

const ownerItem = AccountInfoResponse.result.account_data.OwnerCount;
const totalReserve =
this._reserveBaseXrp + ownerItem * this._reserveIncrementXrp;

const balance =
parseFloat(await this._client.getXrpBalance(wallet.address)) -
totalReserve;
return balance.toString();
}

async getAllBalance(wallet: Wallet): Promise<Array<TokenBalance>> {
await this.ensureConnection();
const balances: Array<TokenBalance> = [];
Expand All @@ -359,7 +398,7 @@ export class XRPL implements XRPLish {
}

balances.push({
currency: token.currency,
currency: convertHexToString(token.currency),
issuer: token.issuer,
value: token.value,
});
Expand All @@ -383,6 +422,21 @@ export class XRPL implements XRPLish {
}
}

async getReserveInfo() {
await this.ensureConnection();
try {
const reserveInfoResp = await this._client.request({
command: 'server_info',
});
this._reserveBaseXrp =
reserveInfoResp.result.info.validated_ledger?.reserve_base_xrp ?? 0;
this._reserveIncrementXrp =
reserveInfoResp.result.info.validated_ledger?.reserve_inc_xrp ?? 0;
} catch (error) {
throw new Error("Can't get reserve info: " + String(error));
}
}

public get chain(): string {
return this._chain;
}
Expand Down Expand Up @@ -495,6 +549,67 @@ export class XRPL implements XRPLish {
public get orderStorage(): XRPLOrderStorage {
return this._orderStorage;
}

async subtractBalancesWithOpenOffers(
balances: TokenBalance[],
wallet: Wallet
) {
await this.ensureConnection();
const accountOffcersResp: AccountOffersResponse =
await this._client.request({
command: 'account_offers',
account: wallet.address,
});

const offers = accountOffcersResp.result.offers;

// create new balances array with deepcopy
const subtractedBalances: TokenBalance[] = JSON.parse(
JSON.stringify(balances)
);

// Subtract XRP balance with reverses
const xrpBalance = subtractedBalances.find(
(balance) => balance.currency === 'XRP'
);

const currentNativeBalance = await this.getNativeAvailableBalance(wallet);
if (xrpBalance) xrpBalance.value = currentNativeBalance;

// Subtract balances with open offers
if (offers !== undefined) {
offers.forEach((offer) => {
const takerGetsBalance = offer.taker_gets as TokenBalance | string;

if (typeof takerGetsBalance === 'string') {
// XRP open offer, find XRP in balances and subtract it
const xrpBalance = subtractedBalances.find(
(balance) => balance.currency === 'XRP'
);
if (xrpBalance) {
xrpBalance.value = (
parseFloat(xrpBalance.value) -
parseFloat(dropsToXrp(takerGetsBalance))
).toString();
}
} else {
// Token open offer, find token in balances and subtract it
const tokenBalance = subtractedBalances.find(
(balance) =>
balance.currency === convertHexToString(takerGetsBalance.currency)
);
if (tokenBalance) {
tokenBalance.value = (
parseFloat(tokenBalance.value) -
parseFloat(takerGetsBalance.value)
).toString();
}
}
});
}

return subtractedBalances;
}
}

export type XRPLish = XRPL;
Expand Down
Loading

0 comments on commit da50036

Please sign in to comment.