Skip to content

Commit 2192006

Browse files
authored
Merge pull request #5 from f-o-a-m/json-instances
Add Json Instances and make BigNumber consistent
2 parents 588ae1a + f4f19a2 commit 2192006

File tree

7 files changed

+137
-31
lines changed

7 files changed

+137
-31
lines changed

bower.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,17 @@
1919
],
2020
"dependencies": {
2121
"purescript-prelude": "^3.3.0",
22-
"purescript-console": "^3.0.0",
2322
"purescript-modules": "^3.0.0",
2423
"purescript-foreign": "^4.0.1",
2524
"purescript-simple-json": "^3.0.0",
2625
"purescript-sets": "^3.2.0",
2726
"purescript-bytestrings": "^6.0.0",
28-
"purescript-spec": "^2.0.0",
29-
"purescript-debug": "^3.0.0"
27+
"purescript-simple-json": "^3.0.0",
28+
"purescript-argonaut": "^3.1.0"
3029
},
3130
"devDependencies": {
32-
"purescript-psci-support": "^3.0.0"
31+
"purescript-psci-support": "^3.0.0",
32+
"purescript-spec": "^2.0.0",
33+
"purescript-debug": "^3.0.0"
3334
}
3435
}

src/Network/Ethereum/Core/BigNumber.js

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ exports.fromStringAsImpl = function (just) {
4949
} else {
5050
result = new BigNumber(s, radix);
5151
}
52-
} catch (e) {
52+
} catch (_) {
5353
return nothing;
5454
}
5555
return just(result);
@@ -102,14 +102,3 @@ var isString = function (object) {
102102
return typeof object === 'string' ||
103103
(object && object.constructor && object.constructor.name === 'String');
104104
};
105-
106-
exports.toBigNumber = function(number) {
107-
if (isBigNumber(number))
108-
return number;
109-
110-
if (isString(number) && (number.indexOf('0x') === 0 || number.indexOf('-0x') === 0)) {
111-
return new BigNumber(number.replace('0x',''), 16);
112-
}
113-
114-
return new BigNumber(number.toString(10), 10);
115-
};

src/Network/Ethereum/Core/BigNumber.purs

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ module Network.Ethereum.Core.BigNumber
1212

1313
import Prelude
1414

15-
import Data.Foreign (Foreign)
15+
import Data.Argonaut as A
16+
import Data.Either (Either(..), either)
17+
import Data.Foreign (ForeignError(..), readString, fail)
1618
import Data.Foreign.Class (class Decode, class Encode, decode, encode)
1719
import Data.Int (Radix, binary, decimal, hexadecimal, floor) as Int
1820
import Data.Maybe (Maybe(..))
1921
import Data.Module (class LeftModule, class RightModule)
20-
import Simple.JSON (class ReadForeign)
22+
import Simple.JSON (class ReadForeign, class WriteForeign)
2123

2224
--------------------------------------------------------------------------------
2325
-- * BigNumber
@@ -119,13 +121,32 @@ unsafeToInt = Int.floor <<< toNumber
119121
-- | Take the integer part of a big number
120122
foreign import floorBigNumber :: BigNumber -> BigNumber
121123

122-
foreign import toBigNumber :: Foreign -> BigNumber
124+
_encode :: BigNumber -> String
125+
_encode = (append "0x") <<< toString Int.hexadecimal
126+
127+
_decode :: String -> Either String BigNumber
128+
_decode str = case parseBigNumber Int.hexadecimal str of
129+
Nothing -> Left $ "Failed to parse as BigNumber: " <> str
130+
Just n -> Right n
123131

124132
instance decodeBigNumber :: Decode BigNumber where
125-
decode = pure <<< toBigNumber
133+
decode x = do
134+
str <- readString x
135+
either (fail <<< ForeignError) pure $ _decode str
126136

127137
instance readFBigNumber :: ReadForeign BigNumber where
128138
readImpl = decode
129139

140+
instance writeFBigNumber :: WriteForeign BigNumber where
141+
writeImpl = encode
142+
130143
instance encodeBigNumber :: Encode BigNumber where
131-
encode = encode <<< (append "0x") <<< toString Int.hexadecimal
144+
encode = encode <<< _encode
145+
146+
instance decodeJsonBigNumber :: A.DecodeJson BigNumber where
147+
decodeJson json = do
148+
str <- A.decodeJson json
149+
_decode str
150+
151+
instance encodeJsonBigNumber :: A.EncodeJson BigNumber where
152+
encodeJson = A.encodeJson <<< _encode

src/Network/Ethereum/Core/HexString.purs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,11 @@ module Network.Ethereum.Core.HexString
2828

2929
import Prelude
3030

