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

Numbers over 16(?) digits are rounded in contract method fields #1761

Merged
merged 3 commits into from
Apr 1, 2024
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
5 changes: 3 additions & 2 deletions deploy/values/review/values.yaml.gotmpl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ imagePullSecrets:
- name: regcred
config:
network:
id: 5
id: 11155111
name: Blockscout
shortname: Blockscout
currency:
Expand Down Expand Up @@ -65,7 +65,8 @@ frontend:
NEXT_PUBLIC_MARKETPLACE_SUGGEST_IDEAS_FORM: https://airtable.com/appiy5yijZpMMSKjT/pag3t82DUCyhGRZZO/form
NEXT_PUBLIC_LOGOUT_URL: https://blockscoutcom.us.auth0.com/v2/logout
NEXT_PUBLIC_HOMEPAGE_CHARTS: "['daily_txs','coin_price','market_cap']"
NEXT_PUBLIC_NETWORK_RPC_URL: https://rpc.ankr.com/eth_goerli
NEXT_PUBLIC_NETWORK_RPC_URL: https://eth-sepolia.public.blastapi.io
NEXT_PUBLIC_NETWORK_ID: '11155111'
NEXT_PUBLIC_NETWORK_EXPLORERS: "[{'title':'Bitquery','baseUrl':'https://explorer.bitquery.io/','paths':{'tx':'/goerli/tx','address':'/goerli/address','token':'/goerli/token','block':'/goerli/block'}},{'title':'Etherscan','logo':'https://github.com/blockscout/frontend-configs/blob/main/configs/explorer-logos/etherscan.png?raw=true','baseUrl':'https://goerli.etherscan.io/','paths':{'tx':'/tx','address':'/address','token':'/token','block':'/block'}}]"
NEXT_PUBLIC_MARKETPLACE_CATEGORIES_URL: https://raw.github.com/blockscout/frontend-configs/dev/configs/marketplace-categories/default.json
NEXT_PUBLIC_GRAPHIQL_TRANSACTION: 0xf7d4972356e6ae44ae948d0cf19ef2beaf0e574c180997e969a2837da15e349d
Expand Down
4 changes: 2 additions & 2 deletions ui/address/contract/methodForm/useArgTypeMatchInt.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ interface Params {
export interface MatchInt {
isUnsigned: boolean;
power: string;
min: number;
max: number;
min: bigint;
max: bigint;
}

export default function useArgTypeMatchInt({ argType }: Params): MatchInt | null {
Expand Down
5 changes: 4 additions & 1 deletion ui/address/contract/methodForm/useFormatFieldValue.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ export default function useFormatFieldValue({ argType, argTypeMatchInt }: Params
}

if (argTypeMatchInt) {
// we have to store all numbers as strings to avoid precision loss
// and we cannot store them as BigInt because the NumberFormat component will not work properly
// so we just remove all white spaces here otherwise the `viem` library will throw an error on attempt to write value to a contract
const formattedString = value.replace(/\s/g, '');
return parseInt(formattedString);
return formattedString;
}

if (argType === 'bool') {
Expand Down
14 changes: 11 additions & 3 deletions ui/address/contract/methodForm/useValidateField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export default function useValidateField({ isOptional, argType, argTypeMatchInt

// some values are formatted before they are sent to the validator
// see ./useFormatFieldValue.tsx hook
return React.useCallback((value: string | number | boolean | undefined) => {
return React.useCallback((value: string | boolean | undefined) => {
if (value === undefined || value === '') {
return isOptional ? true : 'Field is required';
}
Expand All @@ -41,11 +41,19 @@ export default function useValidateField({ isOptional, argType, argTypeMatchInt
}

if (argTypeMatchInt) {
if (typeof value !== 'number' || Object.is(value, NaN)) {
const valueBi = (() => {
try {
return BigInt(value);
} catch (error) {
return null;
}
})();

if (typeof value !== 'string' || valueBi === null) {
return 'Invalid integer format';
}

if (value > argTypeMatchInt.max || value < argTypeMatchInt.min) {
if (valueBi > argTypeMatchInt.max || valueBi < argTypeMatchInt.min) {
const lowerBoundary = argTypeMatchInt.isUnsigned ? '0' : `-1 * 2 ^ ${ Number(argTypeMatchInt.power) - 1 }`;
const upperBoundary = argTypeMatchInt.isUnsigned ? `2 ^ ${ argTypeMatchInt.power } - 1` : `2 ^ ${ Number(argTypeMatchInt.power) - 1 } - 1`;
return `Value should be in range from "${ lowerBoundary }" to "${ upperBoundary }" inclusively`;
Expand Down
8 changes: 4 additions & 4 deletions ui/address/contract/methodForm/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import _set from 'lodash/set';

import type { SmartContractMethodInput } from 'types/api/contract';

export type ContractMethodFormFields = Record<string, string | boolean | number | undefined>;
export type ContractMethodFormFields = Record<string, string | boolean | undefined>;

export const INT_REGEXP = /^(u)?int(\d+)?$/i;

Expand All @@ -11,9 +11,9 @@ export const BYTES_REGEXP = /^bytes(\d+)?$/i;
export const ARRAY_REGEXP = /^(.*)\[(\d*)\]$/;

export const getIntBoundaries = (power: number, isUnsigned: boolean) => {
const maxUnsigned = 2 ** power;
const max = isUnsigned ? maxUnsigned - 1 : maxUnsigned / 2 - 1;
const min = isUnsigned ? 0 : -maxUnsigned / 2;
const maxUnsigned = BigInt(2 ** power);
const max = isUnsigned ? maxUnsigned - BigInt(1) : maxUnsigned / BigInt(2) - BigInt(1);
const min = isUnsigned ? BigInt(0) : -maxUnsigned / BigInt(2);
return [ min, max ];
};

Expand Down
Loading