Skip to content

Commit

Permalink
Merge pull request #121 from XLabs/feat/lock-free-solana-sui
Browse files Browse the repository at this point in the history
Feat/lock free solana sui
  • Loading branch information
scnale authored Dec 7, 2023
2 parents 2596950 + 9108e35 commit 7fe9f09
Show file tree
Hide file tree
Showing 10 changed files with 66 additions and 20 deletions.
3 changes: 2 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ module.exports = {
},
plugins: ["@typescript-eslint", "unused-imports"],
rules: {
"unused-imports/no-unused-imports-ts": 2,
"unused-imports/no-unused-imports-ts": "error",
"@typescript-eslint/no-empty-function": "off",
},
};
4 changes: 2 additions & 2 deletions src/chain-wallet-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
Wallet,
WalletBalance,
} from "./wallets";
import { TransferRecepit } from "./wallets/base-wallet";
import { TransferReceipt } from "./wallets/base-wallet";
import {
rebalanceStrategies,
RebalanceStrategyName,
Expand Down Expand Up @@ -362,7 +362,7 @@ export class ChainWalletManager {

this.emitter.emit("rebalance-started", strategy, instructions);

const receipts: TransferRecepit[] = [];
const receipts: TransferReceipt[] = [];

for (const instruction of instructions) {
const { sourceAddress, targetAddress, amount } = instruction;
Expand Down
4 changes: 2 additions & 2 deletions src/prometheus-exporter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import Router from 'koa-router';
import { Counter, Gauge, Registry } from 'prom-client';

import { WalletBalance, TokenBalance } from './wallets';
import { TransferRecepit } from './wallets/base-wallet';
import { TransferReceipt } from './wallets/base-wallet';

function updateBalancesGauge(gauge: Gauge, chainName: string, network: string, balance: WalletBalance | TokenBalance) {
const { symbol, address, isNative } = balance;
Expand Down Expand Up @@ -177,7 +177,7 @@ export class PrometheusExporter {
updateWalletsLockPeriodGauge(this.walletsLockPeriodGauge, chainName, network, walletAddress, lockTime);
}

public updateRebalanceSuccess(chainName: string, strategy: string, receipts: TransferRecepit[]) {
public updateRebalanceSuccess(chainName: string, strategy: string, receipts: TransferReceipt[]) {
this.rebalanceInstructionsCounter.labels(chainName, strategy, "success").inc(receipts.length);
const totalExpenditure = receipts.reduce((total, receipt) => {
return total + parseFloat(receipt.formattedCost);
Expand Down
5 changes: 2 additions & 3 deletions src/wallet-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@ import {
WalletBalance,
WalletConfigSchema,
} from "./wallets";
import { TransferRecepit } from "./wallets/base-wallet";
import { TransferReceipt } from "./wallets/base-wallet";
import { RebalanceInstruction } from "./rebalance-strategies";
import { CoinGeckoIdsSchema } from "./price-assistant/supported-tokens.config";
import { ScheduledPriceFeed } from "./price-assistant/scheduled-price-feed";
import { OnDemandPriceFeed } from "./price-assistant/ondemand-price-feed";
import { preparePriceFeedConfig } from "./price-assistant/helper";
import { ChainName } from '../lib/wallets/index';

export const WalletRebalancingConfigSchema = z.object({
enabled: z.boolean(),
Expand Down Expand Up @@ -255,7 +254,7 @@ export class WalletManager {

chainManager.on(
"rebalance-finished",
(strategy: string, receipts: TransferRecepit[]) => {
(strategy: string, receipts: TransferReceipt[]) => {
this.logger.info(
`Rebalance Finished. Executed transactions: ${receipts.length}}`,
);
Expand Down
4 changes: 2 additions & 2 deletions src/wallets/base-wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export type BaseWalletOptions = {
failOnInvalidTokens: boolean;
};

export type TransferRecepit = {
export type TransferReceipt = {
transactionHash: string;
gasUsed: string;
gasPrice: string;
Expand Down Expand Up @@ -74,7 +74,7 @@ export abstract class WalletToolbox {
amount: number,
maxGasPrice?: number,
gasLimit?: number,
): Promise<TransferRecepit>;
): Promise<TransferReceipt>;

protected abstract getRawWallet(privateKey: string): Promise<Wallets>;

Expand Down
4 changes: 2 additions & 2 deletions src/wallets/cosmos/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Wallets } from "../../chain-wallet-manager";
import { PriceFeed } from "../../wallet-manager";
import {
BaseWalletOptions,
TransferRecepit,
TransferReceipt,
WalletToolbox,
} from "../base-wallet";
import {
Expand Down Expand Up @@ -205,7 +205,7 @@ export class CosmosWalletToolbox extends WalletToolbox {
amount: number,
maxGasPrice?: number | undefined,
gasLimit?: number | undefined,
): Promise<TransferRecepit> {
): Promise<TransferReceipt> {
const { addressPrefix, defaultDecimals, nativeDenom, minGasPrice } =
this.chainConfig.defaultConfigs[this.network];
const nodeUrl = this.options.nodeUrl!;
Expand Down
4 changes: 3 additions & 1 deletion src/wallets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ export type Balance = {
};

export type TokenBalance = Balance & {
tokenAddress?: string; // Why can solana tokens not have a token address?
// TODO: put Solana mint address here and make this not optional
// Otherwise handle this as a tagged union if there are other types of tokens there.
tokenAddress?: string;
};

export type WalletBalance = Balance & {
Expand Down
30 changes: 26 additions & 4 deletions src/wallets/solana/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
import { PYTHNET, PYTHNET_CHAIN_CONFIG } from "./pythnet.config";
import {
BaseWalletOptions,
TransferRecepit,
TransferReceipt,
WalletToolbox,
} from "../base-wallet";
import {
Expand Down Expand Up @@ -84,6 +84,7 @@ export class SolanaWalletToolbox extends WalletToolbox {
options: WalletOptions,
priceFeed?: PriceFeed,
) {
// TODO: purge useless wallet pool
super(network, chainName, rawConfig, options);

this.chainConfig = SOLANA_CHAIN_CONFIGS[this.chainName];
Expand Down Expand Up @@ -192,8 +193,8 @@ export class SolanaWalletToolbox extends WalletToolbox {
address,
formattedBalance: formattedBalance.toString(),
symbol: tokenKnownSymbol ?? "unknown",
...(tokenUsdPrice && {
balanceUsd: Number(formattedBalance) * tokenUsdPrice,
...(tokenUsdPrice !== undefined && {
balanceUsd: formattedBalance * tokenUsdPrice,
tokenUsdPrice
})
};
Expand Down Expand Up @@ -261,7 +262,7 @@ export class SolanaWalletToolbox extends WalletToolbox {
sourceAddress: string,
targetAddress: string,
amount: number,
): Promise<TransferRecepit> {
): Promise<TransferReceipt> {
// TODO: implement
throw new Error(
"SolanaWalletToolbox.transferNativeBalance not implemented.",
Expand Down Expand Up @@ -310,4 +311,25 @@ export class SolanaWalletToolbox extends WalletToolbox {
public async getBlockHeight(): Promise<number> {
return this.connection.getBlockHeight(SOLANA_DEFAULT_COMMITMENT);
}

public async acquire(address?: string, acquireTimeout?: number) {
// We'll pick the first one only
const wallets = Object.values(this.wallets).filter(
({ privateKey }) => privateKey !== undefined,
);
if (wallets.length === 0) {
throw new Error("No signer wallet found for Solana.");
}

const wallet = wallets[0];
const privateKey = wallet.privateKey;

return {
address: wallet.address,
// We already checked that the private key is defined above
rawWallet: await this.getRawWallet(privateKey!),
};
}

public async release(address: string): Promise<void> {}
}
26 changes: 24 additions & 2 deletions src/wallets/sui/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { WalletConfig, WalletBalance, TokenBalance } from "../";
import {
WalletToolbox,
BaseWalletOptions,
TransferRecepit, WalletData,
TransferReceipt, WalletData,
} from "../base-wallet";
import {
SuiTokenData,
Expand Down Expand Up @@ -70,6 +70,7 @@ export class SuiWalletToolbox extends WalletToolbox {
options: SuiWalletOptions,
priceFeed?: PriceFeed
) {
// TODO: purge useless wallet pool
super(network, chainName, rawConfig, options);
this.chainConfig = SUI_CHAIN_CONFIGS[this.chainName];

Expand Down Expand Up @@ -246,7 +247,7 @@ export class SuiWalletToolbox extends WalletToolbox {
amount: number,
maxGasPrice?: number,
gasLimit?: number
): Promise<TransferRecepit> {
): Promise<TransferReceipt> {
const txDetails = { targetAddress, amount, maxGasPrice, gasLimit };
return transferSuiNativeBalance(this.connection, privateKey, txDetails);
}
Expand Down Expand Up @@ -277,4 +278,25 @@ export class SuiWalletToolbox extends WalletToolbox {
const sequenceNumber = await suiJsonProvider.getLatestCheckpointSequenceNumber();
return Number(sequenceNumber);
}

public async acquire(address?: string, acquireTimeout?: number) {
// We'll pick the first one only
const wallets = Object.values(this.wallets).filter(
({ privateKey }) => privateKey !== undefined,
);
if (wallets.length === 0) {
throw new Error("No signer wallet found for Sui.");
}

const wallet = wallets[0];
const privateKey = wallet.privateKey;

return {
address: wallet.address,
// We already checked that the private key is defined above
rawWallet: await this.getRawWallet(privateKey!),
};
}

public async release(address: string): Promise<void> {}
}
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"module": "CommonJS",
"moduleResolution": "node",
"lib": [
"es2019"
"es2022"
],
"declaration": true,
"skipLibCheck": true,
Expand Down

0 comments on commit 7fe9f09

Please sign in to comment.