31+
import Data.Argonaut as A
3132
import Data.Array (uncons, unsafeIndex, replicate)
3233
import Data.ByteString (ByteString, toString, fromString) as BS
34+
import Data.Either (Either(..), either)
35+
import Data.Foreign (ForeignError(..), fail)
3336
import Data.Foreign.Class (class Decode, class Encode, decode, encode)
3437
import Data.Int (even)
3538
import Data.Maybe (Maybe(..), fromJust, isJust)
@@ -40,7 +43,7 @@ import Data.String as S
4043
import Network.Ethereum.Core.BigNumber (BigNumber, toString, hexadecimal)
4144
import Node.Encoding (Encoding(Hex, UTF8, ASCII))
4245
import Partial.Unsafe (unsafePartial)
43-
import Simple.JSON (class ReadForeign)
46+
import Simple.JSON (class ReadForeign, class WriteForeign)
4447

4548
--------------------------------------------------------------------------------
4649
-- * Signed Values
@@ -87,18 +90,35 @@ derive newtype instance hexStringOrd :: Ord HexString
8790
derive newtype instance semigpStringEq :: Semigroup HexString
8891
derive newtype instance monoidStringEq :: Monoid HexString
8992

93+
_encode :: HexString -> String
94+
_encode = append "0x" <<< unHex
95+
96+
_decode :: String -> Either String HexString
97+
_decode str = case mkHexString str of
98+
Just res -> Right res
99+
Nothing -> Left $ "Failed to parse as HexString: " <> str
100+
90101
instance decodeHexString :: Decode HexString where
91102
decode s = do
92103
str <- decode s
93-
case stripPrefix (Pattern "0x") str of
94-
Nothing -> pure <<< HexString $ str
95-
Just res -> pure <<< HexString $ res
104+
either (fail <<< ForeignError) pure $ _decode str
96105

97106
instance readFHexString :: ReadForeign HexString where
98107
readImpl = decode
99108

109+
instance writeFHexString :: WriteForeign HexString where
110+
writeImpl = encode
111+
100112
instance encodeHexString :: Encode HexString where
101-
encode = encode <<< append "0x" <<< unHex
113+
encode = encode <<< _encode
114+
115+
instance decodeJsonHexString :: A.DecodeJson HexString where
116+
decodeJson json = do
117+
str <- A.decodeJson json
118+
_decode str
119+
120+
instance encodeJsonHexString :: A.EncodeJson HexString where
121+
encodeJson = A.encodeJson <<< _encode
102122

103123
unHex :: HexString -> String
104124
unHex (HexString hx) = hx

src/Network/Ethereum/Core/Signatures.purs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,19 @@ module Network.Ethereum.Core.Signatures
2121

2222
import Prelude
2323

24+
import Data.Argonaut as A
2425
import Data.ByteString as BS
26+
import Data.Either (Either(..), either)
2527
import Data.Function.Uncurried (Fn2, Fn3, runFn2, runFn3)
2628
import Data.Maybe (Maybe(..), fromJust)
27-
import Data.Foreign.Class (class Decode, class Encode)
29+
import Data.Foreign (ForeignError(..), fail)
30+
import Data.Foreign.Class (class Decode, class Encode, decode, encode)
2831
import Data.Generic.Rep (class Generic)
2932
import Data.Generic.Rep.Show (genericShow)
3033
import Network.Ethereum.Core.HexString (HexString, dropHex, hexLength, toByteString, fromByteString)
3134
import Network.Ethereum.Core.Keccak256 (keccak256)
3235
import Partial.Unsafe (unsafePartial)
36+
import Simple.JSON (class ReadForeign, class WriteForeign)
3337

3438
-- | Opaque PrivateKey type
3539
newtype PrivateKey = PrivateKey BS.ByteString
@@ -98,9 +102,32 @@ newtype Address = Address HexString
98102
derive newtype instance addressShow :: Show Address
99103
derive newtype instance addressEq :: Eq Address
100104
derive newtype instance addressOrd :: Ord Address
101-
derive newtype instance decodeAddress :: Decode Address
102105
derive newtype instance encodeAddress :: Encode Address
103106

107+
_decode :: HexString -> Either String Address
108+
_decode hx = case mkAddress hx of
109+
Nothing -> Left $ "Address must be 20 bytes long: " <> show hx
110+
Just res -> Right res
111+
112+
instance decodeAddress :: Decode Address where
113+
decode a = do
114+
hxString <- decode a
115+
either (fail <<< ForeignError) pure $ _decode hxString
116+
117+
instance decodeJsonAddress :: A.DecodeJson Address where
118+
decodeJson json = do
119+
hxString <- A.decodeJson json
120+
_decode hxString
121+
122+
instance encodeJsonAddress :: A.EncodeJson Address where
123+
encodeJson = A.encodeJson <<< unAddress
124+
125+
instance readFAddress :: ReadForeign Address where
126+
readImpl = decode
127+
128+
instance writeFAddress :: WriteForeign Address where
129+
writeImpl = encode
130+
104131
unAddress :: Address -> HexString
105132
unAddress (Address a) = a
106133

test/Spec/BigNumber.purs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,19 @@ module CoreSpec.BigNumber (bigNumberSpec) where
22

