diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/web3.swift.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/web3.swift.xcscheme
index ef141582..adac788c 100644
--- a/.swiftpm/xcode/xcshareddata/xcschemes/web3.swift.xcscheme
+++ b/.swiftpm/xcode/xcshareddata/xcschemes/web3.swift.xcscheme
@@ -104,6 +104,20 @@
ReferencedContainer = "container:">
+
+
+
+
.self])
+ let decoded = try ABIDecoder.decodeData("0x00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000003", types: [ABIArray.self])
XCTAssertEqual(try decoded[0].decodedArray(), [BigInt(1), BigInt(2), BigInt(3)])
} catch let error {
print(error.localizedDescription)
@@ -94,6 +94,26 @@ class ABIDecoderTests: XCTestCase {
XCTFail()
}
}
+
+ func test_GivenBigInt_WhenValueIsNegative_ThenDecodesCorrectly() {
+ do {
+ let decoded = try ABIDecoder.decodeData("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff38", types: [BigInt.self])
+ XCTAssertEqual(try decoded[0].decoded(), BigInt(-200))
+ } catch let error {
+ print(error.localizedDescription)
+ XCTFail()
+ }
+ }
+
+ func test_GivenBigInt_WhenValueIsPositive_ThenDecodesCorrectly() {
+ do {
+ let decoded = try ABIDecoder.decodeData("0x00000000000000000000000000000000000000000000000000000000000000c8", types: [BigInt.self])
+ XCTAssertEqual(try decoded[0].decoded(), BigInt(200))
+ } catch let error {
+ print(error.localizedDescription)
+ XCTFail()
+ }
+ }
func testDecodeEmptyDynamicData() {
do {
@@ -136,9 +156,9 @@ class ABIDecoderTests: XCTestCase {
do {
let decoded = try ABIDecoder.decodeData(
"0x0000000000000000000000000000000000000000000000000000000000a9f60c0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001753796e746865746978204e6574776f726b20546f6b656e000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003534e5800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000012"
- , types: [BigInt.self, ABIArray.self])
+ , types: [BigUInt.self, ABIArray.self])
- XCTAssertEqual(try decoded[0].decoded(), BigInt(integerLiteral: 11138572))
+ XCTAssertEqual(try decoded[0].decoded(), BigUInt(integerLiteral: 11138572))
XCTAssertEqual(try ERC20Responses.nameResponse(data: decoded[1].entry[0])?.value, "Synthetix Network Token")
XCTAssertEqual(try ERC20Responses.symbolResponse(data: decoded[1].entry[1])?.value, "SNX")
XCTAssertEqual(try ERC20Responses.balanceResponse(data: decoded[1].entry[2])?.value, BigUInt(integerLiteral: 0))
@@ -153,9 +173,9 @@ class ABIDecoderTests: XCTestCase {
do {
let decoded = try ABIDecoder.decodeData(
"0x0000000000000000000000000000000000000000000000000000000000a9f60c0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001753796e746865746978204e6574776f726b20546f6b656e000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000003534e580000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020aface4ed2e287b2f681c32da24383f2fb691f0b6962be5ae7950a5dd793e61ad"
- , types: [BigInt.self, ABIArray.self])
+ , types: [BigUInt.self, ABIArray.self])
- XCTAssertEqual(try decoded[0].decoded(), BigInt(integerLiteral: 11138572))
+ XCTAssertEqual(try decoded[0].decoded(), BigUInt(integerLiteral: 11138572))
XCTAssertEqual(try ERC20Responses.nameResponse(data: decoded[1].entry[0])?.value, "Synthetix Network Token")
XCTAssertEqual(try ERC20Responses.symbolResponse(data: decoded[1].entry[1])?.value, "SNX")
XCTAssertEqual(try ERC20Responses.balanceResponse(data: decoded[1].entry[2])?.value, BigUInt(integerLiteral: 0))
diff --git a/web3sTests/Extensions/ByteExtensionsTests.swift b/web3sTests/Extensions/ByteExtensionsTests.swift
index 37a6cdd2..e45167f0 100644
--- a/web3sTests/Extensions/ByteExtensionsTests.swift
+++ b/web3sTests/Extensions/ByteExtensionsTests.swift
@@ -11,29 +11,38 @@ import BigInt
@testable import web3
class ByteExtensionsTests: XCTestCase {
-
- override func setUp() {
- super.setUp()
- }
-
- override func tearDown() {
- super.tearDown()
- }
-
func testBytesFromBigInt() {
XCTAssertEqual(BigInt(3251).web3.bytes, [12, 179])
XCTAssertEqual(BigInt(434350411044).web3.bytes, [101, 33, 77, 77, 36])
- XCTAssertEqual(BigInt(-404).web3.bytes, [254, 108])
+ XCTAssertEqual(BigInt(-404).web3.bytes, [255, 254, 108])
}
- func testBigIntFromTwosComplement() {
- let bytes: [UInt8] = [3, 0, 24, 124, 109]
+ func testGivenBigInt_WhenPositive_ThenParsesCorrectly() {
+ let bytes: [UInt8] = [0x00, 0xc8]
let data = Data(bytes)
let bint = BigInt(twosComplement: data)
- XCTAssertEqual(bint, 12886506605)
+ XCTAssertEqual(bint, 200)
}
-
+
+ func testGivenBigInt_WhenNegative_ThenParsesCorrectly() {
+ let bytes: [UInt8] = [0xff, 0x38]
+ let data = Data(bytes)
+ let bint = BigInt(twosComplement: data)
+
+ XCTAssertEqual(bint, -200)
+ }
+
+ func testGivenBigInt_WhenPositive_ThenBytesArrayIsTwosComplement() {
+ let bint = BigInt(200)
+ XCTAssertEqual(bint.web3.bytes, [0xc8])
+ }
+
+ func testGivenBigInt_WhenNegative_ThenBytesArrayIsTwosComplement() {
+ let bint = BigInt(-200)
+ XCTAssertEqual(bint.web3.bytes, [0xff, 0x38])
+ }
+
func testBytesFromData() {
let bytes: [UInt8] = [255, 0, 123, 64]
let data = Data(bytes)
diff --git a/web3swift/src/Contract/ABIDecoder.swift b/web3swift/src/Contract/ABIDecoder.swift
index 54181409..1a445b0a 100644
--- a/web3swift/src/Contract/ABIDecoder.swift
+++ b/web3swift/src/Contract/ABIDecoder.swift
@@ -75,9 +75,8 @@ public class ABIDecoder {
let startIndex = offset + 32 - type.size
let endIndex = offset + 31
guard data.count > endIndex else { throw ABIError.invalidValue }
- let buf = Data( Array(data[startIndex...endIndex]))
- let bint = BigInt(twosComplement: buf)
- return [String(hexFromBytes: bint.web3.bytes)]
+ let buf = Array(data[startIndex...endIndex])
+ return [String(hexFromBytes: buf)]
case .FixedUInt(_):
guard data.count > 0 else {
return [""]
diff --git a/web3swift/src/Contract/Statically Typed/ABIDecoder+Static.swift b/web3swift/src/Contract/Statically Typed/ABIDecoder+Static.swift
index 4ea04d2d..567d8d29 100644
--- a/web3swift/src/Contract/Statically Typed/ABIDecoder+Static.swift
+++ b/web3swift/src/Contract/Statically Typed/ABIDecoder+Static.swift
@@ -95,7 +95,7 @@ extension ABIDecoder {
}
public static func decode(_ data: ParsedABIEntry, to: BigInt.Type) throws -> BigInt {
- guard let value = BigInt(hex: data) else { throw ABIError.invalidValue }
+ guard let value = data.web3.hexData.map(BigInt.init(twosComplement:)) else { throw ABIError.invalidValue }
return value
}
diff --git a/web3swift/src/Extensions/ByteExtensions.swift b/web3swift/src/Extensions/ByteExtensions.swift
index 2e468bd1..bc32b779 100644
--- a/web3swift/src/Extensions/ByteExtensions.swift
+++ b/web3swift/src/Extensions/ByteExtensions.swift
@@ -26,11 +26,26 @@ public extension Web3Extensions where Base == BigUInt {
extension BigInt {
init(twosComplement data: Data) {
- let unsigned = BigUInt(data)
- self.init(BigInt(unsigned))
- if data[0] == 0xff {
- self.negate()
+ guard data.count > 1 else {
+ self.init(0)
+ return
}
+
+ let isNegative = data[0] & 0x80 == 0x80
+ guard isNegative else {
+ self = BigInt(BigUInt(data))
+ return
+ }
+
+ let bytesLength = data.count
+ let signBit = BigUInt(2).power(bytesLength * 8) / 2
+ let signValue = isNegative ? signBit : 0
+ let rest = data.enumerated().map { index, value in
+ index == 0 ? value & 0x7f : value
+ }
+
+ self = BigInt(signValue - BigUInt(Data(rest)))
+ self.negate()
}
}
@@ -40,11 +55,10 @@ public extension Web3Extensions where Base == BigInt {
if base.sign == .plus {
data = base.magnitude.serialize()
} else {
- // Twos Complement
- let len = base.magnitude.serialize().count
- let maximum = BigUInt(1) << (len * 8)
- let twosComplement = maximum - base.magnitude
- data = twosComplement.serialize()
+ let len = base.magnitude.serialize().count + 1
+ let maximum = BigUInt(2).power(len * 8)
+ let (twosComplement, _) = maximum.subtractingReportingOverflow(base.magnitude)
+ data = (twosComplement).serialize()
}