Git Product home page Git Product logo

web3.swift's Introduction

web3.swift: Ethereum API for Swift

Swift

Installation

Swift Package Manager

Use Xcode to add to the project (File -> Swift Packages) or add this to your Package.swift file:

.package(url: "https://github.com/argentlabs/web3.swift", from: "1.1.0")

CocoaPods (not recommended)

Add web3.swift to your Podfile:

pod 'web3.swift'

Then run the following command:

$ pod install

Usage

Getting Started

Create an instance of EthereumAccount with a EthereumKeyStorage provider. This provides a wrapper around your key for web3.swift to use. NOTE We recommend you implement your own KeyStorage provider, instead of relying on the provided EthereumKeyLocalStorage class. This is provided as an example for conformity to the EthereumSingleKeyStorageProtocol.

import web3

// This is just an example. EthereumKeyLocalStorage should not be used in production code
let keyStorage = EthereumKeyLocalStorage()
let account = try? EthereumAccount.create(replacing: keyStorage, keystorePassword: "MY_PASSWORD")

Create an instance of EthereumHttpClient or EthereumWebSocketClient. This will then provide you access to a set of functions for interacting with the Blockchain.

EthereumHttpClient

guard let clientUrl = URL(string: "https://an-infura-or-similar-url.com/123") else { return }
let client = EthereumHttpClient(url: clientUrl)

OR

EthereumWebSocketClient

guard let clientUrl = URL(string: "wss://sepolia.infura.io/ws/v3//123") else { return }
let client = EthereumWebSocketClient(url: clientUrl)

You can then interact with the client methods, such as to get the current gas price:

client.eth_gasPrice { (error, currentPrice) in
    print("The current gas price is \(currentPrice)")
}

If using async/await you can await on the result

let gasPrice = try await client.eth_gasPrice()

Smart contracts: Static types

Given a smart contract function ABI like ERC20 transfer:

function transfer(address recipient, uint256 amount) public returns (bool)

then you can define an ABIFunction with corresponding encodable Swift types like so:

public struct Transfer: ABIFunction {
    public static let name = "transfer"
    public let gasPrice: BigUInt? = nil
    public let gasLimit: BigUInt? = nil
    public var contract: EthereumAddress
    public let from: EthereumAddress?

    public let to: EthereumAddress
    public let value: BigUInt

    public init(contract: EthereumAddress,
                from: EthereumAddress? = nil,
                to: EthereumAddress,
                value: BigUInt) {
        self.contract = contract
        self.from = from
        self.to = to
        self.value = value
    }

    public func encode(to encoder: ABIFunctionEncoder) throws {
        try encoder.encode(to)
        try encoder.encode(value)
    }
}

This function can be used to generate contract call transactions to send with the client:

let function = transfer(contract: "0xtokenaddress", from: "0xfrom", to: "0xto", value: 100)
let transaction = try function.transaction()

client.eth_sendRawTransaction(transaction, withAccount: account) { (error, txHash) in
    print("TX Hash: \(txHash)")
}

If using async/await you can await on the result

let txHash = try await client.eth_sendRawTransaction(transaction, withAccount: account)

Generating ABI from a smart contract ABI file

Currently we don't support code generation as making it properly is a bigger project, and should possibly live outside of this repository.

You can try this project instead: imanrep/swiftabigen

Data types

The library provides some types and helpers to make interacting with web3 and Ethereum easier.

  • EthereumAddress: For representation of addresses, including checksum support.
  • BigInt and BigUInt: Using BigInt library
  • EthereumBlock: Represents the block, either number of RPC-specific definitions like 'Earliest' or 'Latest'
  • EthereumTransaction: Wraps a transaction. Encoders and decoders can work with it to generate proper data fields.

Conversion from and to Foundation types

All extensions are namespaced under ''.web3. So for example, to convert an Int to a hex string:

let gwei = 100
let hexgwei = gwei.web3.hexString

Supported conversions:

  • Convert from hex byte string ("0xabc") to Data
  • Convert from hex byte string ("0xabc") to Int
  • Convert from hex byte string ("0xabc") to BigUInt
  • Convert String, Int, BigUInt, Data to a hex byte string ("0xabc")
  • Add or remove hex prefixes when working with String

ERC20

