Skip to content

Commit

Permalink
Merge pull request #3681 from osmosis-labs/stage
Browse files Browse the repository at this point in the history
Publish Stage
  • Loading branch information
JoseRFelix authored Aug 6, 2024
2 parents 5c61de7 + e59fe52 commit 31bebcc
Show file tree
Hide file tree
Showing 57 changed files with 2,119 additions and 663 deletions.
19 changes: 8 additions & 11 deletions packages/bridge/src/axelar/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export class AxelarBridgeProvider implements BridgeProvider {
protected _queryClient: AxelarQueryAPI | null = null;
protected _assetTransferClient: AxelarAssetTransfer | null = null;
protected protoRegistry = new Registry(ibcProtoRegistry);
protected axelarChainId: string;

protected readonly axelarScanBaseUrl: string;
protected readonly axelarApiBaseUrl: string;
Expand All @@ -64,6 +65,8 @@ export class AxelarBridgeProvider implements BridgeProvider {
this.ctx.env === "mainnet"
? "https://api.axelarscan.io"
: "https://testnet.api.axelarscan.io";
this.axelarChainId =
ctx.env === "mainnet" ? "axelar-dojo-1" : "axelar-testnet-lisbon-3";
}

async getQuote(params: GetBridgeQuoteParams): Promise<BridgeQuote> {
Expand Down Expand Up @@ -568,7 +571,7 @@ export class AxelarBridgeProvider implements BridgeProvider {
});

const timeoutHeight = await this.ctx.getTimeoutHeight({
chainId: toChain.chainId.toString(),
chainId: this.axelarChainId,
});

const ibcAsset = getAssetFromAssetList({
Expand All @@ -578,23 +581,17 @@ export class AxelarBridgeProvider implements BridgeProvider {
});

if (!ibcAsset) {
throw new BridgeQuoteError({
bridgeId: AxelarBridgeProvider.ID,
errorType: "CreateCosmosTxError",
message: "Could not find IBC asset info",
});
throw new Error("Could not find IBC asset info: " + fromAsset.denom);
}

const ibcTransferMethod = ibcAsset.rawAsset.transferMethods.find(
({ type }) => type === "ibc"
) as IbcTransferMethod | undefined;

if (!ibcTransferMethod) {
throw new BridgeQuoteError({
bridgeId: AxelarBridgeProvider.ID,
errorType: "CreateCosmosTxError",
message: "Could not find IBC asset transfer info",
});
throw new Error(
"Could not find IBC asset transfer info: " + ibcAsset.symbol
);
}

const { typeUrl, value: msg } = cosmosMsgOpts.ibcTransfer.messageComposer(
Expand Down
8 changes: 6 additions & 2 deletions packages/bridge/src/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@ export interface BridgeProviderContext {
assetLists: AssetList[];
chainList: Chain[];

/** Provides current timeout height for a chain of given chainId. */
getTimeoutHeight(params: { chainId: string }): Promise<{
/** Provides current timeout height for a chain of given chainId.
* If a destination address is provided, the bech32Prefix will be used to get the chain. */
getTimeoutHeight(params: {
chainId?: string;
destinationAddress?: string;
}): Promise<{
revisionNumber: string | undefined;
revisionHeight: string;
}>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,11 @@ describe("SkipBridgeProvider", () => {

const txRequest = (await provider.createTransaction(
"1",
"osmosis-1",
{
chainId: "osmosis-1",
chainName: "osmosis",
chainType: "cosmos",
},
"0xabc",
messages
)) as EvmBridgeTransactionRequest;
Expand Down
22 changes: 15 additions & 7 deletions packages/bridge/src/skip/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ export class SkipBridgeProvider implements BridgeProvider {
msg.includes(
"Input amount is too low to cover"
// Could be Axelar or CCTP
) ||
msg.includes(
"Difference in USD value of route input and output is too large"
)
) {
throw new BridgeQuoteError({
Expand Down Expand Up @@ -212,7 +215,7 @@ export class SkipBridgeProvider implements BridgeProvider {

const transactionRequest = await this.createTransaction(
fromChain.chainId.toString(),
toChain.chainId.toString(),
toChain,
fromAddress as Address,
msgs
);
Expand Down Expand Up @@ -441,7 +444,7 @@ export class SkipBridgeProvider implements BridgeProvider {

async createTransaction(
fromChainId: string,
toChainId: string,
toChain: BridgeChain,
address: Address,
messages: SkipMsg[]
) {
Expand All @@ -456,15 +459,15 @@ export class SkipBridgeProvider implements BridgeProvider {

if ("multi_chain_msg" in message) {
return await this.createCosmosTransaction(
toChainId,
toChain,
message.multi_chain_msg
);
}
}
}

async createCosmosTransaction(
toChainId: string,
toChain: BridgeChain,
message: SkipMultiChainMsg
): Promise<CosmosBridgeTransactionRequest & { fallbackGasLimit?: number }> {
const messageData = JSON.parse(message.msg);
Expand Down Expand Up @@ -499,9 +502,14 @@ export class SkipBridgeProvider implements BridgeProvider {
} else {
// is an ibc transfer

const timeoutHeight = await this.ctx.getTimeoutHeight({
chainId: toChainId,
});
// If toChain is not cosmos, this IBC transfer is an
// intermediary IBC transfer where we need to get the
// timeout from the bech32 prefix of the receiving address
const timeoutHeight = await this.ctx.getTimeoutHeight(
toChain.chainType === "cosmos"
? toChain
: { destinationAddress: messageData.receiver }
);

const { typeUrl, value } = cosmosMsgOpts.ibcTransfer.messageComposer({
sourcePort: messageData.source_port,
Expand Down
24 changes: 13 additions & 11 deletions packages/bridge/src/squid/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ export class SquidBridgeProvider implements BridgeProvider {
: await this.createCosmosTransaction(
transactionRequest.data,
fromAddress,
toChain.chainId.toString(),
toChain,
{ denom: fromAsset.address, amount: fromAmount }
// TODO: uncomment when we're able to find a way to get gas limit from Squid
// or get it ourselves
Expand Down Expand Up @@ -495,7 +495,7 @@ export class SquidBridgeProvider implements BridgeProvider {
async createCosmosTransaction(
data: string,
fromAddress: string,
toChainId: string,
toChain: BridgeChain,
fromCoin: {
denom: string;
amount: string;
Expand Down Expand Up @@ -533,9 +533,14 @@ export class SquidBridgeProvider implements BridgeProvider {
};
};

const timeoutHeight = await this.ctx.getTimeoutHeight({
chainId: toChainId,
});
// If toChain is not cosmos, this IBC transfer is an
// intermediary IBC transfer where we need to get the
// timeout from the bech32 prefix of the receiving address
const timeoutHeight = await this.ctx.getTimeoutHeight(
toChain.chainType === "cosmos"
? toChain
: { destinationAddress: ibcData.msg.receiver }
);

const { typeUrl, value: msg } =
cosmosMsgOpts.ibcTransfer.messageComposer({
Expand Down Expand Up @@ -587,12 +592,9 @@ export class SquidBridgeProvider implements BridgeProvider {
};
}

throw new BridgeQuoteError({
bridgeId: SquidBridgeProvider.ID,
errorType: "CreateCosmosTxError",
message:
"Unknown message type. Osmosis FrontEnd only supports the IBC transfer and cosmwasm executeMsg message type",
});
throw new Error(
"Unknown message type. Osmosis FrontEnd only supports the IBC transfer and cosmwasm executeMsg message type"
);
} catch (e) {
const error = e as Error | BridgeQuoteError;

Expand Down
1 change: 1 addition & 0 deletions packages/server/src/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const INDEXER_DATA_URL =
export const NUMIA_BASE_URL =
process.env.NEXT_PUBLIC_NUMIA_BASE_URL ??
"https://public-osmosis-api.numia.xyz";
export const NUMIA_API_KEY = process.env.NUMIA_API_KEY;

// sqs
export const SIDECAR_BASE_URL =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
PricePretty,
RatePretty,
} from "@keplr-wallet/unit";
import { maxTick, minTick, tickToSqrtPrice } from "@osmosis-labs/math";
import { BigDec, maxTick, minTick, tickToSqrtPrice } from "@osmosis-labs/math";
import { AssetList, Chain } from "@osmosis-labs/types";
import { aggregateCoinsByDenom, timeout } from "@osmosis-labs/utils";
import cachified, { CacheEntry } from "cachified";
Expand Down Expand Up @@ -395,9 +395,12 @@ export async function mapGetUserPositionDetails({
: undefined;

const currentPrice = getPriceFromSqrtPrice({
sqrtPrice: new Dec(
// Given that we're only calculating for display purposes,
// and not for quoting or provision of liquidity,
// the loss of precision is acceptable.
sqrtPrice: new BigDec(
(pool.raw as ConcentratedPoolRawResponse).current_sqrt_price
),
).toDec(),
baseCoin,
quoteCoin,
});
Expand Down
9 changes: 8 additions & 1 deletion packages/server/src/queries/complex/get-timeout-height.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,20 @@ import { queryRPCStatus } from "../../queries/cosmos";
export async function getTimeoutHeight({
chainList,
chainId,
destinationAddress,
}: {
chainList: Chain[];
chainId: string;
chainId?: string;
/**
* WARNING: bech32 prefix may be the same across different chains,
* retulting in the use of an unintended chain.
*/
destinationAddress?: string;
}) {
const destinationCosmosChain = getChain({
chainList,
chainId,
destinationAddress,
});

if (!destinationCosmosChain) {
Expand Down
1 change: 1 addition & 0 deletions packages/server/src/queries/complex/portfolio/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from "./allocation";
export * from "./portfolio";
49 changes: 49 additions & 0 deletions packages/server/src/queries/complex/portfolio/portfolio.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import cachified, { CacheEntry } from "cachified";
import { LRUCache } from "lru-cache";

import { queryPortfolioOverTime } from "../../../queries/data-services";
import { DEFAULT_LRU_OPTIONS } from "../../../utils/cache";

export type Range = "1d" | "7d" | "1mo" | "1y" | "all";

const transactionsCache = new LRUCache<string, CacheEntry>(DEFAULT_LRU_OPTIONS);

export interface ChartPortfolioOverTimeResponse {
time: number;
value: number;
}

export async function getPortfolioOverTime({
address,
range,
}: {
address: string;
range: Range;
}): Promise<ChartPortfolioOverTimeResponse[]> {
return await cachified({
cache: transactionsCache,
ttl: 1000 * 60, // 60 seconds
key: `portfolio-over-time-${address}-range-${range}`,
getFreshValue: async () => {
const data = await queryPortfolioOverTime({
address,
range,
});

// sort data by timestamp in ascending order for chart
const sortedData = data?.sort(
(a, b) =>
new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
);

// map data to time and value for chart
const mappedData = sortedData.map((d) => ({
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date#get_the_number_of_seconds_since_the_ecmascript_epoch
time: Math.floor(new Date(d.timestamp).getTime() / 1000), // convert to seconds
value: d.usd,
}));

return mappedData;
},
});
}
1 change: 1 addition & 0 deletions packages/server/src/queries/data-services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * from "./filtered-pools";
export * from "./market-cap";
export * from "./pool-aprs";
export * from "./pools-fees";
export * from "./portfolio-over-time";
export * from "./position-performance";
export * from "./price-range-apr";
export * from "./staking-apr";
Expand Down
27 changes: 27 additions & 0 deletions packages/server/src/queries/data-services/portfolio-over-time.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { apiClient } from "@osmosis-labs/utils";

import { NUMIA_BASE_URL } from "../../env";

export interface PortfolioOverTimeResponse {
timestamp: string;
usd: number;
}

export async function queryPortfolioOverTime({
address,
range,
}: {
address: string;
range: string;
}): Promise<PortfolioOverTimeResponse[]> {
const url = new URL("/users/portfolio/over_time", NUMIA_BASE_URL);

url.searchParams.append("address", address);
url.searchParams.append("range", range);

const headers = {
Authorization: `Bearer ${process.env.NUMIA_API_KEY}`,
};

return apiClient<PortfolioOverTimeResponse[]>(url.toString(), { headers });
}
4 changes: 2 additions & 2 deletions packages/server/src/queries/data-services/staking-apr.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { apiClient } from "@osmosis-labs/utils";

import { NUMIA_BASE_URL } from "../../env";
import { NUMIA_API_KEY, NUMIA_BASE_URL } from "../../env";

interface StakingAprResponse {
labels: string;
Expand All @@ -20,7 +20,7 @@ export async function queryStakingApr({
url.searchParams.append("end_date", endDate);

const headers = {
Authorization: `Bearer ${process.env.NEXT_PUBLIC_NUMIA_API_KEY}`,
Authorization: `Bearer ${NUMIA_API_KEY}`,
};

return apiClient<StakingAprResponse[]>(url.toString(), { headers });
Expand Down
2 changes: 1 addition & 1 deletion packages/server/src/queries/data-services/transactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ export async function queryTransactions({
url.searchParams.append("pageSize", pageSize);

const headers = {
Authorization: `Bearer ${process.env.NEXT_PUBLIC_NUMIA_API_KEY}`,
Authorization: `Bearer ${process.env.NUMIA_API_KEY}`,
};

return apiClient<Transaction[]>(url.toString(), { headers });
Expand Down
20 changes: 20 additions & 0 deletions packages/trpc/src/portfolio.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,29 @@
import { getPortfolioOverTime } from "@osmosis-labs/server";
import { getAllocation } from "@osmosis-labs/server";
import { ChartPortfolioOverTimeResponse } from "@osmosis-labs/server/src/queries/complex/portfolio/portfolio";
import { z } from "zod";

import { createTRPCRouter, publicProcedure } from "./api";

export const portfolioRouter = createTRPCRouter({
getPortfolioOverTime: publicProcedure
.input(
z.object({
address: z.string(),
range: z.enum(["1d", "7d", "1mo", "1y", "all"]),
})
)
.query(
async ({
input: { address, range },
}): Promise<ChartPortfolioOverTimeResponse[]> => {
const res = await getPortfolioOverTime({
address,
range,
});
return res;
}
),
getAllocation: publicProcedure
.input(
z.object({
Expand Down
Loading

0 comments on commit 31bebcc

Please sign in to comment.