33

44
import Prelude
5-
import Data.Maybe (Maybe(Just))
5+
6+
import Control.Monad.Except (runExcept)
7+
import Data.Argonaut as A
8+
import Data.Either (Either(..), fromRight)
9+
import Data.Foreign (toForeign)
10+
import Data.Foreign.Class (decode, encode)
11+
import Data.Maybe (Maybe(Just), fromJust)
12+
import Network.Ethereum.Core.BigNumber (BigNumber, decimal, embed, hexadecimal, parseBigNumber)
13+
import Partial.Unsafe (unsafePartial)
14+
import Simple.JSON (readImpl)
615
import Test.Spec (Spec, describe, it)
716
import Test.Spec.Assertions (shouldEqual)
8-
import Network.Ethereum.Core.BigNumber (BigNumber, decimal, embed, hexadecimal, parseBigNumber)
17+
918

1019
bigNumberSpec :: forall r . Spec r Unit
1120
bigNumberSpec = describe "BigNumber-spec" do
@@ -47,3 +56,15 @@ bigNumberSpec = describe "BigNumber-spec" do
4756
((parseBigNumber decimal "21") >>= \x -> pure $ x - zero) `shouldEqual` parseBigNumber hexadecimal "0x15"
4857
(Just $ one `mul` one) `shouldEqual` parseBigNumber decimal "1"
4958
(Just $ one * embed (-7)) `shouldEqual` parseBigNumber hexadecimal "-0x7"
59+
60+
it "can handle deserialization" do
61+
let bnString = "f43"
62+
d1 = unsafePartial $ fromRight $ runExcept $ readImpl (toForeign bnString)
63+
d2 = unsafePartial $ fromRight $ runExcept $ decode (toForeign bnString)
64+
d3 = unsafePartial $ fromRight $ A.decodeJson (A.fromString bnString)
65+
d4 = unsafePartial $ fromJust $ parseBigNumber hexadecimal bnString
66+
d4 `shouldEqual` d1
67+
d4 `shouldEqual` d2
68+
d4 `shouldEqual` d3
69+
runExcept (decode (encode d1)) `shouldEqual` Right d4
70+
(A.decodeJson (A.encodeJson d1)) `shouldEqual` Right d4

test/Spec/Hex.purs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,17 @@ module CoreSpec.Hex (hexSpec) where
22

33
import Prelude
44

5+
import Control.Monad.Except (runExcept)
6+
import Data.Argonaut as A
57
import Data.ByteString as BS
8+
import Data.Either (Either(..), fromRight)
9+
import Data.Foreign (toForeign)
10+
import Data.Foreign.Class (encode, decode)
611
import Data.Maybe (Maybe(Just), fromJust)
7-
import Network.Ethereum.Core.HexString (mkHexString, toByteString, toUtf8, toAscii, fromUtf8, fromAscii)
12+
import Network.Ethereum.Core.HexString (HexString, mkHexString, toByteString, toUtf8, toAscii, fromUtf8, fromAscii)
813
import Node.Encoding (Encoding(Hex))
914
import Partial.Unsafe (unsafePartial)
15+
import Simple.JSON (readImpl)
1016
import Test.Spec (Spec, describe, it)
1117
import Test.Spec.Assertions (shouldEqual)
1218

@@ -46,3 +52,24 @@ hexSpec = describe "hex-spec" do
4652
it "can convert asci to hex" do
4753
fromAscii "myString" `shouldEqual` unsafePartial (fromJust <<< mkHexString) "6d79537472696e67"
4854
fromAscii "myString\00" `shouldEqual` unsafePartial (fromJust <<< mkHexString) "6d79537472696e6700"
55+
56+
describe "json tests" do
57+
58+
it "can convert hex strings to and from json" do
59+
60+
let hx = (unsafePartial (fromJust <<< mkHexString) "0x6d79537472696e67")
61+
hxJson = A.fromString "0x6d79537472696e67"
62+
(A.encodeJson <$> (A.decodeJson hxJson :: Either String HexString)) `shouldEqual` Right hxJson
63+
A.decodeJson (A.encodeJson hx) `shouldEqual` Right hx
64+
65+
it "can handle deserialization" do
66+
let hxString = "0f43"
67+
d1 = unsafePartial $ fromRight $ runExcept $ readImpl (toForeign hxString)
68+
d2 = unsafePartial $ fromRight $ runExcept $ decode (toForeign hxString)
69+
d3 = unsafePartial $ fromRight $ A.decodeJson (A.fromString hxString)
70+
d4 = unsafePartial $ fromJust $ mkHexString hxString
71+
d4 `shouldEqual` d1
72+
d4 `shouldEqual` d2
73+
d4 `shouldEqual` d3
74+
runExcept (decode (encode d1)) `shouldEqual` Right d4
75+
(A.decodeJson (A.encodeJson d1)) `shouldEqual` Right d4

0 commit comments

Comments
 (0)