We support querying ERC20 token data via the ERC20 struct. Calls allow to:

  • Get the token symbol, name, and decimals
  • Get a token balance
  • Retrieve Transfer events

ERC721

We support querying ERC721 token data via the ERC721 struct. Including:

  • Get the token symbol, name, and decimals
  • Get a token balance
  • Retrieve Transfer events
  • Decode standard JSON for NFT metadata. Please be aware some smart contracts are not 100% compliant with standard.

ZKSync Era

We also include additional helpers to interact with ZKSync Era, by importing web3_zksync.

Take a look at ZKSyncTransaction or use directly ZKSyncClient which has similar API as the EthereumClient

Running Tests

Some of the tests require a private key, which is not stored in the repository. You can ignore these while testing locally, as CI will use the encrypted secret key from Github.

It's better to run only the tests you need, instead of the whole test suite while developing. If you ever need to set up the key locally, take a look at TestConfig.swift where you can manually set it up. Alternatively you can set it up by calling the script setupKey.sh and passing the value (adding 0x) so it's written to an ignored file.

Dependencies

We built web3.swift to be as lightweight as possible. However, given the cryptographic nature of Ethereum, there's a couple of reliable C libraries you will find packaged with this framework:

  • keccac-tiny: An implementation of the FIPS-202-defined SHA-3 and SHAKE functions in 120 cloc (156 lines).
  • Tiny AES: A small and portable implementation of the AES ECB, CTR and CBC encryption algorithms.
  • secp256k1.swift

Package dependencies:

Also for Linux build, we can't use Apple crypto APIs, so we embedded a small subset of CryptoSwift (instead of importing the whole library). Credit to Marcin Krzyżanowski

Contributors

The initial project was crafted by the team at Argent. However, we encourage anyone to help implement new features and to keep this library up-to-date. For features and fixes, simply submit a pull request to the develop branch. Please follow the contributing guidelines.

For bug reports and feature requests, please open an issue.

License

Released under the MIT license.

web3.swift's People

Contributors

armanarutiunov avatar clee681 avatar daltonclaybrook avatar danielnordh avatar darthmike avatar dependabot[bot] avatar dhruv500 avatar dmcrodrigues avatar dnkaratzas avatar gergold avatar gooddaisy avatar hboon avatar ismail9001 avatar joeblau avatar joshuajiangdev avatar jsdu avatar mluisbrown avatar oguzyuuksel avatar peerasak-u avatar peerasakava avatar pranav-singhal avatar rick-ahnlabio avatar rinat-enikeev avatar rkreutz avatar rkreutz-teamwork avatar syn-mcj avatar th3m477 avatar thantthet avatar tungnguyen20 avatar varunlohade avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

web3.swift's Issues

Can't interact with the client methods

Hi all!
When I try

