tomusdrw / rust-web3

Ethereum JSON-RPC multi-transport client. Rust implementation of web3 library. ENS address: rust-web3.eth
MIT License
1.45k stars 465 forks source link

Contract call return value parsing problem #669

Closed litcc closed 1 year ago

litcc commented 1 year ago

When abi is the following result

{
    "inputs": [],
    "name": "slot0",
    "outputs": [
      {
        "internalType": "uint160",
        "name": "sqrtPriceX96",
        "type": "uint160"
      },
      {
        "internalType": "int24",
        "name": "tick",
        "type": "int24"
      },
      {
        "internalType": "uint16",
        "name": "observationIndex",
        "type": "uint16"
      },
      {
        "internalType": "uint16",
        "name": "observationCardinality",
        "type": "uint16"
      },
      {
        "internalType": "uint16",
        "name": "observationCardinalityNext",
        "type": "uint16"
      },
      {
        "internalType": "uint8",
        "name": "feeProtocol",
        "type": "uint8"
      },
      {
        "internalType": "bool",
        "name": "unlocked",
        "type": "bool"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  }

Corresponding contract call code:

contract.query::<Vec<Token>,_,_,_>("slot0",(),None,Options::default(),None)

The code there always reports an error, no matter what I set the return value type to be

https://github.com/tomusdrw/rust-web3/blob/c593b722d57da0c2885123867a7d4662a288d6cc/src/contract/tokens.rs#L20

Because the function returns a list, there may be more than one

https://github.com/tomusdrw/rust-web3/blob/c593b722d57da0c2885123867a7d4662a288d6cc/src/contract/mod.rs#L276

https://github.com/rust-ethereum/ethabi/blob/8501b692587bea8e93bb9440abd35038cb0d6bde/ethabi/src/function.rs#L72

I think this is a bug

litcc commented 1 year ago

Sorry, this may be a misunderstanding, a separate implementation of Detokenize will solve the problem

#[derive(Debug)]
enum OutputData {
    One(Token),
    List(Vec<Token>)
}

impl Detokenize for OutputData {
    fn from_tokens(tokens: Vec<Token>) -> std::result::Result<Self, Error> where Self: Sized {
        if tokens.len() !=1 {
            Ok(OutputData::List(tokens))
        }else {
            Ok(OutputData::One(tokens.first().unwrap().to_owned()))
        }
    }
}
contract.query::<OutputData,_,_,_>("slot0", (), None, Options::default(), None)