ethers-io / ethers.js

Complete Ethereum library and wallet implementation in JavaScript.
https://ethers.org/
MIT License
7.85k stars 1.82k forks source link

Tuple return values from contract calls cannot be used as parameters in subsequent calls. #4730

Open mountainpath9 opened 3 months ago

mountainpath9 commented 3 months ago

Ethers Version

6.12.1

Search Terms

abi

Describe the Problem

expected:

1) call a contract view method that returns a tuple 2) use the returned tuple as a parameter to a subsequent contract view method call

the second call should succeed

observed:

the second call fails with an exception

Code Snippet

import { Contract, JsonRpcProvider } from "ethers";

const MORPHO_ABI = [
  "function idToMarketParams(bytes32 id) external view returns (address loanToken, address collateralToken, address oracle, address irm, uint256 lltv)",
  "function market(bytes32 id) external view returns (uint128 totalSupplyAssets, uint128 totalSupplyShares, uint128 totalBorrowAssets, uint128 totalBorrowShares, uint128 lastUpdate, uint128 fee)",
];

const IIRM_ABI = [
  "function borrowRateView((address loanToken, address collateralToken, address oracle, address irm, uint256 lltv) memory marketParams, (uint128 totalSupplyAssets, uint128 totalSupplyShares, uint128 totalBorrowAssets, uint128 totalBorrowShares, uint128 lastUpdate, uint128 fee) memory market) external view returns (uint256)",
];

async function broken() {
  const provider = new JsonRpcProvider("https://eth.llamarpc.com");
  const marketId = "0xc581c5f70bd1afa283eed57d1418c6432cbff1d862f94eaf58fdd4e46afbb67f"
  const morpho = new Contract("0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb", MORPHO_ABI, provider);
  const marketParams = await morpho.idToMarketParams(marketId);
  console.log("marketParams", marketParams);
  const market = await morpho.market(marketId);
  console.log("market", market);

  const irm = new Contract(marketParams[3], IIRM_ABI, provider);
  const borrowRate = await irm.borrowRateView(marketParams, market);
  console.log("borrowRate", borrowRate);
}

broken()

Contract ABI

(see code above)

Errors

marketParams Result(5) [
  '0x6B175474E89094C44Da98b954EedeAC495271d0F',
  '0x4c9EDD5852cd905f086C759E8383e09bff1E68B3',
  '0xaE4750d0813B5E37A51f7629beedd72AF1f9cA35',
  '0x870aC11D48B15DB9a138Cf899d20F13F79Ba00BC',
  860000000000000000n
]
market Result(6) [
  143646693420632712048392077n,
  138787440880551261968694027994569n,
  119618520385587078436088379n,
  115178926608471665264960764648817n,
  1715823875n,
  0n
]
/tmp/test/node_modules/ethers/src.ts/abi/fragments.ts:772
                    result[index] = value;
                                 ^

TypeError: Cannot assign to read only property '0' of object '[object Array]'
    at <anonymous> (/tmp/test/node_modules/ethers/src.ts/abi/fragments.ts:772:34)
    at ParamType.#walkAsync (/tmp/test/node_modules/ethers/src.ts/abi/fragments.ts:783:13)
    at <anonymous> (/tmp/test/node_modules/ethers/src.ts/abi/fragments.ts:771:45)
    at Result.forEach (<anonymous>)
    at Proxy.<anonymous> (/tmp/test/node_modules/ethers/src.ts/abi/coders/abstract-coder.ts:118:42)
    at ParamType.#walkAsync (/tmp/test/node_modules/ethers/src.ts/abi/fragments.ts:770:20)
    at ParamType.walkAsync (/tmp/test/node_modules/ethers/src.ts/abi/fragments.ts:797:24)
    at <anonymous> (/tmp/test/node_modules/ethers/src.ts/contract/contract.ts:170:22)
    at Array.map (<anonymous>)
    at resolveArgs (/tmp/test/node_modules/ethers/src.ts/contract/contract.ts:169:37)

Environment

Ethereum (mainnet/ropsten/rinkeby/goerli)

Environment (Other)

No response

mountainpath9 commented 3 months ago

A workaround is to shallow copy the tuples, ie:

  const borrowRate = await irm.borrowRateView([...marketParams], [...market]);

but this: