Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions apps/ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@
"@solana/spl-token": "^0.3.5",
"@solana/web3.js": "^1.62.0",
"@swim-io/aptos": "workspace:^",
"@swim-io/core": "^0.40.0",
"@swim-io/core": "workspace:^",
"@swim-io/evm": "^0.40.0",
"@swim-io/evm-contracts": "^0.40.0",
"@swim-io/pool-math": "^0.40.0",
"@swim-io/solana": "^0.40.0",
"@swim-io/solana-contracts": "^0.40.0",
"@swim-io/token-projects": "^0.40.0",
"@swim-io/token-projects": "workspace:^",
"@swim-io/utils": "^0.40.0",
"@swim-io/wormhole": "^0.40.0",
"bn.js": "^5.2.1",
Expand Down
6 changes: 5 additions & 1 deletion apps/ui/src/hooks/swim/usePoolMaths.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { bnOrBigNumberToDecimal } from "../../amounts";
import { getTokenDetailsForEcosystem } from "../../config";
import { selectConfig } from "../../core/selectors";
import { useEnvironment } from "../../core/store";
import { Amount, isEvmPoolState } from "../../models";
import { Amount, isAptosPoolState, isEvmPoolState } from "../../models";

import type { PoolData } from "./usePools";
import { usePools } from "./usePools";
Expand Down Expand Up @@ -47,6 +47,10 @@ const getPoolMath = ({
);
}

if (isAptosPoolState(poolState)) {
return null; // TODO aptos
}

