{"id":19952286,"url":"https://github.com/sparrowcode/swift-ethereum","last_synced_at":"2025-05-03T19:30:47.728Z","repository":{"id":39996044,"uuid":"470651205","full_name":"sparrowcode/swift-ethereum","owner":"sparrowcode","description":"Going to be official Ethereum repo for Swift. There is active progress right now. We will soon get the documentation in order and offer examples of use.","archived":false,"fork":false,"pushed_at":"2022-06-07T10:36:06.000Z","size":40159,"stargazers_count":19,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-04-07T20:21:23.742Z","etag":null,"topics":["blockchain","eth","ethereum","ethereum-blockchain","ethereum-contract","ethereum-dapp","ios","mew","rainbow","solidity","swift","wallet","web3","xcode"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sparrowcode.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null},"funding":{"github":["ivanvorobei","sparrowcode"]}},"created_at":"2022-03-16T15:53:02.000Z","updated_at":"2025-02-10T10:08:02.000Z","dependencies_parsed_at":"2022-08-25T18:31:17.628Z","dependency_job_id":null,"html_url":"https://github.com/sparrowcode/swift-ethereum","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sparrowcode%2Fswift-ethereum","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sparrowcode%2Fswift-ethereum/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sparrowcode%2Fswift-ethereum/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sparrowcode%2Fswift-ethereum/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sparrowcode","download_url":"https://codeload.github.com/sparrowcode/swift-ethereum/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252241936,"owners_count":21717070,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["blockchain","eth","ethereum","ethereum-blockchain","ethereum-contract","ethereum-dapp","ios","mew","rainbow","solidity","swift","wallet","web3","xcode"],"created_at":"2024-11-13T01:12:26.977Z","updated_at":"2025-05-03T19:30:47.347Z","avatar_url":"https://github.com/sparrowcode.png","language":"Swift","readme":"# swift-ethereum\n\nGoing to be official Ethereum repo for Swift. There is active progress right now. We will soon get the documentation in order and offer examples of use.\n\n## Installation\n\n### Swift Package Manager\nThe [Swift Package Manager](https://swift.org/package-manager/) is a tool for automating the distribution of Swift code and is integrated into the `swift` compiler. It’s integrated with the Swift build system to automate the process of downloading, compiling, and linking dependencies.\n\nOnce you have your Swift package set up, adding as a dependency is as easy as adding it to the `dependencies` value of your `Package.swift`.\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/sparrowcode/swift-ethereum.git\", .branchItem(\"main\"))\n]\n```\n\n## Navigation \n- [Account](#account)\n    - [Create new account](#create-new-account)\n    - [Import account](#import-account)\n    - [Remove account from manager](#remove-account-from-manager)\n    - [Sign data](#sign-data)\n- [Storage](#storage)\n    - [AES](#to-secure-private-keys-in-a-storage-make-use-of-aes)\n    - [Encrypting private key](#encrypting-private-key)\n    - [Decrypting](#decrypting)\n- [Interacting with Ethereum](#interacting-with-ethereum)\n    - [Send a transaction](#send-a-transaction)\n    - [Call a transaction](#call-a-transaction)\n    - [Get balance](#get-balance-of-any-address)\n    - [Get transactions count](#get-transactions-count)\n    - [Get current block number](#get-current-block-number)\n    - [Get current gas price](#get-current-gas-price)\n    - [Get block transaction count by block hash](#get-block-transaction-count-by-block-hash)\n    - [Get block transaction count by block number](#get-block-transaction-count-by-block-number)\n    - [Get storage at address](#get-storage-at-address)\n    - [Get code for address](#get-code-for-address)\n    - [Get block by hash](#get-block-by-hash)\n    - [Get block by number](#get-block-by-number)\n    - [Get transaction by hash](#get-transaction-by-hash)\n    - [Get uncle by block hash and index](#get-uncle-by-block-hash-and-index)\n    - [Get uncle by block number and index](#get-uncle-by-block-number-and-index)\n    - [Get transaction by block hash and index](#get-transaction-by-block-hash-and-index)\n    - [Get transaction by block number and index](#get-transaction-by-block-number-and-index)\n    - [Get transaction receipt](#get-transaction-receipt)\n    - [Estimate gas for transaction](#estimate-gas-for-transaction)\n- [Node](#getting-info-about-the-node)\n    - [Initialize custom node](#initialize-a-node-with-your-custom-rpc-url)\n    - [Get version](#get-version)\n    - [Check if listening](#check-if-listening)\n    - [Get peer count](#get-peer-count)\n    - [Get client version](#get-client-version)\n- [Utils](#utils)\n    - [Get public key from private key](#get-public-key-from-private-key)\n    - [Get address from public key](#get-address-from-public-key)\n    - [Convert Ethereum Units](#convert-ethereum-units)\n- [Smart Contracts](#smart-contracts-and-abi-decodingencoding)\n    - [ERC20](#erc20)\n        - [Get balance](#get-balance)\n        - [Transfer tokens](#transfer-tokens)\n        - [Get decimals](#get-decimals)\n        - [Get symbol](#get-symbol)\n        - [Get total supply](#get-total-supply)\n        - [Get name](#get-name)\n    - [ERC721](#erc721)\n        - [Get balance](#get-balance-1)\n        - [Get owner of](#get-owner-of)\n        - [Get name](#get-name-1)\n        - [Get symbol](#get-symbol)\n        - [Get token URI](#get-token-uri)\n        - [Get total supply](#get-total-supply-1)\n    - [Calling Smart Contract transaction and decoding response](#calling-smart-contract-transaction-and-decoding-response)\n    - [Sending Smart Contract transaction](#sending-smart-contract-transaction)\n    - [Custom Contracts](#custom-contracts)\n\n## Account\n\n### Create new account\nIn order to create a new account you have to use AccountManager. It secures your private key with AES encryption. You can also select a storage, where to hold the encrypted data.\n\n```swift\nlet account = try accountManager.createAccount()\n```\n\n### Import account\n```swift\nlet storage = UserDefaultsStorage(password: \"password\")\n        \nlet accountManager = AccountManager(storage: storage)\n        \nlet account = try accountManager.importAccount(privateKey: \"your_private_key\")\n```\n\nAll the fields of your account are decoded from your private key by the library, so after importing your account you can just tap to them:\n\n```swift\nlet address = account.address\nlet publicKey = account.publicKey\nlet privateKey = account.privateKey\n```\n\n### Remove account from manager\n\n```swift\ntry accountManager.removeAccount(account)\n```\n\n### Sign data\n\nYou can sign any instance of a type that confirms to `RLPEncodable` with your private key:\n\n```swift\nlet signedData = try account.sign(rlpEncodable)\n```\n\nTo confirm your type to `RLPEncodable` protocol provide how the data should be encoded for your type in `encodeRLP()` method:\n\n```swift\nstruct SomeType {\n    let name: String\n}\n\nextension SomeType: RLPEncodable {\n    func encodeRLP() throws -\u003e Data {\n        return try RLPEncoder.encode(self.name)\n    }\n}\n```\n\nRead more about RLP here: [RLP Ethereum Wiki](https://eth.wiki/fundamentals/rlp)\n\n## Storage\n\nA custom storage can be created by confirming to `StorageProtocol`:\n\n```swift\nstruct CustomStorage: StorageProtocol {\n\n    func storePrivateKey(_ privateKey: String) throws {\n        // store private key in database of your choice\n    }\n\n    func getPrivateKey(for address: String) throws -\u003e String {\n        // get private key from storage for address\n    }\n\n    func removePrivateKey(for address: String) throws {\n        // removes private key from storage\n    }\n}\n```\n\n### To secure private keys in a storage make use of `AES`\n\n#### Encrypting private key:\n\n```swift\nlet privateKey = \"some_private_key\"\n\nlet aes = AES()\n\nlet iv = aes.initialVector // a vector that is used for encrypting the data\n\nlet aesEncryptedPrivateKey = try aes.encrypt(privateKey, password: password, iv: iv)\n```\n\nThe encrypt method accepts only the `hexidecimal string of bytes representation` ex: \"0xfce353f6616263\" or any `Data`\n\n#### Decrypting:\n\n```swift\nlet decryptedPrivateKey = try aes.decrypt(aesEncryptedPrivateKey, password: password, iv: iv)\n```\n\n## Interacting with Ethereum\n\nThe abstraction between you and Ethereum is `EthereumService`. Before starting to call methods you have to configure provider with a [Node](#initialize-a-node-with-your-custom-rpc-url):\n\n```swift\nlet node = try Node(url: \"https://mainnet.infura.io/v3/967cf8dc4a37411c8e62698c7c603cee\")\nEthereumService.configureProvider(with: node)\n```\n\n#### Send a transaction:\n\n```swift\nlet value = \"1000000000000000000\" // 1 eth in wei\nlet transaction = try Transaction(from:\"0xE92A146f86fEda6D14Ee1dc1BfB620D3F3d1b873\",\n                                  gasLimit: \"210000\",\n                                  gasPrice: \"250000000000\",\n                                  to: \"0xc8DE4C1B4f6F6659944160DaC46B29a330C432B2\",\n                                  value: BigUInt(value))\n\nlet transactionHash = try await EthereumService.sendRawTransaction(account: account, transaction: transaction)\n```\n\n#### Call a transaction:\n\n```swift\nlet transaction = try Transaction(to: \"0xF65FF945f3a6067D0742fD6890f32A6960dD817d\", input: \"0x\")\n\nlet response = try await EthereumService.call(transaction: transaction, block: \"latest\")\n```\n\n\u003e Quick note: block is optional for calling this methods and is set to latest by default\n\n#### Get balance of any address:\n\n```swift\nlet balance = try await EthereumService.getBalance(for: \"address\")\n```\n\n#### Get transactions count:\n\n```swift\nlet count = try await EthereumService.getTransactionCount(for: \"address\")\n```\n\n#### Get current block number:\n\n```swift\nlet blockNumber = try await EthereumService.blockNumber()\n```\n\n#### Get current gas price:\n\n```swift\nlet gasPrice = try await EthereumService.gasPrice()\n```\n\n#### Get block transaction count by block hash:\n\n```swift\nlet blockTransactionCount = try await EthereumService.getBlockTransactionCountByHash(blockHash: \"block_hash\")\n```\n\n#### Get block transaction count by block number:\n\n```swift\nlet blockNumber = 2\nlet blockTransactionCount = try await EthereumService.getBlockTransactionCountByNumber(blockNumber: blockNumber)\n```\n\n#### Get storage at address:\n\n```swift\nlet address = \"0x295a70b2de5e3953354a6a8344e616ed314d7251\"\nlet storageSlot = 3\n\nlet storage = try await EthereumService.getStorageAt(address: address, storageSlot: storageSlot, block: \"latest\")\n```\n\n#### Get code for address:\n\n```swift\nlet address = \"0x2b591e99afE9f32eAA6214f7B7629768c40Eeb39\"\n\nlet code = try await EthereumService.getCode(address: address, block: \"latest\")\n```\n\n#### Get block by hash:\n\n```swift \nlet block = try await EthereumService.getBlockByHash(hash: \"block_hash\")\n```\n\n#### Get block by number:\n\n```swift\nlet blockNumber = 12312\n\nlet block = try await EthereumService.getBlockByNumber(blockNumber: blockNumber)\n```\n\n#### Get transaction by hash:\n\n```swift\nlet transactionHash = \"transaction_hash\"\n\nlet transaction = try await EthereumService.getTransactionByHash(transactionHash: transactionHash)\n```\n\n#### Get uncle by block hash and index:\n\n```swift\nlet blockHash = \"block_hash\"\nlet index = 0\n\nlet uncleBlock = try await EthereumService.getUncleByBlockHashAndIndex(blockHash: blockHash, index: index)\n```\n\n#### Get uncle by block number and index:\n\n```swift\nlet blockNumber = 668\nlet index = 0\n\nlet uncleBlock = try await EthereumService.getUncleByBlockNumberAndIndex(blockNumber: blockNumber, index: index)\n```\n\n#### Get transaction by block hash and index:\n\n```swift\nlet blockHash = \"block_hash\"\nlet index = 0\n\nlet transaction = try await EthereumService.getTransactionByBlockHashAndIndex(blockHash: blockHash, index: index)\n```\n\n#### Get transaction by block number and index:\n\n```swift\nlet blockNumber = 5417326\nlet index = 0\n\nlet transaction = try await EthereumService.getTransactionByBlockNumberAndIndex(blockNumber: blockNumber, index: index)\n```\n\n#### Get transaction receipt:\n\n```swift\nlet transactionHash = \"transaction_hash\"\n\nlet receipt = try await EthereumService.getTransactionReceipt(transactionHash: transactionHash)\n```\n\n#### Estimate gas for transaction:\n\n```swift\nlet transaction = try Transaction(from: \"0xE92A146f86fEda6D14Ee1dc1BfB620D3F3d1b873\",\n                                  to: \"0xc8DE4C1B4f6F6659944160DaC46B29a330C432B2\",\n                                  value: \"100000000000\")\n\nlet estimatedGas = try await EthereumService.estimateGas(for: transaction)\n```\n\n## Getting info about the Node\n\n#### Initialize a node with your custom rpc url\n```swift\nlet node = try Node(url: \"your_custom_rpc_url\")\n```\n\n#### Get version:\n\n```swift\nlet version = try await node.version()\n```\n\n#### Check if listening:\n\n```swift\nlet isListening = try await node.listening()\n```\n\n#### Get peer count:\n\n```swift\nlet peerCount = try await node.peerCount()\n```\n\n#### Get client version:\n\n```swift\nlet clientVersion = try await node.clientVersion()\n```\n\n\n## Utils\n\nWe provide commonly used scenarious under an easy interface\n\n#### Get public key from private key:\n\n```swift\nlet privateKey = \"private_key\"\n\nlet publicKey = try Utils.KeyUtils.getPublicKey(from: privateKey)\n```\n\n#### Get address from public key:\n\n```swift\nlet publicKey = \"public_key\"\n\nlet ethereumAddress = try Utils.KeyUtils.getEthereumAddress(from: publicKey)\n```\n\n#### Convert Ethereum Units:\n\n```swift\nlet wei = \"12345678901234567890\"\nlet eth = Utils.Converter.convert(value: wei, from: .wei, to: .eth)\n```\n\n## Smart Contracts and ABI Decoding/Encoding\n\nWe decided to create a transaction based flow for interacting with smart contracts, because of scalable architecture and lack of strong relations\n\nThe flow is super easy, we provide factory for both ERC20 and ERC721 contracts. Factory lets you generate transactions and then you can [call or send them via EthereumService](#calling-smart-contract-transaction-and-decoding-response)\n\n### ERC20\n\n```swift\nlet contractAddress = \"erc20_contract_address\" \n```\n\n#### Get balance:\n\n```swift\nlet address = \"address_to_check_balance\"\n\nlet transaction = try ERC20TransactionFactory.generateBalanceTransaction(address: address, contractAddress: contractAddress)\n```\n\n#### Transfer tokens:\n\n```swift\nlet value = BigUInt(some_value)\nlet toAddress = \"to_address\"\nlet gasLimit = BigUInt(gas_limit_value)\nlet gasPrice = BigUInt(gas_price_value)\n\nlet transaction = try ERC20TransactionFactory.generateTransferTransaction(value: value, \n                                                                          to: toAddress,\n                                                                          gasLimit: gasLimit,\n                                                                          gasPrice: gasPrice, \n                                                                          contractAddress: contractAddress)\n```\n\n#### Get decimals:\n\n```swift\nlet transaction = try ERC20TransactionFactory.generateDecimalsTransaction(contractAddress: contractAddress)\n```\n\n#### Get symbol:\n\n```swift\nlet transaction = try ERC20TransactionFactory.generateSymbolTransaction(contractAddress: contractAddress)\n```\n\n#### Get total supply:\n\n```swift\nlet transaction = try ERC20TransactionFactory.generateTotalSupplyTransaction(contractAddress: contractAddress)\n```\n\n#### Get name:\n\n```swift\nlet transaction = try ERC20TransactionFactory.generateNameTransaction(contractAddress: contractAddress)\n```\n\n### ERC721\n\n```swift\nlet contractAddress = \"erc721_contract_address\"\n```\n\n#### Get balance:\n\n```swift\nlet transaction = try ERC721TransactionFactory.generateBalanceTransaction(address: address, contractAddress: contractAddress)\n```\n\n#### Get owner of:\n\n```swift\nlet tokenId = BigUInt(708)\n        \nlet transaction = try ERC721TransactionFactory.generateOwnerOfTransaction(tokenId: tokenId, contractAddress: contractAddress)\n```\n\n#### Get name:\n\n```swift\nlet transaction = try ERC721TransactionFactory.generateNameTransaction(contractAddress: contractAddress)\n```\n\n#### Get symbol:\n\n```swift\nlet transaction = try ERC721TransactionFactory.generateSymbolTransaction(contractAddress: contractAddress)\n```\n\n#### Get token URI:\n\n```swift\nlet tokenId = BigUInt(708)\n\nlet transaction = try ERC721TransactionFactory.generateTokenURITransaction(tokenId: tokenId, contractAddress: contractAddress)\n```\n\n#### Get total supply:\n\n```swift\nlet transaction = try ERC721TransactionFactory.generateTotalSupplyTransaction(contractAddress: contractAddress)\n```\n\n#### Calling Smart Contract transaction and decoding response:\n\nThen just call the transaction with EthereumService, get the abi encoded result and decode it using ABIDecoder:\n\n```swift\n// transaction is a erc20 balance one\nlet abiEncodedBalance = try await EthereumService.call(transaction: transaction)\n\nlet balance = try ABIDecoder.decode(abiEncodedBalance, to: .uint()) as? BigUInt\n```\n\nIf the abi encoded result contains several types, provide them as an array:\n\n```swift\nlet decodedResult = try ABIDecoder.decode(someEncodedValue, to: [.uint(), .string, .address])\n```\n\n\u003e Decode method accepts both Data and String values\n\n#### Sending Smart Contract transaction:\n\nIf the transaction is a transfer one, send it via EthereumService:\n\n```swift\nlet transactionHash = try await EthereumService.sendRawTransaction(account: account, transaction: transaction)\n```\n\n### Custom Contracts\n\nIf you have a custom contract that you want to interact with, the flow is again very intuitive:\n\n1. Select a method that you want to call from your contract:\n\nFor example we want to call this method:\n\n```\nfunction balanceOf(address _owner) constant returns (uint balance);\n```\n\n2. Check the input and output parameters of the method:\n\nMethod accepts `address` type as an input and returns a `uint`\n\n3. Encode parameters:\n\n```swift\nlet params = [SmartContractParam(type: .address,  value: ABIEthereumAddress(\"some_address\"))]\n        \nlet method = SmartContractMethod(name: \"balanceOf\", params: params)\n\nguard let data = method.abiData else {\n    return\n}\n```\n\n4. Create a transaction:\n\n```swift\nlet  contractAddress = \"contract_address\"\n\nlet transaction = try Transaction(input: data, to: contractAddress)\n```\n\nThat's all, next you can [call the transaction and decode the response](#calling-smart-contract-transaction-and-decoding-response)\n","funding_links":["https://github.com/sponsors/ivanvorobei","https://github.com/sponsors/sparrowcode"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsparrowcode%2Fswift-ethereum","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsparrowcode%2Fswift-ethereum","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsparrowcode%2Fswift-ethereum/lists"}