Skip to content

Commit

Permalink
feat: apply dynamic fees (#651)
Browse files Browse the repository at this point in the history
  • Loading branch information
jinoosss authored Jan 13, 2025
1 parent 9e24e1c commit 42b006e
Show file tree
Hide file tree
Showing 64 changed files with 2,436 additions and 312 deletions.
5 changes: 3 additions & 2 deletions packages/adena-extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,9 @@
},
"dependencies": {
"@adena-wallet/sdk": "^0.0.2",
"@gnolang/gno-js-client": "1.3.0",
"@gnolang/tm2-js-client": "1.2.1",
"@bufbuild/protobuf": "^2.2.3",
"@gnolang/gno-js-client": "1.3.1",
"@gnolang/tm2-js-client": "1.2.3",
"@tanstack/react-query": "^4.36.1",
"@vespaiach/axios-fetch-adapter": "^0.3.1",
"adena-module": "*",
Expand Down
16 changes: 16 additions & 0 deletions packages/adena-extension/src/assets/icon-right.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* eslint-disable react/no-unknown-property */
import React from 'react';

const IconRight = (): JSX.Element => (
<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='none'>
<path
d='M6 12L10 8L6 4'
stroke='#777777'
stroke-width='1.5'
stroke-linecap='round'
stroke-linejoin='round'
/>
</svg>
);

export default IconRight;
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ export const GNOT_TOKEN = {
symbol: 'GNOT',
decimals: 6,
};

export const GasToken = GNOT_TOKEN;
2 changes: 2 additions & 0 deletions packages/adena-extension/src/common/constants/tx.constant.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export const DEFAULT_GAS_WANTED = 10_000_000;

export const DEFAULT_GAS_FEE = 100_000;

export const DEFAULT_NETWORK_FEE = 1;

export const TRANSACTION_MESSAGE_SEND_OF_REGISTER = '200000000ugnot';
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ChainRepository } from '@repositories/common';
import { TokenRepository } from '@repositories/common/token';
import { FaucetRepository } from '@repositories/faucet/faucet';
import { TransactionHistoryRepository } from '@repositories/transaction';
import { TransactionGasRepository } from '@repositories/transaction/transaction-gas';
import {
WalletAccountRepository,
WalletAddressRepository,
Expand All @@ -12,7 +13,11 @@ import {
} from '@repositories/wallet';
import { FaucetService } from '@services/faucet';
import { ChainService, TokenService } from '@services/resource';
import { TransactionHistoryService, TransactionService } from '@services/transaction';
import {
TransactionGasService,
TransactionHistoryService,
TransactionService,
} from '@services/transaction';
import {
WalletAccountService,
WalletAddressBookService,
Expand All @@ -37,6 +42,7 @@ export interface AdenaContextProps {
transactionService: TransactionService;
transactionHistoryService: TransactionHistoryService;
faucetService: FaucetService;
transactionGasService: TransactionGasService;
}

export const AdenaContext = createContext<AdenaContextProps | null>(null);
Expand Down Expand Up @@ -91,6 +97,11 @@ export const AdenaProvider: React.FC<React.PropsWithChildren<unknown>> = ({ chil
return new TransactionHistoryRepository(axiosInstance, currentNetwork);
}, [axiosInstance, currentNetwork]);

const transactionGasRepository = useMemo(
() => new TransactionGasRepository(gnoProvider, axiosInstance, currentNetwork),
[gnoProvider, transactionHistoryRepository, currentNetwork],
);

const chainService = useMemo(() => new ChainService(chainRepository), [chainRepository]);

const tokenService = useMemo(() => new TokenService(tokenRepository), [tokenRepository]);
Expand Down Expand Up @@ -126,6 +137,11 @@ export const AdenaProvider: React.FC<React.PropsWithChildren<unknown>> = ({ chil
[gnoProvider, transactionHistoryRepository],
);

const transactionGasService = useMemo(
() => new TransactionGasService(transactionGasRepository),
[transactionGasRepository],
);

const faucetRepository = useMemo(() => new FaucetRepository(axios), [axiosInstance]);

const faucetService = useMemo(() => new FaucetService(faucetRepository), [faucetRepository]);
Expand All @@ -145,6 +161,7 @@ export const AdenaProvider: React.FC<React.PropsWithChildren<unknown>> = ({ chil
transactionService,
transactionHistoryService,
faucetService,
transactionGasService,
}}
>
{children}
Expand Down
75 changes: 21 additions & 54 deletions packages/adena-extension/src/common/provider/gno/gno-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@ import { GnoJSONRPCProvider } from '@gnolang/gno-js-client';
import {
ABCIEndpoint,
ABCIResponse,
base64ToUint8Array,
BlockInfo,
BroadcastTxCommitResult,
BroadcastTxSyncResult,
newRequest,
parseABCI,
RPCResponse,
TransactionEndpoint,
Tx,
uint8ArrayToBase64,
} from '@gnolang/tm2-js-client';
import fetchAdapter from '@vespaiach/axios-fetch-adapter';
import { sha256 } from 'adena-module';
import axios from 'axios';
import { ResponseDeliverTx } from './proto/tm2/abci';
import { parseProto } from './utils';

interface ABCIAccount {
BaseAccount: {
Expand Down Expand Up @@ -150,60 +151,26 @@ export class GnoProvider extends GnoJSONRPCProvider {
return response;
}

public waitResultForTransaction(hash: string, timeout?: number): Promise<unknown> {
// eslint-disable-next-line no-async-promise-executor
return new Promise(async (resolve, reject) => {
// Fetch the starting point
let currentHeight = await this.getBlockNumber();

const exitTimeout = timeout ? timeout : 15000;

const fetchInterval = setInterval(async () => {
// Fetch the latest block height
const latestHeight = await this.getBlockNumber();

if (latestHeight < currentHeight) {
// No need to parse older blocks
return;
}

for (let blockNum = currentHeight; blockNum <= latestHeight; blockNum++) {
// Fetch the block from the chain
const block: BlockInfo = await this.getBlock(blockNum);

// Check if there are any transactions at all in the block
if (!block.block.data.txs || block.block.data.txs.length == 0) {
continue;
}
async estimateGas(tx: Tx): Promise<number> {
const encodedTx = uint8ArrayToBase64(Tx.encode(tx).finish());
const params = {
request: newRequest(ABCIEndpoint.ABCI_QUERY, ['.app/simulate', `${encodedTx}`, '0', false]),
};

// Find the transaction among the block transactions
for (const tx of block.block.data.txs) {
// Decode the base-64 transaction
const txRaw = base64ToUint8Array(tx);

// Calculate the transaction hash
const txHash = sha256(txRaw);
const txHashStr = Buffer.from(txHash).toString('base64');
if (txHashStr == hash) {
// Clear the interval
clearInterval(fetchInterval);

// Decode the transaction from amino
const result = await this.getBlockResult(blockNum);
resolve(result);
}
}
}
const abciResponse = await axios.post<RPCResponse<ABCIResponse>>(this.baseURL, params.request, {
adapter: fetchAdapter,
});

currentHeight = latestHeight + 1;
}, 1000);
const responseValue = abciResponse.data.result?.response.Value;
if (!responseValue) {
throw new Error('Failed to estimate gas');
}

setTimeout(() => {
// Clear the fetch interval
clearInterval(fetchInterval);
const simulateResult = parseProto(responseValue, ResponseDeliverTx.decode);
if (simulateResult.responseBase?.error) {
throw new Error(simulateResult.responseBase.error.typeUrl);
}

reject('transaction fetch timeout');
}, exitTimeout);
});
return simulateResult.gasUsed.toInt();
}
}
Loading

0 comments on commit 42b006e

Please sign in to comment.