Skip to content

Commit

Permalink
Merge pull request #44 from ThalaLabs/samuel/remove-sentio
Browse files Browse the repository at this point in the history
fetch data from aptos sdk directly, instead of depending on external indexer
  • Loading branch information
SamuelQZQ authored Apr 7, 2024
2 parents 878b4e7 + 952c683 commit 54f6a83
Show file tree
Hide file tree
Showing 11 changed files with 250 additions and 103 deletions.
5 changes: 5 additions & 0 deletions .changeset/lovely-cooks-allow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@thalalabs/router-sdk": major
---

Fetch data from aptos sdk directly, instead of depends on external indexer
Binary file modified bun.lockb
Binary file not shown.
5 changes: 1 addition & 4 deletions examples/examples.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ const account = Account.fromPrivateKey({
privateKey: new Ed25519PrivateKey(privateKey),
});

// `testnet-example-pools.json` contains some testnet pools. The data is not up-to-date.
const router = new ThalaswapRouter(
"https://raw.githubusercontent.com/ThalaLabs/thala-router/main/examples/testnet-example-pools.json",
);
const router = new ThalaswapRouter("https://fullnode.mainnet.aptoslabs.com/v1");

// Example 1: Exact input. 1 hop
async function example1() {
Expand Down
12 changes: 8 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "1.2.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"sideEffects": false,
"scripts": {
"typecheck": "bun run tsc --noEmit",
"build": "bun run tsup ./src/index.ts --dts",
Expand Down Expand Up @@ -32,15 +33,18 @@
"prettier": "3.1.0",
"tsup": "^7.2.0",
"typescript": "^5.2.2",
"@aptos-labs/ts-sdk": "^1.2.0",
"@thalalabs/surf": "^1.1.0"
"@aptos-labs/ts-sdk": "^1.11.0",
"@thalalabs/surf": "^1.3.1",
"@types/lodash": "^4.17.0"
},
"license": "MIT",
"dependencies": {
"axios": "^1.5.1"
"bignumber.js": "^9.1.2",
"lodash": "^4.17.21"
},
"peerDependencies": {
"@thalalabs/surf": "^1.1.0"
"@aptos-labs/ts-sdk": "^1.11.0",
"@thalalabs/surf": "^1.3.1"
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
Expand Down
113 changes: 95 additions & 18 deletions src/PoolDataClient.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,116 @@
import axios from "axios";
import { Coin, PoolData, RawPool, RawPoolData } from "./types";
import { Coin, Pool, PoolData } from "./types";
import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";
import { THALASWAP_RESOURCE_ACCOUNT_ADDRESS } from "./constants";
import { uniq } from "lodash";
import { parsePoolMetadata, scaleDown } from "./utils";

class PoolDataClient {
private poolData: PoolData | null = null;
private lastUpdated: number = 0;
private expiry = 10000; // 10 seconds
private retryLimit = 3;
private URL = "";
private client: Aptos;
private coins: Coin[] = [];

constructor(dataURL: string) {
this.URL = dataURL;
constructor(aptosRpc: string) {
this.client = new Aptos(
new AptosConfig({
network: Network.MAINNET,
fullnode: aptosRpc,
}),
);
}

async getPoolData(): Promise<PoolData> {
const currentTime = Date.now();
if (!this.poolData || currentTime - this.lastUpdated > this.expiry) {
for (let i = 0; i < this.retryLimit; i++) {
try {
const response = await axios.get<RawPoolData>(this.URL);

// Convert the indices in the pools to the actual coin addresses
const coins = response.data.coins as Coin[];
const pools = response.data.pools.map((pool: RawPool) => {
return {
...pool,
asset0: coins[pool.asset0],
asset1: coins[pool.asset1],
asset2: pool.asset2 ? coins[pool.asset2] : undefined,
asset3: pool.asset3 ? coins[pool.asset3] : undefined,
const resources = (
await this.client.getAccountResources({
accountAddress: THALASWAP_RESOURCE_ACCOUNT_ADDRESS,
})
).filter(
(r) =>
r.type.startsWith(
`${THALASWAP_RESOURCE_ACCOUNT_ADDRESS}::weighted_pool::WeightedPool<`,
) ||
r.type.startsWith(
`${THALASWAP_RESOURCE_ACCOUNT_ADDRESS}::stable_pool::StablePool<`,
),
) as {
type: string;
data: {
asset_0: { value: string };
asset_1: { value: string };
asset_2: { value: string };
asset_3: { value: string };
amp_factor?: string;
};
});
}[];

const allCoinAddress = uniq(
resources.reduce((acc, resource) => {
const metadata = parsePoolMetadata(resource.type);
metadata.coinAddresses.forEach((coin) => {
coin && acc.push(coin);
});
return acc;
}, [] as string[]),
);

await Promise.all(
allCoinAddress.map(async (address) => {
if (this.coins.find((c) => c.address === address)) return;
const coin = {
address,
decimals: (
await this.client.view({
payload: {
function: "0x1::coin::decimals",
functionArguments: [],
typeArguments: [
address as `${string}::${string}::${string}`,
],
},
})
)[0] as number,
};
this.coins.push(coin);
}),
);

const pools = resources.reduce((acc, resource) => {
const metadata = parsePoolMetadata(resource.type);
const [coin0, coin1, coin2, coin3] = metadata.coinAddresses.map(
(addr) => this.coins.find((c) => c.address === addr),
);

acc.push({
weights: metadata.weights.map((w) => Number(w) / 100),
poolType: metadata.poolType,
amp: resource.data.amp_factor
? Number(resource.data.amp_factor)
: undefined,
asset0: coin0!,
asset1: coin1!,
asset2: coin2,
asset3: coin3,
balance0: scaleDown(resource.data.asset_0.value, coin0!.decimals),
balance1: scaleDown(resource.data.asset_1.value, coin1!.decimals),
balance2: coin2
? scaleDown(resource.data.asset_2.value, coin2.decimals)
: undefined,
balance3: coin3
? scaleDown(resource.data.asset_3.value, coin3.decimals)
: undefined,
});
return acc;
}, [] as Pool[]);

this.poolData = {
pools,
coins,
coins: this.coins,
};
this.lastUpdated = currentTime;
return this.poolData;
Expand Down
47 changes: 6 additions & 41 deletions src/ThalaswapRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const encodePoolType = (
pool: LiquidityPool,
extendStableArgs: boolean,
): string[] => {
if (pool.poolType === "stable_pool") {
if (pool.poolType === "Stable") {
const typeArgs = NULL_4.map((nullType, i) =>
i < pool.coinAddresses.length ? pool.coinAddresses[i] : nullType,
);
Expand Down Expand Up @@ -80,34 +80,6 @@ class ThalaswapRouter {
this.graph = await this.buildGraph(pools);
}

parseWeightsFromWeightedPoolName(poolName: string): number[] {
const weights: number[] = [];

const tokenWeightPairs = poolName.split(":");

// Iterate over each token-weight pair except the first one (which is just 'W' or 'S')
for (const pair of tokenWeightPairs.slice(1)) {
const parts = pair.split("-");
if (parts.length === 2) {
const weight = parseInt(parts[1], 10);
if (!isNaN(weight)) {
weights.push(weight / 100);
} else {
throw new Error("Invalid weight in pool name");
}
} else {
throw new Error("Invalid token-weight pair in pool name: " + poolName);
}
}

return weights;
}

parseAmpFactorFromStablePoolName(poolName: string): number {
const parts = poolName.split(":");
return parseInt(parts[1]);
}

async buildGraph(pools: Pool[]): Promise<Graph> {
const tokens: Set<string> = new Set();
const graph: Graph = {};
Expand All @@ -122,26 +94,19 @@ class ThalaswapRouter {
.filter((b, i) => assets[i])
.map((b) => pool[b as BalanceIndex] as number);

const poolType = pool.name[0] === "S" ? "stable_pool" : "weighted_pool";
const swapFee =
poolType === "stable_pool"
pool.poolType === "Stable"
? DEFAULT_SWAP_FEE_STABLE
: DEFAULT_SWAP_FEE_WEIGHTED;

const weights =
poolType === "weighted_pool"
? this.parseWeightsFromWeightedPoolName(pool.name)
: undefined;
const weights = pool.poolType === "Weighted" ? pool.weights! : undefined;

const amp =
poolType === "stable_pool"
? this.parseAmpFactorFromStablePoolName(pool.name)
: undefined;
const amp = pool.poolType === "Stable" ? pool.amp! : undefined;

const convertedPool: LiquidityPool = {
coinAddresses: assets.map((a) => a.address),
balances,
poolType,
poolType: pool.poolType,
swapFee,
weights,
amp,
Expand Down Expand Up @@ -258,7 +223,7 @@ class ThalaswapRouter {
const functionName =
route.type === "exact_input" ? "swap_exact_in" : "swap_exact_out";
const abi =
path.pool.poolType === "stable_pool"
path.pool.poolType === "Stable"
? STABLE_POOL_SCRIPTS_ABI
: WEIGHTED_POOL_SCRIPTS_ABI;
const typeArgs = encodePoolType(path.pool, false).concat([
Expand Down
2 changes: 2 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const THALASWAP_RESOURCE_ACCOUNT_ADDRESS =
"0x48271d39d0b05bd6efca2278f22277d6fcc375504f9839fd73f74ace240861af" as const;
12 changes: 6 additions & 6 deletions src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ function calcOutGivenIn(
toIndex: number,
): number {
const { poolType, balances, swapFee, weights, amp } = pool;
if (poolType === "stable_pool") {
if (poolType === "Stable") {
return calcOutGivenInStable(
amountIn,
fromIndex,
Expand All @@ -31,7 +31,7 @@ function calcOutGivenIn(
amp as number,
swapFee,
);
} else if (poolType === "weighted_pool") {
} else if (poolType === "Weighted") {
const weightFrom = weights![fromIndex];
const weightTo = weights![toIndex];
return calcOutGivenInWeighted(
Expand All @@ -58,7 +58,7 @@ function calcInGivenOut(
throw new Error("Insufficient balance");
}

if (poolType === "stable_pool") {
if (poolType === "Stable") {
return calcInGivenOutStable(
amountOut,
fromIndex,
Expand All @@ -67,7 +67,7 @@ function calcInGivenOut(
amp as number,
swapFee,
);
} else if (poolType === "weighted_pool") {
} else if (poolType === "Weighted") {
return calcInGivenOutWeighted(
balances[fromIndex],
weights![fromIndex],
Expand All @@ -90,7 +90,7 @@ function calcPriceImpactPercentage(
toIndex: number,
): number {
const { poolType, balances, weights, amp } = pool;
if (poolType === "stable_pool") {
if (poolType === "Stable") {
return calcPriceImpactPercentageStable(
amountIn,
amountOut,
Expand All @@ -99,7 +99,7 @@ function calcPriceImpactPercentage(
balances,
amp as number,
);
} else if (poolType === "weighted_pool") {
} else if (poolType === "Weighted") {
return calcPriceImpactPercentageWeighted(
amountIn,
amountOut,
Expand Down
13 changes: 11 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,12 @@ type Coin = {
};

type PoolBase = {
name: string;
poolType: "Weighted" | "Stable";
balance0: number;
balance1: number;
balance2?: number;
balance3?: number;
weights: number[];
amp?: number;
};
type RawPool = PoolBase & {
Expand Down Expand Up @@ -65,7 +66,7 @@ type PoolData = {
};

type RouteType = "exact_input" | "exact_output";
type PoolType = "stable_pool" | "weighted_pool";
type PoolType = "Stable" | "Weighted";
type Graph = Record<string, Edge[]>;
type Distances = Record<string, Record<number, number>>;
type Predecessors = Record<
Expand Down Expand Up @@ -93,3 +94,11 @@ export type {
PoolData,
Pool,
};

export type LiquidityPoolMetadata = {
type: string;
poolType: PoolType;
numCoins: number;
coinAddresses: string[];
weights: number[];
};
Loading

0 comments on commit 54f6a83

Please sign in to comment.