guard let clientUrl = URL(string: "https://mainnet.infura.io/v3/<my infura id>") else { return }
let client = EthereumClient(url: clientUrl)
client.net_version(completion: { (error, network) in ...
// or
client.eth_gasPrice { (error, gasPrice) in

I got error:
Task <...>.<1> finished with error [-999] Error Domain=NSURLErrorDomain Code=-999 "cancelled" UserInfo={NSErrorFailingURLStringKey=https://mainnet.infura.io/v3/b2f4b3f635d8425c96854c3d28ba6bb0, NSLocalizedDescription=cancelled, NSErrorFailingURLKey=https://mainnet.infura.io/v3/b2f4b3f635d8425c96854c3d28ba6bb0}

Connection 1: unable to determine interface type without an established connection
Connection 1: unable to determine fallback status without a connection
Task <...>.<1> HTTP load failed, 0/0 bytes (error code: -999 [1:89])

and error description: The operation couldn’t be completed. (web3.EthereumClientError error 2.)

also tried with the similar url for Kovan https://kovan.infura.io/v3/
also used urls from tests
https://ropsten.infura.io/v3/b2f4b3f635d8425c96854c3d28ba6bb0"
https://mainnet.infura.io/v3/b2f4b3f635d8425c96854c3d28ba6bb0

what am i doing wrong?

Deploy contracts with ABIConstructor

Hi there! Great library, love it.

Feature request: I want to be able to deploy contracts from Swift code. PR #196.

Something like:

struct BokkyTokenConstructor: ABIConstructor {
    static let bytecode: Data = {bytecodeHex}.web3.hexData!

    let gasPrice: BigUInt? = nil
    let gasLimit: BigUInt? = 4712388
    let contract: EthereumAddress = EthereumAddress("0x")
    let from: EthereumAddress?

    let name: String
    let symbol: String
    let decimals: UInt8

    init(
       name: String,
       symbol: String,
       decimals: UInt8,
       from: EthereumAddress? = nil
    ) {
       self.name = name
       self.symbol = symbol
       self.decimals = decimals
       self.from = from
    }

    func encode(to encoder: ABIConstructorEncoder) throws {
       try encoder.encode(name)
       try encoder.encode(symbol)
       try encoder.encode(decimals)
    }
}

And finally:

let transaction = BokkyTokenConstructor(name: "BokkyPooBah Test Token", symbol: "BOKKY", decimals: UInt8(18))
let txHash = try await transaction.execute(withClient: client, account: account)
print(EthereumAddress(txHash))

where {bytecodeHex} is contract bytecode.

This code should deploy new Bokky Token contract.

ERC721Metadata.tokenURI call returns no data. Expected to return json metadata.

I'm trying to get the token URI with the below code but don't receive any response data.

let erc721 = ERC721Metadata(
    client: client,
    metadataSession: .shared
)
erc721.tokenURI(
    contract: EthereumAddress("0x3b3ee1931dc30c1957379fac9aba94d1c48a5405"),
    tokenID: BigUInt(37949)
) { error, url in
    if let error = error { return print(error) }
    print(url)
}

Using the same input with Boilertalk's Web3.swift framework I receive the following response:

["": "https://ipfs.foundation.app/ipfs/QmWiWTXdRCbiCm6n1BEujGJMA8GJNpmGx88nbmf5QcdYzA/metadata.json"]

Thanks a lot for your work guys!

Question: EIP-1559

Hello Devs,

Thanks for supporting this great library and I have a simple question.

I just wonder if web3.swift supports EIP-1559 so it can create 0x02 transaction.

If it doesn't, can you let me know the plan?

Sincerely,

Getting started code fails gas price call

Using the Getting started code for setting up the client:

guard let clientUrl = URL(string: "https://mainnet.infura.io/v3/<myInfuradetails>") else  { return    false}
let client = EthereumClient(url: clientUrl)
 client.eth_gasPrice(completion: { (error, currentPrice) in
    print("The current gas price is \(currentPrice)")
 })

Fails with the following error:

Task <BEC188CB-97F7-417B-85F2-3D8A7E3781E3>.<1> finished with error [-999] 
Error Domain=NSURLErrorDomain Code=-999 "cancelled" 
UserInfo={NSErrorFailingURLStringKey=https://mainnet.infura.io/v3/<myInfuradetails>, 
NSLocalizedDescription=cancelled, 
NSErrorFailingURLKey=https://mainnet.infura.io/v3/<myInfuradetails>}

The current gas price is nil

I would normally guess this was an https issue but that seems unlikely here.
Any tips on how to get this library working?
(Xcode 11.3.1)

Contract Transfer Events (Non ERC721/ERC20)

Please implement a function to gather all transfer events to and from addresses (ETH). Same function that is available for ERC721 / ERC20 transfer events for normal transactions.

eth_sendRawTransaction always pending on Etherscan

I am trying to send some ethers to an address, here is my code

func transaction() async {
        do {
            let tx = EthereumTransaction(from: EthereumAddress("my_wallet_public_key"), to: EthereumAddress("target_wallet_public_key"), value: BigUInt(16000000000000), data: nil, nonce: 2, gasPrice: BigUInt(4000000), gasLimit: BigUInt(500000), chainId: 3)
            let txHash = try await client?.eth_sendRawTransaction(tx, withAccount: self.account!)
            print("transaction completed: \(txHash)")
        } catch {
            print("transaction failed")
        }
}

After I called this function, the transaction seems to be completed and the txHash was returned. But that transaction was always pending on etherscan and never got passed.

https://ropsten.etherscan.io/tx/0xc30c3ab114f3fe27b0ac9402aa972a31415691eaaf4edac3afdf1918ee4795f2

Am I doing anything wrong?

How do you export a private key that's password protected

If a private key is password-protected, EthereumAccount encrypts the key before passing it to key storage, which makes sense. But I can't find a way to access the decrypted private key data from app so that I can export it. The privateKeyData property on EthereumAccount is private, and the KeystoreUtil class is internal, so I can't just use it to decode the key manually. Is there another way? Do you see any problem with exposing a public accessor for the private key?

WSS integration

Hello, i have a wss server that i want to connect to. Does this library support wss connections?

how to convert BigUInt to eth value?

You'll need to divide by decimals of smaller value, in this case 18

let wei = BigUInt(10000)
let eth = wei / BigUInt(10).power(18)

Alternatively you can convert to Foundation Decimal to represent or display with comma values.

Working with EIP-3009, transferWithAuthorization

I'm trying to get our client to support EIP-3009, to let us submit transactions on our users' behalf.
Specifically USDC's 'transferWithAuthorization' function.

image

My assumptions for how the flow should go:

  1. Create a Data object that conforms to the function protocol described here. Not sure which existing web3.swift functions I can leverage here. Their javascript example below. (Do I include the type definitions in the data, or just the actual data - domain, primaryType, message?)

image

  1. Sign the Data object, hopefully using func sign(data: Data) throws -> Data (Will the result allow for extracting the v, r, s values?)
  2. Pass the necessary transaction parameters and signature to the server who will be submitting the transaction
  3. Extract the v, r, s values from the signature
  4. Call the USDC contract's transferWithAuthorization function with all the parameters

If you have any thoughts on errors in this flow, or ideas for how to best support EIP-3009 @DarthMike let me know.
I haven't been able to find much info on this, particularly in Swift. Not sure it has been done before.
Happy to submit any work I do here back to the repo.

Getting started SwiftUI with EthereumClient

I am having an issue getting started, It looks like the issue is with the EthereumClient and strong reference but I can't seem to figure it out, I keep getting errors, is this not the correct method using SwiftUI ?

    class ContractManager {
    
        let client: EthereumClient!
        let account: EthereumAccount!
    
        init() {
            let keyStorage = EthereumKeyLocalStorage()
            account = try! EthereumAccount.create(keyStorage: keyStorage, keystorePassword: "MY_PASSWORD")
            client = EthereumClient(url: URL(string: "https://mainnet.infura.io/v3/238a6eb832834984ae827fc59dd1d992")!)
        }
    
        func getGasPrice() {
            client.eth_gasPrice { (error, currentPrice) in
                guard error != nil else {
                    print(error?.localizedDescription)
                    return
                }
                print("The current gas price is \(currentPrice)")
            }
        }
        
    }
    
    struct ContentView: View {
        
        let contractManager = ContractManager()
        
        var body: some View {
            VStack(alignment: .leading, spacing: 10) {
                
                Button("Get Gas"){
                    contractManager.getGasPrice()
                }
            }
        }
    }

Needs guidance on error handling

Hello,

I have noticed most of the EthereumClient errors are wrapped into EthereumClientError.unexpectedReturnValue.

Althought EthereumRPC handle and parse the errors properly. On the upper layer they are all hidden into the generic EthereumClientError.unexpectedReturnValue.

What do you think would be a good way to propagate these underlying errors? I am trying to figure out how to properly make these errors flow to the UI layer so that I can give a proper reason to the user on why the transaction failed. Typically, the most common issues would be not enough eth to pay for transaction value or gas but could be anything more.

I considered adding an associated string to the EthereumClientError.unexpectedReturnValue enum but this would basically change the whole EthereumClient api. Do you guys get the the transaction errors by querying the logs directly or in some other way?

Great job on the library thanks!

'EthereumKeyLocalStorage' initializer is inaccessible due to 'internal' protection level

i want to try to use Account in MyViewController

import web3

override func viewDidLoad() {
   super.viewDidLoad()
   let keyStorage = EthereumKeyLocalStorage()
   let account = try? EthereumAccount.create(keyStorage: keyStorage, keystorePassword: "MY_PASSWORD")
}

so i face the following error
'EthereumKeyLocalStorage' initializer is inaccessible due to 'internal' protection level

Support for macOS 12.3.1

It seems that library fails to build for macOS 12.3.1.
Any plans to support current Apple platforms?

Linux transactions fail

On Linux I get when I try to transfer tokens.
"Ethereum response error: JSONRPCErrorDetail(code: -32000, message: "insufficient funds for gas * price + value")"

On macOS that error does not occur and the transaction completes successfully. Checked BSScan and the Gas, Limit etc are all ok. Any idea what might me wrong?

Signed Integer Not Processing Correctly

I'm trying to call call the slot0 function from a UniswapV3 pool and when I make the request, the second parameter in the response is supposed to be Ann int24. In some cases, this int24 is negative, but the ABI response always returns a positive number.

For this pool at this address 0x69d91b94f0aaf8e8a2586909fa77a5c2c89818d5 the response for the tick property should be -61627 but I'm seeing 61627 in my logs.

EthereumAddress(value: "0x69d91b94f0aaf8e8a2586909fa77a5c2c89818d5") 61627

This is my ABI Function

import BigInt
import Foundation
import web3

public struct Slot0ABIFunction: ABIFunction {
    public static let name = "slot0"
    public let gasPrice: BigUInt? = nil
    public let gasLimit: BigUInt? = nil
    public var contract: EthereumAddress
    public let from: EthereumAddress? = nil

    public func encode(to _: ABIFunctionEncoder) throws {}

    // MARK: - Response

    public struct Response: ABIResponse {
        public static var types: [ABIType.Type] = [BigUInt.self, BigInt.self, UInt16.self, UInt16.self, UInt16.self, UInt8.self, Bool.self]
        let sqrtPriceX96: BigUInt
        let tick: BigInt
        let observationIndex: UInt16
        let observationCardinality: UInt16
        let observationCardinalityNext: UInt16
        let feeProtocol: UInt8
        let unlocked: Bool

        public init?(values: [ABIDecoder.DecodedValue]) throws {
            sqrtPriceX96 = try values[0].decoded()
            tick = try values[1].decoded()
            observationIndex = try values[2].decoded()
            observationCardinality = try values[3].decoded()
            observationCardinalityNext = try values[4].decoded()
            feeProtocol = try values[5].decoded()
            unlocked = try values[6].decoded()
        }
    }
}

This is my client call

let slot0 = Slot0ABIFunction(contract: poolAddress)
slot0.call(withClient: client,
           responseType: Slot0ABIFunction.Response.self) { error, response in
    switch error {
    case let .some(err):
        os_log("%@", log: .uniswapSmartContract, type: .error, err.localizedDescription)
    case .none:
        switch response {
        case let .some(response):
            print(poolAddress, response.tick)
        case .none:
            os_log("No slot in pool", log: .uniswapSmartContract, type: .info)
        }
    }
}

Parsing error when reading ERC20 contract's `symbol` property

When using public func symbol(tokenContract: EthereumAddress, completion: @escaping((Error?, String?) -> Void)) from public class ERC20 parsing sometimes fails.

Expected Behavior

As a consumer of this library, I should be able to retrieve ERC20 token's symbol using public func symbol(...) function.

Current Behavior

Currently, call fails with EthereumClientError.decodeIssue for some ERC20 contracts. This is because symbol function call expects the result to be of string type as defined in ERC20 standard. However, some contracts implement symbol as bytes32 type causing this failure.

Steps to Reproduce

  1. Create let client = EthereumClient(...) with Ropsten testnet (https://ropsten.infura.io/)

  2. get an array of incoming ERC transfers via:
    ERC20(client: client).transferEventsTo(recipient: "0x70abd7f0c9bdc109b579180b272525880fb7e0cb")

  3. Having results like let transfers: [ERC721Events.Transfer] = step 2 result try to query token symbols for respective transfers using ERC20(client: client).name(tokenContract: transfer.log.address). One of the contracts that are causing this issue: "0x70503d98c63e9803233789c4ab0c33848dcca47f"

  4. Underling call func call<T: ABIResponse>(withClient client: EthereumClient, responseType: T.Type, block: EthereumBlock = .Latest, completion: @escaping((EthereumClientError?, T?) -> Void)) will compleate yet will fail during parsing let response = (try? T(data: res))

Support other uint/int sizes

Currently when a type is BigUInt, it's assumed to be 256, which is correct in most cases. But sometimes need more specific size. We should support any size, as we do for Dataxyz solidity types

Problem Encoding Tuples with Dynamic Types

Hi @DarthMike we are working to use this library to encode tuples as function parameters to call smart contract functions.

For simple tuples with only statically sized variables we have no problem. For example -- we are able to use your library to define a custom ABITuple type for a struct

struct Ask {
        // Amount of the currency being asked
        uint256 amount;
        // Address to the ERC20 token being asked
        address currency;
}

However when we attempt to encode a struct with dynamic size aka a string value we are running into trouble.

the struct looks like this

struct MediaData {
        // A valid URI of the content represented by this token
        string tokenURI;
        // A valid URI of the metadata associated with this token
        string metadataURI;
        // A SHA256 hash of the content pointed to by tokenURI
        bytes32 contentHash;
        // A SHA256 hash of the content pointed to by metadataURI
        bytes32 metadataHash;
    }

Looking at the input data it seems like the library is having a difficult time properly encoding the dynamic tuple.

Doing some research here and dynamic tuples are definitely encoded differently than static tuples so it does feel like perhaps there is a bug in the encoding logic.

Have you all ever run into this?

Here is an example of input data on a successful ethereum transaction using a different library ethers and then the input data for the malformed input data using web3.swift.

Correct Input Data

2cca323700000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a688906bd8b00000000000000000000000000000000000000000000000000004c53ecdc18a600000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001007efef35dcd300eec8819c4ce5cb6b57be685254d583954273c5cc16edee83790ba42a7d804d9eff383efb1864514f5f15c82f1c333a777dd8f76dba1c1977029000000000000000000000000000000000000000000000000000000000000005668747470733a2f2f697066732e666c65656b2e636f2f697066732f62616679626569623774726c746c66353637647171336a766f6b37336b3776706e6b7864713367663665766a326c74657a7a7a7a6871756336656100000000000000000000000000000000000000000000000000000000000000000000000000000000005668747470733a2f2f697066732e666c65656b2e636f2f697066732f62616679626569657a706165676378796c74707733716a6d78746678716961646471627264727a6f79766d62616768716468776875756c6963697900000000000000000000

Incorrect Input Data

2cca323700000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a688906bd8b00000000000000000000000000000000000000000000000000004c53ecdc18a600000000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000001007efef35dcd300eec8819c4ce5cb6b57be685254d583954273c5cc16edee83790ba42a7d804d9eff383efb1864514f5f15c82f1c333a777dd8f76dba1c1977029000000000000000000000000000000000000000000000000000000000000005668747470733a2f2f697066732e666c65656b2e636f2f697066732f62616679626569623774726c746c66353637647171336a766f6b37336b3776706e6b7864713367663665766a326c74657a7a7a7a6871756336656100000000000000000000000000000000000000000000000000000000000000000000000000000000005668747470733a2f2f697066732e666c65656b2e636f2f697066732f62616679626569657a706165676378796c74707733716a6d78746678716961646471627264727a6f79766d62616768716468776875756c6963697900000000000000000000

You will notice the only different is a 40 in the second 32 byte sequence of the incorrect input data and an 80 as the second 32 byte sequence in the correct input data.

Any help here would be much appreciated!

Getting all request cancelled as soon as they are created, causing all responses to be nil

Trying to run the simple gas price function on the docs to initially test the library, but getting always nil as the value returned, after doing some dig and debugging, down to the EthereumRPC.execute call, I found that all the requests are returning a cancelled error. The call is made on a SwiftUI class on the onAppear block of the body GUI.
image

I'm working on iOS 15.1, maybe I'm missing something on the app config.
Thanks for the work you put on this!

General Blockchain?

Hi guys, is this only for ETH?
Can I retrieve also wallet information from BNB blockchain?
Any plans to add support for the rest of the blockchain, for example ADA and so on?

Thank you

Unable to obtain signed transaction for submission by relayer

I am trying to sign a transaction on the device for later submission by a relayer.
(USDC 'transferWithAuthorization')

Using:
let signedTx = (try? account.sign(transaction)) I get No exact matches in call to instance method 'sign'

Presumably because of the unnamed parameter (_ transaction: in
func sign(_ transaction: EthereumTransaction)

Is there a better way of acquiring a signed transaction that I'm missing?

RFC: EIP-1559 vs EIP-3416 impact on Client Apps/Wallets

Dear Argent Wallet client devs, we are looking forward to improving the Market Fee on Ethereum blockchain. We are a couple of engineers proposing an EIP improvement based on EIP-1559. We estimate 1559 is great but we propose an improvement to:

  • further reduce the gas price volatility with a median function (on premium gas price on top of base fees);
  • reduce base fees volatility with an additive function (linear dynamic) instead of multiplicative (ie. exponential dynamic);
  • reduce the footprint of the changes on wallets and clients by maintaining the same tx format and UI.

I know you have probably expressed your opinion before but we will appreciate if you can leave a Support +1 , NotSupport -1, or NeedMoreInfo opinion or comments on the forums from client/wallet apps before the AllCoreDevs meeting this Friday. This can helps us avoid the proposal get pushed for August or later:

Proposal:
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-3416.md
EIP-33416 proposal for London fork:
ethereum/pm#294
Discord (Fee Market):
https://discord.com/channels/595666850260713488/749160974506000444

UI Comparison Diagram:
image
Best,
HexZorro
image

Unable to decode Dynamic array. Potential Int overflow in the decoder for dynamic array.

This is my struct.

struct TupleWithArray: ABITuple {
    static var types: [ABIType.Type] { [ABIArray<EthereumAddress>.self] }
    
    var owners: [EthereumAddress]
    
    init(owners: [EthereumAddress]) {
        self.owners = owners
    }
    
    init?(values: [ABIDecoder.DecodedValue]) throws {
        self.owners = try values[0].decodedArray()
    }
    
    func encode(to encoder: ABIFunctionEncoder) throws {
        try encoder.encode(owners)
    }
    
    var encodableValues: [ABIType] { [ABIArray(values: owners)] }
}

Here's the test

 do {
            let tuple = TupleWithArray(owners: [EthereumAddress("0xdF136715f7bafD40881cFb16eAa5595C2562972b"), EthereumAddress("0xdF136715f7bafD40881cFb16eAa5595C2562972b")])
            
            let encodedHexString = try encoder.encoded().web3.hexString
            
            // Fails
            let value = try ABIDecoder.decodeData(encodedHexString, types: [TupleWithArray.self])
            
        } catch {
            XCTFail()
        }

The code fails in ABIDecoder.swift during Int(hex: string) due to overflow.

guard var size = Int(hex: sizeHex) else {
                throw ABIError.invalidValue
            }

// The Following is nil

    let a = Int.init("000000000000000000000000e000000000000000000000000000000000000000", radix: 16)

Build issues

Im getting 18 Swift compiler issues after adding the pod and opening my workspace.

  • Redefinition of module 'CommonCrypto'
  • Could not build module 'Dispatch'

etc

Multiple targets named "CryptoSwift" when using web3.swift

I'm using a dependency in my app that imports CryptoSwift and web3.swift. You recently made a change to use an embedded version of CryptoSwift:

.target(name: "CryptoSwift",
                dependencies: [],
                path: "web3swift/lib/CryptoSwift"),

and named the target the same as the official package version. Now any package or app that tries to import CryptoSwift and web3.swift is getting build failures "multiple targets named CryptoSwift in: cryptoswift, web3.swift". Because it was only a minor version bump too, its being automatically pulled down.

Can you either rename your target, or ideally use the official CryptoSwift as a listed dependency so there won't be 2 copies of the same code

(EIP712) - Encoding TypedData containing bytes

I want to encode the following typed message:

{
  "types": {
      "EIP712Domain": [
          {"name": "verifyingContract", "type": "address"},
          {"name": "chainId", "type": "uint256"},
      ],
      "TxMessage": [
          {"name": "signer", "type": "address"},
          {"name": "to", "type": "address"},
          {"name": "data", "type": "bytes"},
          {"name": "nonce", "type": "uint256"}
      ]
  },
  "primaryType": "TxMessage",
  "domain": {
      "chainId": 3,
      "verifyingContract": "0x9f733Fd052A5526cdc646E178c684B1Bf2313C57"
  },
  "message": {
      "signer": "0x2c68bfBc6F2274E7011Cd4AB8D5c0e69B2341309",
      "to": "0x68f3cEdf21B0f9ce31AAdC5ed110014Af5DA1828",
      "data": "0xa21f3c6a68656c6c6f000000000000000000000000000000000000000000000000000000776f726c64202100000000000000000000000000000000000000000000000000",
      "nonce": 0
    }
}

Calling :

let typedData = try! JSONDecoder().decode(TypedData.self, from: jsonString.data(using: .utf8)!)
try! typedData.signableHash().web3.hexString

Returns:

0x064198dd39fd7731b32f3ea8873c8811a58d0a161374a7755533f67c8fb3c7fa

Expected returns:

0x1f177092c4fbedf53f392389d4512f0a61babf07acc05303a4f1ef7e90b67d92

Fix proposal

I thinks the problem come from the method parseAtomicType on the file Utils/TypedData.swift.

You have line 110:

       case .DynamicString, .DynamicBytes:
            guard let value = data.stringValue?.web3.keccak256 else {
                throw ABIError.invalidValue
            }
            return try ABIEncoder.encode(value, forType: .FixedBytes(32))
        case .FixedAddress, .FixedBytes:

You are considering 0xa21f3c6a68656c6c6f000000000000000000000000000000000000000000000000000000776f726c64202100000000000000000000000000000000000000000000000000" as a String, not as a Hex encoded Data.

I think it should be:

case .DynamicBytes:
            guard let stringValue = data.stringValue, let value = Data(hex:stringValue)?.web3.keccak256 else {
                throw ABIError.invalidValue
            }
            return try ABIEncoder.encode(value, forType: .FixedBytes(32))
        case .DynamicString:
            guard let value = data.stringValue?.web3.keccak256 else {
                throw ABIError.invalidValue
            }
            return try ABIEncoder.encode(value, forType: .FixedBytes(32))

Using this code, I got the expected Hash.

I think you based your code from TrustCore iOS SDK because it has the same logic with the same issues.

Thanks

Unexpected Return Type while getting Balances

The error occurs while getting the balance for an address of a contract on the ETH mainnet with working Infura credentials.

Error: web3.EthereumClientError.unexpectedReturnValue
While calling function: client.balanceOf (....)

As commented on another issue: Neither the client saving as a var is helping nor any suggestion towards Metamask - however that should be in any relevance to this project. There is apparently a failure in how the code returns values. The return type is unexpected but there is no clear way to get raw data as return before the error is handled as to see what exactly is received.

Remove logic around 'execution error' calls

See #118 and #119

We included some logic to keep library working as before, but geth nodes are expected to be updated, this logic is obsolete.

Remove the workaround and just fail, giving the proper error to the caller.

Example code returns client error

I tried to run sample code in readme after importing library using SPM. I connect to mainnet using Infura.

    guard let clientUrl = URL(string: "https://mainnet.infura.io/v3/MY_TOKEN_HERE) else { return }
    let client = EthereumClient(url: clientUrl)
    
    client.eth_gasPrice(completion: { er, val in
        print(er)
        print(val)
    })

eth_gasPrice method returns web3.EthereumClientError.unexpectedReturnValue

Optional(web3.EthereumClientError.unexpectedReturnValue)
nil

Any ideas?

Support Linux

When I try to build on Linux the build Fails cause CommonCrypt doesn't exists on linux.

EthereumLog removed optionality

Subject: I want [PR] to make removed property of EthereumLog optional.

public struct EthereumLog: Equatable {
    ...
    public let removed: Bool?
}

Motivation: if I call eth_getTransactionReceipt I sometimes receive response without removed property, like in this code:

let deployTx = try await TokenABIServiceImpl.deploy(name: name, symbol: symbol, decimals: 18, account: account, client: client, from: account.address)
print(deployTx)

let txReceipt = try await client.eth_getTransactionReceipt(txHash: deployTx.value)
let contractAddress = txReceipt.contractAddress!

let tokenService = TokenABIServiceImpl(client: client, contract: contractAddress)
let nameFromService = try await tokenService.name()
let symbolFromService = try await tokenService.symbol()
XCTAssertEqual(name, nameFromService)
XCTAssertEqual(symbol, symbolFromService)

Idk why yet, there are some hint on SO, but being honest I don't understand fully why is it a case.

Tests failing

Hey,

in EthereumAccountTests

func testCreateAccount() {
        let account = try? EthereumAccount.create(keyStorage: EthereumKeyLocalStorage(), keystorePassword: "PASSWORD")
        XCTAssertNotNil(account)
    }

account is returning nil, and so failing.

Also, when running testLoadAccountAndAddress

in loadPrivateKey() in TestEthereumKeyStorage

privateKey.hexData is returning nil

ERC1155 ABI support

Hi there, great library!

The ERC20 and ERC721 ABI helpers built in are great, are there plans to add the ERC1155 ABI?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.