argentlabs / web3.swift

Ethereum Swift API with support for smart contracts, ENS & ERC20
MIT License
668 stars 168 forks source link

Uniswap ABIFunction Call getPool #369

Open wilks7 opened 4 months ago

wilks7 commented 4 months ago

I have having an issue with my Uniswap ABIFunction, the function is defined on the Uniswap V3 Router 0x1F98431c8aD98523631AE4a59f267346ea31F984 getPool(address,address,uint24)

fails with executionError(Code: -32000 Message: execution reverted)

I assume passing BigUInt is sufficient for the uint24 getPool requires

public protocol UniswapProtocol {
    init(client: EthereumRPCProtocol)
    func getPool(
        contract: EthereumAddress,
        tokenIn: EthereumAddress,
        tokenOut: EthereumAddress,
        fee: BigUInt
    ) async throws -> EthereumAddress
}

public class Uniswap: UniswapProtocol {
    public let client: EthereumRPCProtocol

    public required init(client: EthereumRPCProtocol) {
        self.client = client
    }

    public static let v3_router = EthereumAddress("0x1F98431c8aD98523631AE4a59f267346ea31F984")

    public func getPool(
        contract: EthereumAddress = v3_router,
        tokenIn: EthereumAddress,
        tokenOut: EthereumAddress,
        fee: BigUInt = 3000
    ) async throws -> EthereumAddress {
        let function = UniswapFunctions.getPool(contract: contract, tokenIn: tokenIn, tokenOut: tokenOut, fee: fee)
        let response = try await function.call(withClient: client, responseType: UniswapResponses.poolResponse.self)

        return response.value
    }

}

public enum UniswapFunctions {

    struct getPool: ABIFunction {
        static let name = "getPool"

        let contract: EthereumAddress
        let tokenIn: EthereumAddress
        let tokenOut: EthereumAddress
        let fee: BigUInt

        public var gasPrice: BigUInt? = nil
        public var gasLimit: BigUInt? = nil
        public var from: web3.EthereumAddress? = nil

        init(contract: EthereumAddress, tokenIn: EthereumAddress, tokenOut: EthereumAddress, fee: BigUInt) {
            self.contract = contract
            self.tokenIn = tokenIn
            self.tokenOut = tokenOut
            self.fee = fee
        }

        public func encode(to encoder: ABIFunctionEncoder) throws {
            try encoder.encode(tokenIn)
            try encoder.encode(tokenOut)
            try encoder.encode(fee)
        }
    }
}

public enum UniswapResponses {
    public struct poolResponse: ABIResponse, MulticallDecodableResponse {

        public static var types: [ABIType.Type] = [EthereumAddress.self]
        public let value: EthereumAddress

        public init?(values: [ABIDecoder.DecodedValue]) throws {
            self.value = try values[0].decoded()
        }
    }
}
func testGetPool() async {
    let rpc =  INFURA_RPC
    let node = EthereumHttpClient(url: rpc, network: .mainnet)

    let weth = EthereumAddress("0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2")
    let usdc = EthereumAddress("0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48")

    let expectedPool = EthereumAddress("0x8ad599c3A0ff1De082011EFDDc58f1908eb6e6D8")

    let uniswap = Uniswap(client: node)

    do {
        let pool = try await uniswap.getPool(
            tokenIn: weth,
            tokenOut: usdc
        )
        XCTAssertEqual(expectedPool, pool)
    } catch {
        XCTFail("Expected Client to return a WETH - USDC pool \n\(error)")
    }
}
DarthMike commented 4 months ago

Hi @wilks7 I can't get any reading from that contract from etherscan It returns 0x00 Screenshot 2024-04-17 at 17 20 07

wilks7 commented 4 months ago

it seems there is a typo in your query, the uint24 input should be 3000 not 300, it is the percent fee of a Uniswap pool, if there is no pool at the given percent it returns empty address

either way shouldn't the function still return an empty EthereumAddress instead of failing?

DarthMike commented 1 month ago

If the call returns executionError(Code: -32000 Message: execution reverted) the result is correct. It fails executing so defaulting to a specific value is not a good behaviour.