11module Network.Ethereum.Web3.Solidity.AbiEncoding where
22
33import Prelude
4- import Data.Array (length ) as A
4+ import Data.Array (length , fold ) as A
55import Data.ByteString (ByteString )
66import Data.ByteString (toUTF8 , fromUTF8 , toString , fromString , length , Encoding (Hex)) as BS
77import Data.Either (Either )
88import Data.Foldable (foldMap )
99import Data.Functor.Tagged (Tagged , tagged , untagged )
1010import Data.Maybe (maybe , fromJust )
11- import Data.String.CodeUnits ( fromCharArray )
11+ import Data.String ( splitAt )
1212import Data.Unfoldable (replicateA )
1313import Network.Ethereum.Core.BigNumber (toTwosComplement , unsafeToInt )
14- import Network.Ethereum.Core.HexString (HexString , Signed (..), getPadLength , mkHexString , padLeft , padLeftSigned , padRight , toBigNumberFromSignedHexString , toBigNumber , toSignedHexString , unHex )
14+ import Network.Ethereum.Core.HexString (HexString , Signed (..), mkHexString , padLeft , padLeftSigned , padRight , toBigNumberFromSignedHexString , toBigNumber , toSignedHexString , unHex , numberOfBytes )
1515import Network.Ethereum.Types (Address , BigNumber , embed , mkAddress , unAddress )
1616import Network.Ethereum.Web3.Solidity.Bytes (BytesN , unBytesN , update , proxyBytesN )
1717import Network.Ethereum.Web3.Solidity.Int (IntN , unIntN , intNFromBigNumber )
1818import Network.Ethereum.Web3.Solidity.Size (class ByteSize , class IntSize , class KnownSize , DLProxy (..), sizeVal )
1919import Network.Ethereum.Web3.Solidity.UInt (UIntN , unUIntN , uIntNFromBigNumber )
2020import Network.Ethereum.Web3.Solidity.Vector (Vector )
2121import Partial.Unsafe (unsafePartial )
22- import Text.Parsing.Parser (ParseError , Parser , ParserT , fail , runParser )
23- import Text.Parsing.Parser.String (anyChar )
22+ import Text.Parsing.Parser (ParseError , Parser , ParseState (..), ParserT , fail , runParser )
23+ import Control.Monad.State (get , put )
24+ import Text.Parsing.Parser.Pos (Position (..))
2425
2526-- | Class representing values that have an encoding and decoding instance to/from a solidity type.
2627class ABIEncode a where
@@ -56,8 +57,8 @@ instance abiEncodeAddress :: ABIEncode Address where
5657
5758instance abiDecodeAddress :: ABIDecode Address where
5859 fromDataParser = do
59- _ <- take 24
60- maddr <- mkAddress <$> take 40
60+ _ <- parseBytes 12
61+ maddr <- mkAddress <$> parseBytes 20
6162 maybe (fail " Address is 20 bytes, receieved more" ) pure maddr
6263
6364instance abiEncodeBytesD :: ABIEncode ByteString where
@@ -66,7 +67,7 @@ instance abiEncodeBytesD :: ABIEncode ByteString where
6667instance abiDecodeBytesD :: ABIDecode ByteString where
6768 fromDataParser = do
6869 len <- unsafeToInt <$> fromDataParser
69- bytesDecode <<< unHex <$> take ( len * 2 )
70+ bytesDecode <<< unHex <$> parseBytes len
7071
7172instance abiEncodeString :: ABIEncode String where
7273 toDataBuilder = toDataBuilder <<< BS .toUTF8
@@ -82,9 +83,9 @@ instance abiDecodeBytesN :: ByteSize n => ABIDecode (BytesN n) where
8283 let
8384 len = sizeVal (DLProxy :: DLProxy n )
8485
85- zeroBytes = getPadLength (len * 2 )
86- raw <- take $ len * 2
87- _ <- take $ zeroBytes
86+ zeroBytes = 32 - len
87+ raw <- parseBytes len
88+ _ <- parseBytes zeroBytes
8889 pure <<< update proxyBytesN <<< bytesDecode <<< unHex $ raw
8990
9091instance abiEncodeVector :: (ABIEncode a , KnownSize n ) => ABIEncode (Vector n a ) where
@@ -168,11 +169,11 @@ uInt256HexBuilder x =
168169
169170-- | Parse as a signed `BigNumber`
170171int256HexParser :: forall m . Monad m => ParserT HexString m BigNumber
171- int256HexParser = toBigNumberFromSignedHexString <$> take 64
172+ int256HexParser = toBigNumberFromSignedHexString <$> parseBytes 32
172173
173174-- | Parse an unsigned `BigNumber`
174175uInt256HexParser :: forall m . Monad m => ParserT HexString m BigNumber
175- uInt256HexParser = toBigNumber <$> take 64
176+ uInt256HexParser = toBigNumber <$> parseBytes 32
176177
177178-- | Decode a `Boolean` as a BigNumber
178179fromBool :: Boolean -> BigNumber
@@ -183,5 +184,20 @@ toBool :: BigNumber -> Boolean
183184toBool bn = not $ bn == zero
184185
185186-- | Read any number of HexDigits
186- take :: forall m . Monad m => Int -> ParserT HexString m HexString
187- take n = unsafePartial fromJust <<< mkHexString <<< fromCharArray <$> replicateA n anyChar
187+ parseBytes :: forall m . Monad m => Int -> ParserT HexString m HexString
188+ parseBytes n = A .fold <$> replicateA n parseByte
189+
190+ parseByte :: forall m . Monad m => ParserT HexString m HexString
191+ parseByte = do
192+ ParseState input (Position position) _ <- get
193+ if numberOfBytes input < 1 then
194+ fail " Unexpected EOF"
195+ else do
196+ let
197+ { after, before } = splitAt 2 (unHex input)
198+
199+ unsafeMkHex s = unsafePartial $ fromJust $ mkHexString s
200+
201+ position' = Position $ position { column = position.column + 1 }
202+ put $ ParseState (unsafeMkHex after) position' true
203+ pure $ unsafeMkHex before
0 commit comments