Skip to content

Commit

Permalink
Initial implementation of "feemarket" feature
Browse files Browse the repository at this point in the history
  • Loading branch information
Thunnini committed Jun 21, 2024
1 parent e6f5b1b commit f3ccbae
Show file tree
Hide file tree
Showing 7 changed files with 344 additions and 9 deletions.
130 changes: 122 additions & 8 deletions apps/extension/src/pages/main/components/claim-all/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { CoinPretty, Dec, Int, PricePretty } from "@keplr-wallet/unit";
import {
AminoSignResponse,
BroadcastMode,
FeeCurrency,
StdSignDoc,
} from "@keplr-wallet/types";
import { InExtensionMessageRequester } from "@keplr-wallet/router-extension";
Expand Down Expand Up @@ -286,10 +287,14 @@ export const ClaimAll: FunctionComponent<{ isNotReady?: boolean }> = observer(
account.cosmos.makeWithdrawDelegationRewardTx(validatorAddresses);

(async () => {
let feeCurrency = chainInfo.feeCurrencies.find(
(cur) =>
cur.coinMinimalDenom === chainInfo.stakeCurrency?.coinMinimalDenom
);
// feemarket feature가 있는 경우 이후의 로직에서 사용할 수 있는 fee currency를 찾아야하기 때문에 undefined로 시작시킨다.
let feeCurrency = chainInfo.hasFeature("feemarket")
? undefined
: chainInfo.feeCurrencies.find(
(cur) =>
cur.coinMinimalDenom ===
chainInfo.stakeCurrency?.coinMinimalDenom
);

if (chainInfo.hasFeature("osmosis-base-fee-beta") && feeCurrency) {
const queryBaseFee = queriesStore.get(chainInfo.chainId).osmosis
Expand Down Expand Up @@ -354,7 +359,107 @@ export const ClaimAll: FunctionComponent<{ isNotReady?: boolean }> = observer(
}
| undefined;

for (const chainFeeCurrency of chainInfo.feeCurrencies) {
const feeCurrencies = await (async () => {
if (chainInfo.hasFeature("feemarket")) {
const queryFeeMarketGasPrices =
queriesStore.get(chainId).cosmos.queryFeeMarketGasPrices;
await queryFeeMarketGasPrices.waitFreshResponse();

const result: FeeCurrency[] = [];

for (const gasPrice of queryFeeMarketGasPrices.gasPrices) {
const currency = await chainInfo.findCurrencyAsync(
gasPrice.denom
);
if (currency) {
let multiplication = {
low: 1.1,
average: 1.2,
high: 1.3,
};

const multificationConfig =
queriesStore.simpleQuery.queryGet<{
[str: string]:
| {
low: number;
average: number;
high: number;
}
| undefined;
}>(
"https://gjsttg7mkgtqhjpt3mv5aeuszi0zblbb.lambda-url.us-west-2.on.aws",
"/feemarket/info.json"
);

if (multificationConfig.response) {
const _default =
multificationConfig.response.data["__default__"];
if (
_default &&
_default.low != null &&
typeof _default.low === "number" &&
_default.average != null &&
typeof _default.average === "number" &&
_default.high != null &&
typeof _default.high === "number"
) {
multiplication = {
low: _default.low,
average: _default.average,
high: _default.high,
};
}
const specific =
multificationConfig.response.data[
chainInfo.chainIdentifier
];
if (
specific &&
specific.low != null &&
typeof specific.low === "number" &&
specific.average != null &&
typeof specific.average === "number" &&
specific.high != null &&
typeof specific.high === "number"
) {
multiplication = {
low: specific.low,
average: specific.average,
high: specific.high,
};
}
}

result.push({
...currency,
gasPriceStep: {
low: parseFloat(
new Dec(multiplication.low)
.mul(gasPrice.amount)
.toString()
),
average: parseFloat(
new Dec(multiplication.average)
.mul(gasPrice.amount)
.toString()
),
high: parseFloat(
new Dec(multiplication.high)
.mul(gasPrice.amount)
.toString()
),
},
});
}
}

return result;
} else {
return chainInfo.feeCurrencies;
}
})();
for (const chainFeeCurrency of feeCurrencies) {
const currency = await chainInfo.findCurrencyAsync(
chainFeeCurrency.coinMinimalDenom
);
Expand All @@ -369,23 +474,32 @@ export const ClaimAll: FunctionComponent<{ isNotReady?: boolean }> = observer(
);

if (!prev) {
feeCurrency = currency;
feeCurrency = {
...chainFeeCurrency,
...currency,
};
prev = {
balance: balance.balance,
price,
};
} else {
if (!prev.price) {
if (prev.balance.toDec().lt(balance.balance.toDec())) {
feeCurrency = currency;
feeCurrency = {
...chainFeeCurrency,
...currency,
};
prev = {
balance: balance.balance,
price,
};
}
} else if (price) {
if (prev.price.toDec().lt(price.toDec())) {
feeCurrency = currency;
feeCurrency = {
...chainFeeCurrency,
...currency,
};
prev = {
balance: balance.balance,
price,
Expand Down
13 changes: 13 additions & 0 deletions packages/chain-validator/src/feature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const SupportedChainFeatures = [
"ibc-pfm",
"authz-msg-revoke-fixed",
"osmosis-base-fee-beta",
"feemarket",
];

/**
Expand Down Expand Up @@ -151,6 +152,18 @@ export const RecognizableChainFeaturesMethod: {
return result.status === 400;
},
},
{
feature: "feemarket",
fetch: async (_features, _rpc, rest) => {
const result = await simpleFetch<{
params: {
enabled: boolean;
};
}>(rest, "/feemarket/v1/params");

return result.data.params.enabled;
},
},
];

/**
Expand Down
156 changes: 156 additions & 0 deletions packages/hooks/src/tx/fee.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,35 @@ export class FeeConfig extends TxChainSetter implements IFeeConfig {
return cur1.coinMinimalDenom < cur2.coinMinimalDenom ? -1 : 1;
});
}
} else if (this.canFeeMarketTxFeesAndReady()) {
const queryCosmos = this.queriesStore.get(this.chainId).cosmos;
if (queryCosmos) {
const gasPrices = queryCosmos.queryFeeMarketGasPrices.gasPrices;

const found: FeeCurrency[] = [];
for (const gasPrice of gasPrices) {
const cur = this.chainInfo.findCurrency(gasPrice.denom);
if (cur) {
found.push(cur);
}
}

const firstFeeDenom =
this.chainInfo.feeCurrencies.length > 0
? this.chainInfo.feeCurrencies[0].coinMinimalDenom
: "";
return found.sort((cur1, cur2) => {
// firstFeeDenom should be the first.
// others should be sorted in alphabetical order.
if (cur1.coinMinimalDenom === firstFeeDenom) {
return -1;
}
if (cur2.coinMinimalDenom === firstFeeDenom) {
return 1;
}
return cur1.coinDenom < cur2.coinDenom ? -1 : 1;
});
}
}

const res: FeeCurrency[] = [];
Expand Down Expand Up @@ -409,6 +438,38 @@ export class FeeConfig extends TxChainSetter implements IFeeConfig {
return false;
}

protected canFeeMarketTxFeesAndReady(): boolean {
if (this.chainInfo.hasFeature("feemarket")) {
const queries = this.queriesStore.get(this.chainId);
if (!queries.cosmos) {
console.log(
"Chain has feemarket feature. But no cosmos queries provided."
);
return false;
}

const queryFeeMarketGasPrices = queries.cosmos.queryFeeMarketGasPrices;

if (queryFeeMarketGasPrices.gasPrices.length === 0) {
return false;
}

for (let i = 0; i < queryFeeMarketGasPrices.gasPrices.length; i++) {
const gasPrice = queryFeeMarketGasPrices.gasPrices[i];
// 일단 모든 currency에 대해서 find를 시도한다.
this.chainInfo.findCurrency(gasPrice.denom);
}

return (
queryFeeMarketGasPrices.gasPrices.find((gasPrice) =>
this.chainInfo.findCurrency(gasPrice.denom)
) != null
);
}

return false;
}

protected canEIP1559TxFeesAndReady(): boolean {
if (this.chainInfo.evm && this.senderConfig.sender.startsWith("0x")) {
const queries = this.queriesStore.get(this.chainId);
Expand Down Expand Up @@ -548,6 +609,81 @@ export class FeeConfig extends TxChainSetter implements IFeeConfig {
return this.populateGasPriceStep(baseFeeCurrency, feeType);
}
}
} else if (this.canFeeMarketTxFeesAndReady()) {
const queryCosmos = this.queriesStore.get(this.chainId).cosmos;
if (queryCosmos) {
const gasPrices = queryCosmos.queryFeeMarketGasPrices.gasPrices;

const gasPrice = gasPrices.find(
(gasPrice) => gasPrice.denom === feeCurrency.coinMinimalDenom
);
if (gasPrice) {
let multiplication = {
low: 1.1,
average: 1.2,
high: 1.3,
};

const multificationConfig = this.queriesStore.simpleQuery.queryGet<{
[str: string]:
| {
low: number;
average: number;
high: number;
}
| undefined;
}>(
"https://gjsttg7mkgtqhjpt3mv5aeuszi0zblbb.lambda-url.us-west-2.on.aws",
"/feemarket/info.json"
);

if (multificationConfig.response) {
const _default = multificationConfig.response.data["__default__"];
if (
_default &&
_default.low != null &&
typeof _default.low === "number" &&
_default.average != null &&
typeof _default.average === "number" &&
_default.high != null &&
typeof _default.high === "number"
) {
multiplication = {
low: _default.low,
average: _default.average,
high: _default.high,
};
}
const specific =
multificationConfig.response.data[
this.chainInfo.chainIdentifier
];
if (
specific &&
specific.low != null &&
typeof specific.low === "number" &&
specific.average != null &&
typeof specific.average === "number" &&
specific.high != null &&
typeof specific.high === "number"
) {
multiplication = {
low: specific.low,
average: specific.average,
high: specific.high,
};
}
}
switch (feeType) {
case "low":
return new Dec(multiplication.low).mul(gasPrice.amount);
case "average":
return new Dec(multiplication.average).mul(gasPrice.amount);
case "high":
return new Dec(multiplication.high).mul(gasPrice.amount);
}
}
}
}

if (this.canEIP1559TxFeesAndReady()) {
Expand Down Expand Up @@ -719,6 +855,26 @@ export class FeeConfig extends TxChainSetter implements IFeeConfig {
};
}
}
} else if (this.canFeeMarketTxFeesAndReady()) {
const queryCosmos = this.queriesStore.get(this.chainId).cosmos;
if (queryCosmos) {
const queryFeeMarketGasPrices = queryCosmos.queryFeeMarketGasPrices;
if (queryFeeMarketGasPrices.error) {
return {
warning: new Error("Failed to fetch gas prices"),
};
}
if (!queryFeeMarketGasPrices.response) {
return {
loadingState: "loading-block",
};
}
if (queryFeeMarketGasPrices.isFetching) {
return {
loadingState: "loading",
};
}
}
}

if (this.canOsmosisTxFeesAndReady()) {
Expand Down
5 changes: 4 additions & 1 deletion packages/hooks/src/tx/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import { EthereumQueries } from "@keplr-wallet/stores-eth";
export type QueriesStore = IQueriesStore<
Partial<OsmosisQueries> &
Partial<EthereumQueries> & {
cosmos?: Pick<CosmosQueriesImpl, "queryDelegations">;
cosmos?: Pick<
CosmosQueriesImpl,
"queryDelegations" | "queryFeeMarketGasPrices"
>;
} & {
keplrETC?: Pick<
KeplrETCQueriesImpl,
Expand Down
Loading

0 comments on commit f3ccbae

Please sign in to comment.