if (
poolLpMint === null ||
poolTokenAccounts === null ||
Expand Down
9 changes: 8 additions & 1 deletion apps/ui/src/hooks/swim/usePoolStateQueries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { selectConfig } from "../../core/selectors";
import { useEnvironment } from "../../core/store";
import type { PoolState } from "../../models";
import { getEvmPoolState, getSolanaPoolState } from "../../models";
import { useAptosClient } from "../aptos";
import { useGetEvmClient } from "../evm";
import { useSolanaClient } from "../solana";

Expand All @@ -18,6 +19,7 @@ export const usePoolStateQueries = (
): readonly UseQueryResult<PoolState | null, Error>[] => {
const { env } = useEnvironment();
const { tokens } = useEnvironment(selectConfig, shallow);
const aptosClient = useAptosClient();
const getEvmConnection = useGetEvmClient();
const solanaClient = useSolanaClient();

Expand All @@ -30,7 +32,12 @@ export const usePoolStateQueries = (
return await getSolanaPoolState(solanaClient, poolSpec);
}
if (ecosystem === APTOS_ECOSYSTEM_ID) {
return null; // TODO aptos
const poolState = await aptosClient.getPoolState(poolSpec.id);

return {
...poolState,
ecosystem: APTOS_ECOSYSTEM_ID,
};
}
const evmConnection = getEvmConnection(ecosystem);
const routingContractAddress =
Expand Down
22 changes: 21 additions & 1 deletion apps/ui/src/hooks/swim/usePools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@ import { getSolanaTokenDetails } from "../../config";
import { selectConfig } from "../../core/selectors";
import { useEnvironment } from "../../core/store";
import type { PoolState } from "../../models";
import { getPoolUsdValue, isEvmPoolState } from "../../models";
import {
getPoolUsdValue,
isAptosPoolState,
isEvmPoolState,
} from "../../models";
import {
useSolanaTokenAccountQueries,
useSolanaWallet,
Expand Down Expand Up @@ -73,6 +77,22 @@ const constructPool = (
};
}

if (isAptosPoolState(poolState)) {
return {
spec: poolSpec,
nativeEcosystems,
lpToken,
tokens,
state: poolState,
poolUsdValue: Decimal.sum(...poolState.balances),
isPoolPaused: poolState.isPaused,
// solana based attributes
poolLpMint: null,
poolTokenAccounts: null,
userLpTokenAccount: null,
};
}

if (isEvmPoolState(poolState)) {
return {
spec: poolSpec,
Expand Down
15 changes: 14 additions & 1 deletion apps/ui/src/hooks/swim/useUserLpBalances.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { SOLANA_ECOSYSTEM_ID } from "@swim-io/solana";
import type { EcosystemId, TokenConfig } from "../../config";
import { getTokenDetailsForEcosystem } from "../../config";
import { Amount } from "../../models";
import { useAptosTokenBalanceQuery } from "../aptos";
import { useErc20BalanceQuery } from "../evm";

export const useUserLpBalances = (
Expand Down Expand Up @@ -45,8 +46,20 @@ export const useUserLpBalances = (
? Amount.fromHuman(lpTokenConfig, userLpBalanceBnbHuman)
: null;

// aptos
const aptosTokenDetails =
getTokenDetailsForEcosystem(lpTokenConfig, APTOS_ECOSYSTEM_ID) ?? null;
const { data: userLpBalanceAptosHuman = null } = useAptosTokenBalanceQuery(
aptosTokenDetails,
{ enabled: !!aptosTokenDetails },
);
const userLpBalanceAptos =
aptosTokenDetails && userLpBalanceAptosHuman
? Amount.fromHuman(lpTokenConfig, userLpBalanceAptosHuman)
: null;

return {
[APTOS_ECOSYSTEM_ID]: null,
[APTOS_ECOSYSTEM_ID]: userLpBalanceAptos,
[SOLANA_ECOSYSTEM_ID]: userLpBalanceSolana,
[EvmEcosystemId.Ethereum]: userLpBalanceEthereum,
[EvmEcosystemId.Bnb]: userLpBalanceBnb,
Expand Down
14 changes: 13 additions & 1 deletion apps/ui/src/models/swim/pool.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import { PublicKey } from "@solana/web3.js";
import type { AptosEcosystemId } from "@swim-io/aptos";
import { APTOS_ECOSYSTEM_ID } from "@swim-io/aptos";
import type { PoolState as CorePoolState } from "@swim-io/core";
import type { EvmClient, EvmEcosystemId } from "@swim-io/evm";
import { isEvmEcosystemId } from "@swim-io/evm";
import { Routing__factory } from "@swim-io/evm-contracts";
Expand Down Expand Up @@ -44,7 +47,11 @@ export interface EvmPoolState {
readonly governanceFee: Decimal;
}

export type PoolState = SolanaPoolState | EvmPoolState;
export interface AptosPoolState extends CorePoolState {
readonly ecosystem: AptosEcosystemId;
}

export type PoolState = AptosPoolState | SolanaPoolState | EvmPoolState;

export type TokensByPoolId = ReadonlyRecord<
string, // Pool ID
Expand Down Expand Up @@ -157,6 +164,11 @@ export const isEvmPoolState = (
): poolState is EvmPoolState =>
poolState !== null && isEvmEcosystemId(poolState.ecosystem);

export const isAptosPoolState = (
Comment thread
wormat marked this conversation as resolved.
poolState: PoolState | null,
): poolState is AptosPoolState =>
poolState !== null && poolState.ecosystem === APTOS_ECOSYSTEM_ID;

export const isSolanaPoolState = (
poolState: PoolState,
): poolState is SolanaPoolState => poolState.ecosystem === SOLANA_ECOSYSTEM_ID;
25 changes: 23 additions & 2 deletions apps/ui/src/pages/PoolPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ import {
} from "../hooks";
import BNB_SVG from "../images/ecosystems/bnb.svg";
import ETHEREUM_SVG from "../images/ecosystems/ethereum.svg";
import { isEvmPoolState } from "../models";
import { isAptosPoolState, isEvmPoolState } from "../models";

import "./PoolPage.scss";

Expand Down Expand Up @@ -135,7 +135,27 @@ export const PoolPageInner = ({
);

const reserveStats = tokens.map((tokenConfig, i) => {
const solanaDetails = getSolanaTokenDetails(tokenConfig);
// loading state
if (poolState === null) {
return {
title: <TokenConfigIcon token={tokenConfig} />,
description: "-",
key: tokenConfig.id,
};
}

if (isAptosPoolState(poolState)) {
return {
title: (
<TokenConfigIcon token={tokenConfig} ecosystem={poolSpec.ecosystem} />
),
description: atomicToHumanString(
new Decimal(poolState.balances[i].toString()),
2,
),
key: tokenConfig.id,
};
}

if (isEvmPoolState(poolState)) {
return {
Expand All @@ -150,6 +170,7 @@ export const PoolPageInner = ({
};
}

const solanaDetails = getSolanaTokenDetails(tokenConfig);
const poolTokenAccount =
poolTokenAccounts?.find(
(account) =>
Expand Down
1 change: 1 addition & 0 deletions packages/aptos/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"prepare": "yarn verify && yarn build"
},
"dependencies": {
"@pontem/liquidswap-sdk": "^0.0.1",
"@swim-io/core": "workspace:^",
"@swim-io/token-projects": "workspace:^",
"@swim-io/utils": "workspace:^",
Expand Down
70 changes: 54 additions & 16 deletions packages/aptos/src/client.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { TokenDetails, TxGeneratorResult } from "@swim-io/core";
import type { PoolState, TokenDetails, TxGeneratorResult } from "@swim-io/core";
import { Client } from "@swim-io/core";
import { atomicToHuman } from "@swim-io/utils";
import type { Types } from "aptos";
import { atomicToHuman, findOrThrow } from "@swim-io/utils";
import {
APTOS_COIN,
ApiError,
Expand All @@ -10,31 +9,23 @@ import {
} from "aptos";
import Decimal from "decimal.js";

import { DAO_FEE_DECIMALS, FEE_DECIMALS, getPoolBalances } from "./liquidswap";
import type { PoolResource } from "./liquidswap";
import type {
AptosChainConfig,
AptosEcosystemId,
AptosTx,
AptosTxType,
} from "./protocol";
import { APTOS_ECOSYSTEM_ID } from "./protocol";
import type { CoinInfoResource, CoinResource, GasScheduleV2 } from "./types";
import { getCoinInfoSupply, getCoinInfoType, getCoinStoreType } from "./utils";
import type { AptosWalletAdapter } from "./walletAdapters";

interface GasScheduleV2 {
readonly entries: readonly {
readonly key: string;
readonly value: string;
}[];
}

export interface AptosClientOptions {
readonly endpoint: string;
}

interface CoinResource {
readonly data: { readonly coin: { readonly value: string } };
readonly type: Types.MoveStructTag;
}

export class AptosClient extends Client<
AptosEcosystemId,
AptosChainConfig,
Expand Down Expand Up @@ -71,7 +62,7 @@ export class AptosClient extends Client<
try {
const resource = (await this.sdkClient.getAccountResource(
account.address(),
tokenDetails.address,
getCoinStoreType(tokenDetails.address),
)) as CoinResource;
return atomicToHuman(
new Decimal(resource.data.coin.value),
Expand Down Expand Up @@ -142,4 +133,51 @@ export class AptosClient extends Client<
> {
throw new Error("Not implemented");
}

public async getPoolState(poolId: string): Promise<PoolState> {
const { address, owner, lpTokenId, tokenIds } = findOrThrow(
this.chainConfig.pools,
(poolConfig) => poolConfig.id === poolId,
);
const lpToken = findOrThrow(
Comment thread
wormat marked this conversation as resolved.
this.chainConfig.tokens,
(token) => token.id === lpTokenId,
);
const [tokenX, tokenY]: readonly TokenDetails[] = tokenIds.map(
(tokenId) => {
if (/swimusd$/.test(tokenId)) return this.chainConfig.swimUsdDetails; // TODO is there a better way to do this?
Comment thread
wormat marked this conversation as resolved.

return findOrThrow(
this.chainConfig.tokens,
(token) => token.id === tokenId,
).nativeDetails;
},
);

const [lpTokenSupplyResponse, poolResponse] = await Promise.all([
this.sdkClient.getAccountResource(
owner,
getCoinInfoType(lpToken.nativeDetails.address),
),
this.sdkClient.getAccountResource(owner, address),
]);

const totalLpSupply = getCoinInfoSupply(
lpTokenSupplyResponse as CoinInfoResource,
);
const pool = poolResponse as PoolResource;
const balances = getPoolBalances(pool, [tokenX, tokenY]);

return {
isPaused: false, // TODO ? https://exsphere.slack.com/archives/C03SQTXMFT9/p1666390318707959?thread_ts=1666352227.333479&cid=C03SQTXMFT9
ampFactor: new Decimal("1"), // no ampFactor for liquidswap pool ?
lpFee: atomicToHuman(new Decimal(pool.data.fee), FEE_DECIMALS),
governanceFee: atomicToHuman(
new Decimal(pool.data.dao_fee),
DAO_FEE_DECIMALS,
),
balances,
totalLpSupply,
};
}
}
3 changes: 3 additions & 0 deletions packages/aptos/src/liquidswap/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// From https://github.com/pontem-network/liquidswap/blob/b89aed9adb96c0b083134765f75be814418be670/sources/swap/liquidity_pool.move#L70-L74
export const FEE_DECIMALS = 4;
export const DAO_FEE_DECIMALS = 2;
3 changes: 3 additions & 0 deletions packages/aptos/src/liquidswap/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from "./constants";
export * from "./types";
export * from "./utils";
20 changes: 20 additions & 0 deletions packages/aptos/src/liquidswap/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import type { Types } from "aptos";

export interface PoolResource {
readonly data: {
readonly coin_x_reserve: {
readonly value: string;
};
readonly coin_y_reserve: {
readonly value: string;
};
readonly dao_fee: string;
readonly fee: string;
readonly last_block_timestamp: string;
readonly last_price_x_cumulative: string;
readonly last_price_y_cumulative: string;
readonly x_scale: string;
readonly y_scale: string;
};
readonly type: Types.MoveStructTag;
}
24 changes: 24 additions & 0 deletions packages/aptos/src/liquidswap/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { isSortedSymbols } from "@pontem/liquidswap-sdk/dist/tsc/utils/contracts.js";
import type { PoolState, TokenDetails } from "@swim-io/core";
import { atomicToHuman } from "@swim-io/utils";
import { Decimal } from "decimal.js";

import type { PoolResource } from "./types";

export const getPoolBalances = (
pool: PoolResource,
tokens: readonly [TokenDetails, TokenDetails],
): PoolState["balances"] => {
const reserves = [
pool.data.coin_x_reserve.value,
pool.data.coin_y_reserve.value,
];
const atomicBalances = isSortedSymbols(tokens[0].address, tokens[1].address)
? reserves
: [...reserves].reverse();

return [
atomicToHuman(new Decimal(atomicBalances[0]), tokens[0].decimals),
atomicToHuman(new Decimal(atomicBalances[1]), tokens[1].decimals),
];
};
Loading