Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: apply dynamic fees #651

Merged
merged 14 commits into from
Jan 13, 2025
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;
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
Loading