Skip to content

Commit

Permalink
Merge branch 'develop' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
yaroslavyaroslav committed Oct 11, 2022
2 parents 45f2a70 + 860c68e commit 4bd644a
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 25 deletions.
91 changes: 89 additions & 2 deletions Sources/Core/EthereumNetwork/Request/APIRequest+Methods.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,24 @@ extension APIRequest {
}
}

if let error = (try? JSONDecoder().decode(JsonRpcErrorObject.self, from: data))?.error {
guard let parsedErrorCode = error.parsedErrorCode else {
throw Web3Error.nodeError(desc: "\(error.message)\nError code: \(error.code)")
}
let description = "\(parsedErrorCode.errorName). Error code: \(error.code). \(error.message)"
switch parsedErrorCode {
case .parseError, .invalidParams:
throw Web3Error.inputError(desc: description)
case .methodNotFound, .invalidRequest:
throw Web3Error.processingError(desc: description)
case .internalError, .serverError:
throw Web3Error.nodeError(desc: description)
}
}

/// This bit of code is purposed to work with literal types that comes in ``Response`` in hexString type.
/// Currently it's just `Data` and any kind of Integers `(U)Int`, `Big(U)Int`.
if Result.self == Data.self || Result.self == UInt.self || Result.self == Int.self || Result.self == BigInt.self || Result.self == BigUInt.self {
guard let LiteralType = Result.self as? LiteralInitiableFromString.Type else { throw Web3Error.typeError }
if let LiteralType = Result.self as? LiteralInitiableFromString.Type {
guard let responseAsString = try? JSONDecoder().decode(APIResponse<String>.self, from: data) else { throw Web3Error.dataError }
guard let literalValue = LiteralType.init(from: responseAsString.result) else { throw Web3Error.dataError }
/// `literalValue` conforms `LiteralInitiableFromString`, that conforming to an `APIResponseType` type, so it's never fails.
Expand All @@ -47,3 +61,76 @@ extension APIRequest {
return try JSONDecoder().decode(APIResponse<Result>.self, from: data)
}
}

/// JSON RPC Error object. See official specification https://www.jsonrpc.org/specification#error_object
fileprivate struct JsonRpcErrorObject: Decodable {
public let error: RpcError?

class RpcError: Decodable {
let message: String
let code: Int
var parsedErrorCode: JsonRpcErrorCode? {
JsonRpcErrorCode.from(code)
}
}
}

/// For error codes specification see chapter `5.1 Error object`
/// https://www.jsonrpc.org/specification#error_object
fileprivate enum JsonRpcErrorCode {
/// -32700
/// Invalid JSON was received by the server. An error occurred on the server while parsing the JSON
case parseError
/// -32600
/// The JSON sent is not a valid Request object.
case invalidRequest
/// -32601
/// The method does not exist / is not available.
case methodNotFound
/// -32602
/// Invalid method parameter(s).
case invalidParams
/// -32603
/// Internal JSON-RPC error.
case internalError
/// Values in range of -32000 to -32099
/// Reserved for implementation-defined server-errors.
case serverError(Int)

var errorName: String {
switch self {
case .parseError:
return "Parsing error"
case .invalidRequest:
return "Invalid request"
case .methodNotFound:
return "Method not found"
case .invalidParams:
return "Invalid parameters"
case .internalError:
return "Internal error"
case .serverError(_):
return "Server error"
}
}

static func from(_ code: Int) -> JsonRpcErrorCode? {
switch code {
case -32700:
return .parseError
case -32600:
return .invalidRequest
case -32601:
return .methodNotFound
case -32602:
return .invalidParams
case -32603:
return .internalError
default:
if (-32000)...(-32099) ~= code {
return .serverError(code)
}
return nil
}
}
}
3 changes: 3 additions & 0 deletions Sources/web3swift/Web3/Web3.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,21 @@ extension Web3 {
}

/// Initialized Web3 instance bound to Infura's rinkeby provider.
@available(*, deprecated, message: "This network support was deprecated by Infura")
public static func InfuraRinkebyWeb3(accessToken: String? = nil) async -> Web3 {
let infura = await InfuraProvider(Networks.Rinkeby, accessToken: accessToken)!
return Web3(provider: infura)
}

/// Initialized Web3 instance bound to Infura's ropsten provider.
@available(*, deprecated, message: "This network support was deprecated by Infura")
public static func InfuraRopstenWeb3(accessToken: String? = nil) async -> Web3 {
let infura = await InfuraProvider(Networks.Ropsten, accessToken: accessToken)!
return Web3(provider: infura)
}

/// Initialized Web3 instance bound to Infura's kovan provider.
@available(*, deprecated, message: "This network support was deprecated by Infura")
public static func InfuraKovanWeb3(accessToken: String? = nil) async -> Web3 {
let infura = await InfuraProvider(Networks.Kovan, accessToken: accessToken)!
return Web3(provider: infura)
Expand Down
49 changes: 26 additions & 23 deletions Tests/web3swiftTests/remoteTests/ST20AndSecurityTokenTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,42 +15,45 @@ import Core
// MARK: Works only with network connection
class ST20AndSecurityTokenTests: XCTestCase {

func testERC20TokenCreation() async throws {
let web3 = await Web3.InfuraKovanWeb3(accessToken: Constants.infuraToken)
let w3sTokenAddress = EthereumAddress("0x2dD33957C90880bE4Ee9fd5F703110BDA2E579EC")!
let st20token = ST20.init(web3: web3, provider: web3.provider, address: w3sTokenAddress)
try await st20token.readProperties()
XCTAssertEqual(st20token.symbol(), "MIMI")
XCTAssertEqual(st20token.name(), "Mimi")
XCTAssertEqual(st20token.decimals(), 18)
}
// FIXME: Enable me back again
// Test fails because there's no such wallet on goerli chain as well as token.
// func testERC20TokenCreation() async throws {
// let web3 = await Web3.InfuraGoerliWeb3(accessToken: Constants.infuraToken)
// let w3sTokenAddress = EthereumAddress("0x2dD33957C90880bE4Ee9fd5F703110BDA2E579EC")!
// let st20token = ST20.init(web3: web3, provider: web3.provider, address: w3sTokenAddress)
// try await st20token.readProperties()
// XCTAssertEqual(st20token.symbol(), "MIMI")
// XCTAssertEqual(st20token.name(), "Mimi")
// XCTAssertEqual(st20token.decimals(), 18)
// }

func testST20tokenBalanceAndAllowance() async throws {
let web3 = await Web3.InfuraKovanWeb3(accessToken: Constants.infuraToken)
let web3 = await Web3.InfuraGoerliWeb3(accessToken: Constants.infuraToken)
let w3sTokenAddress = EthereumAddress("0x2dD33957C90880bE4Ee9fd5F703110BDA2E579EC")!
let st20token = ST20.init(web3: web3, provider: web3.provider, address: w3sTokenAddress)
let userAddress = EthereumAddress("0xe22b8979739D724343bd002F9f432F5990879901")!
let balance = try await st20token.getBalance(account: userAddress)
let allowance = try await st20token.getAllowance(originalOwner: userAddress, delegate: userAddress)
XCTAssertEqual(String(balance), "0")
XCTAssertEqual(balance, 0)
XCTAssertEqual(allowance, 0)
}

func testSecurityTokenInvestors() async throws {
let web3 = await Web3.InfuraKovanWeb3(accessToken: Constants.infuraToken)
let web3 = await Web3.InfuraGoerliWeb3(accessToken: Constants.infuraToken)
let w3sTokenAddress = EthereumAddress("0x2dD33957C90880bE4Ee9fd5F703110BDA2E579EC")!
let stoken = SecurityToken.init(web3: web3, provider: web3.provider, address: w3sTokenAddress)
let investorsCount = try await stoken.investorCount()
let stringInvestorsCount = String(investorsCount)
XCTAssertEqual(stringInvestorsCount, "0")
}

func testSecurityTokenGranularity() async throws {
let web3 = await Web3.InfuraKovanWeb3(accessToken: Constants.infuraToken)
let w3sTokenAddress = EthereumAddress("0x2dD33957C90880bE4Ee9fd5F703110BDA2E579EC")!
let stoken = SecurityToken.init(web3: web3, provider: web3.provider, address: w3sTokenAddress)
let granularity = try await stoken.getGranularity()
let stringGranularity = String(granularity)
XCTAssertEqual(stringGranularity, "1000000000000000000")
XCTAssertEqual(investorsCount, 0)
}

// FIXME: Enable me back again
// Test fails because there's no such wallet on goerli chain as well as token.
// func testSecurityTokenGranularity() async throws {
// let web3 = await Web3.InfuraGoerliWeb3(accessToken: Constants.infuraToken)
// let w3sTokenAddress = EthereumAddress("0x2dD33957C90880bE4Ee9fd5F703110BDA2E579EC")!
// let stoken = SecurityToken.init(web3: web3, provider: web3.provider, address: w3sTokenAddress)
// let granularity = try await stoken.getGranularity()
// let stringGranularity = String(granularity)
// XCTAssertEqual(stringGranularity, "1000000000000000000")
// }
}

0 comments on commit 4bd644a

Please sign in to comment.