tronprotocol / tronweb

Javascript API Library for interacting with the TRON Network
MIT License
446 stars 280 forks source link

TypeError: overflow (argument="value", value=349464387838299168674417, code=INVALID_ARGUMENT, version=6.13.2) #557

Open shestakov2103 opened 2 months ago

shestakov2103 commented 2 months ago

An overflow error occurs when trying to decode smart contract input data using TronWeb's contract.decodeInput() method. The error is thrown because the value being processed is too large to be handled by the system, resulting in an invalid argument error.

Steps to Reproduce:

  1. Set up the environment and install the required dependencies:

    • Node.js version: v21.4.0
    • TronWeb version: 6.13.2
  2. Use the following JavaScript code to reproduce the issue:

    import { TronWeb } from 'tronweb';
    
    (async () => {
       try {
           // Initialize TronWeb with TronGrid API
           const tronWeb = new TronWeb({
               fullHost: 'https://api.trongrid.io',
           });
    
           // TxID: ddaea1e22e40b32dc16f98692047bbf5b0dea073c513ddd3521cd8c798032701
           // Example contract input data
           const contractData = '7ff36ab5000000000000000000000000000000000000000000004a00809eed40b99d92710000000000000000000000000000000000000000000000000000000000000080000000000000000000000000f8723944ea1a271ca894669d777989fa2ade95640000000000000000000000000000000000000000000000000000000066e3364f0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000891cdb91d149f23b1a45d9c5ca78a88d0cb44c180000000000000000000000009cbf59a05d8dfe8e7774efde192ed4fa6cffef32';
    
           // Contract address
           const contractAddress = 'TZFs5ch1R1C4mmjwrrmZqeqbUgGpxY1yWB';
    
           // Get contract instance
           const contract = await tronWeb.contract().at(contractAddress);
    
           // Decode contract input data
           const decode = contract.decodeInput(contractData);
    
           // Print decoded data
           console.log(decode);
       } catch (error) {
           console.error("Error:", error);
       }
    })();
  3. Run the script, and the following error will be thrown:

    TypeError: overflow (argument="value", value=349464387838299168674417, code=INVALID_ARGUMENT, version=6.13.2)
    at makeError (file:///tron-web/node_modules/ethers/lib.esm/utils/errors.js:117:21)
    at assert (file:///tron-web/node_modules/ethers/lib.esm/utils/errors.js:143:15)
    at assertArgument (file:///tron-web/node_modules/ethers/lib.esm/utils/errors.js:154:5)
    at getNumber (file:///tron-web/node_modules/ethers/lib.esm/utils/maths.js:126:13)
    at toNumber (file:///tron-web/node_modules/ethers/lib.esm/utils/maths.js:150:12)
    at Reader.readIndex (file:///tron-web/node_modules/ethers/lib.esm/abi/coders/abstract-coder.js:463:16)
    at file:///tron-web/node_modules/ethers/lib.esm/abi/coders/array.js:64:33
    at Array.forEach (<anonymous>)
    at unpack (file:///tron-web/node_modules/ethers/lib.esm/abi/coders/array.js:61:12)
    at TupleCoder.decode (file:///tron-web/node_modules/ethers/lib.esm/abi/coders/tuple.js:60:16) {
       code: 'INVALID_ARGUMENT',
       argument: 'value',
       value: 349464387838299168674417n,
       shortMessage: 'overflow'
    }
    
    Node.js v21.4.0
Satan-web3 commented 2 months ago

Sorry it's really a problem here. We'll fix it soon. Here is the temporary solution:

  1. Copy the abis from https://tronscan.org/#/contract/TZFs5ch1R1C4mmjwrrmZqeqbUgGpxY1yWB/code
  2. Find the target abi and replace the outputs with inputs
  3. Call utils.abi.decodeParamsV2ByABI Here's the example below:
    
    import { TronWeb, utils } from 'tronweb';

(async () => { try { // Initialize TronWeb with TronGrid API // const tronWeb = new TronWeb({ // fullHost: 'https://api.trongrid.io', // });

    // TxID: ddaea1e22e40b32dc16f98692047bbf5b0dea073c513ddd3521cd8c798032701
    // Example contract input data
    const contractData = '7ff36ab5000000000000000000000000000000000000000000004a00809eed40b99d92710000000000000000000000000000000000000000000000000000000000000080000000000000000000000000f8723944ea1a271ca894669d777989fa2ade95640000000000000000000000000000000000000000000000000000000066e3364f0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000891cdb91d149f23b1a45d9c5ca78a88d0cb44c180000000000000000000000009cbf59a05d8dfe8e7774efde192ed4fa6cffef32';

    // Contract address
    // const contractAddress = 'TZFs5ch1R1C4mmjwrrmZqeqbUgGpxY1yWB';

    // Get contract instance
    // const contract = await tronWeb.contract().at(contractAddress);

    // Decode contract input data
    // const decode = contract.decodeInput(contractData);
    const abis = [{"inputs":[{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_WETH","type":"address"},{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_operator","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOnwer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"amountADesired","type":"uint256"},{"internalType":"uint256","name":"amountBDesired","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountTokenDesired","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"reserveIn","type":"uint256"},{"internalType":"uint256","name":"reserveOut","type":"uint256"}],"name":"getAmountIn","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"reserveIn","type":"uint256"},{"internalType":"uint256","name":"reserveOut","type":"uint256"}],"name":"getAmountOut","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"getAmountsIn","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"getAmountsOut","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"}],"name":"getPairOffChain","outputs":[{"internalType":"address","name":"pair","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPauseState","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"}],"name":"isAllowedTradingPair","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"}],"name":"isSunPumpToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"launchPad","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"operator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pathLimit","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pauseRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"reserveA","type":"uint256"},{"internalType":"uint256","name":"reserveB","type":"uint256"}],"name":"quote","outputs":[{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"removeAllowedTradeToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETHSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermit","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermitSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityWithPermit","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rerunRouter","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"setAllowedTradeToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_launchpad","type":"address"}],"name":"setLaunchPad","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOperator","type":"address"}],"name":"setOperator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newOwner","type":"address"}],"name":"setPendingOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapETHForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETHSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokenWhiteList","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}];
    const abi = abis.find((item) => item.name === 'swapExactETHForTokens');
    abi.outputs = abi.inputs;
    const decode = utils.abi.decodeParamsV2ByABI(
        abi,
        '0x' + contractData.slice(8),
    );

    // Print decoded data
    console.log(decode);
} catch (error) {
    console.error("Error:", error);
}

})();

shestakov2103 commented 2 months ago

Thank you. When you run your code:

Error: TypeError: Cannot mix BigInt and other types, use explicit conversions
    at Reader.subReader (file:///tron-web/node_modules/ethers/lib.esm/abi/coders/abstract-coder.js:446:65)
    at file:///tron-web/node_modules/ethers/lib.esm/abi/coders/array.js:65:43
    at Array.forEach (<anonymous>)
    at unpack (file:///tron-web/node_modules/ethers/lib.esm/abi/coders/array.js:61:12)
    at TupleCoder.decode (file:///tron-web/node_modules/ethers/lib.esm/abi/coders/tuple.js:60:16)
    at AbiCoder.decode (file:///tron-web/node_modules/ethers/lib.esm/abi/abi-coder.js:180:22)
    at Module.decodeParamsV2ByABI (file:///tron-web/node_modules/tronweb/lib/esm/utils/abi.js:238:36)
    at file:///tron-web/abi.js:26:34
    at file:///tron-web/abi.js:36:3
    at ModuleJob.run (node:internal/modules/esm/module_job:218:25)
Satan-web3 commented 2 months ago

Thank you. When you run your code:

Error: TypeError: Cannot mix BigInt and other types, use explicit conversions
    at Reader.subReader (file:///tron-web/node_modules/ethers/lib.esm/abi/coders/abstract-coder.js:446:65)
    at file:///tron-web/node_modules/ethers/lib.esm/abi/coders/array.js:65:43
    at Array.forEach (<anonymous>)
    at unpack (file:///tron-web/node_modules/ethers/lib.esm/abi/coders/array.js:61:12)
    at TupleCoder.decode (file:///tron-web/node_modules/ethers/lib.esm/abi/coders/tuple.js:60:16)
    at AbiCoder.decode (file:///tron-web/node_modules/ethers/lib.esm/abi/abi-coder.js:180:22)
    at Module.decodeParamsV2ByABI (file:///tron-web/node_modules/tronweb/lib/esm/utils/abi.js:238:36)
    at file:///tron-web/abi.js:26:34
    at file:///tron-web/abi.js:36:3
    at ModuleJob.run (node:internal/modules/esm/module_job:218:25)

Can you post your code? I've tested it and it outputs the right answer.

shestakov2103 commented 2 months ago

Thank you, I was able to run your code, here is the result of its execution:

[
  349464387838299168674417n,
  [
    '41891cdb91d149f23b1a45d9c5ca78a88d0cb44c18',
    '419cbf59a05d8dfe8e7774efde192ed4fa6cffef32'
  ],
  '41f8723944ea1a271ca894669d777989fa2ade9564',
  1726166607n,
  amountOutMin: 349464387838299168674417n,
  path: [
    '41891cdb91d149f23b1a45d9c5ca78a88d0cb44c18',
    '419cbf59a05d8dfe8e7774efde192ed4fa6cffef32'
  ],
  to: '41f8723944ea1a271ca894669d777989fa2ade9564',
  deadline: 1726166607n
]

Is it possible to insert a trx transaction in Hex format into TronWeb and decode it to extract the relevant data, such as the method called and the parameters? Something similar to decodeRawTransaction functionality.

Satan-web3 commented 2 months ago

Thank you, I was able to run your code, here is the result of its execution:

[
  349464387838299168674417n,
  [
    '41891cdb91d149f23b1a45d9c5ca78a88d0cb44c18',
    '419cbf59a05d8dfe8e7774efde192ed4fa6cffef32'
  ],
  '41f8723944ea1a271ca894669d777989fa2ade9564',
  1726166607n,
  amountOutMin: 349464387838299168674417n,
  path: [
    '41891cdb91d149f23b1a45d9c5ca78a88d0cb44c18',
    '419cbf59a05d8dfe8e7774efde192ed4fa6cffef32'
  ],
  to: '41f8723944ea1a271ca894669d777989fa2ade9564',
  deadline: 1726166607n
]

Is it possible to insert a trx transaction in Hex format into TronWeb and decode it to extract the relevant data, such as the method called and the parameters? Something similar to decodeRawTransaction functionality.

It is possible to get relevant data from raw_data_hex. We'll consider add this functionality in the next version.