diff --git a/bower.json b/bower.json index 4c60b6c..2129866 100644 --- a/bower.json +++ b/bower.json @@ -28,7 +28,7 @@ "purescript-node-fs-aff": "^5.0.0", "purescript-console": "^3.0.0", "purescript-string-parsers": "^3.0.1", - "purescript-web3": "^0.24.0", + "purescript-web3": "^0.25.0", "purescript-mkdirp": "^0.3.0", "purescript-fixed-points": "^4.0.0", "purescript-record-extra": "^0.3.0" diff --git a/src/Data/AbiParser.purs b/src/Data/AbiParser.purs index a31b7e2..1c03d4b 100644 --- a/src/Data/AbiParser.purs +++ b/src/Data/AbiParser.purs @@ -8,10 +8,10 @@ import Data.Argonaut as A import Data.Argonaut.Core (fromObject) import Data.Argonaut.Decode ((.?)) import Data.Argonaut.Decode.Class (class DecodeJson, decodeJson) -import Data.Array (fromFoldable) +import Data.Array (fromFoldable, null) import Data.Bifunctor (lmap) import Data.Either (Either(..)) -import Data.Foldable (foldMap) +import Data.Foldable (all, foldMap) import Data.FunctorWithIndex (mapWithIndex) import Data.Generic (class Generic, gEq, gShow) import Data.Int (fromString) @@ -174,6 +174,7 @@ data SolidityFunction = , constant :: Boolean , payable :: Boolean , isConstructor :: Boolean + , isUnCurried :: Boolean } derive instance genericSolidityFunction :: Generic SolidityFunction @@ -195,6 +196,8 @@ instance decodeJsonSolidityFunction :: DecodeJson SolidityFunction where , constant : c , payable: p , isConstructor: false + , isUnCurried: all (\(FunctionInput fi) -> fi.name /= "") is + && not (null is) } -------------------------------------------------------------------------------- @@ -203,6 +206,7 @@ instance decodeJsonSolidityFunction :: DecodeJson SolidityFunction where data SolidityConstructor = SolidityConstructor { inputs :: Array FunctionInput + , isUnCurried :: Boolean } derive instance genericSolidityConstructor :: Generic SolidityConstructor @@ -215,6 +219,8 @@ instance decodeJsonSolidityConstructor :: DecodeJson SolidityConstructor where obj <- decodeJson json is <- obj .? "inputs" pure $ SolidityConstructor { inputs : is + , isUnCurried: all (\(FunctionInput fi) -> fi.name /= "") is + && not (null is) } -------------------------------------------------------------------------------- diff --git a/src/Data/Generator.purs b/src/Data/Generator.purs index 3f75cfb..64070d8 100644 --- a/src/Data/Generator.purs +++ b/src/Data/Generator.purs @@ -5,7 +5,7 @@ import Prelude import Control.Monad.Writer (Writer, tell) import Data.AbiParser (Abi(..), AbiType(..), FunctionInput(..), IndexedSolidityValue(..), SolidityEvent(..), SolidityFunction(..), SolidityConstructor(..), SolidityType(..), format) import Data.Array (filter, length, mapWithIndex, null, replicate, uncons, unsnoc, zip, zipWith, (:)) -import Data.Foldable (all, fold) +import Data.Foldable (fold) import Data.Identity (Identity(..)) import Data.List (uncons) as List import Data.List.Types (NonEmptyList(..)) as List @@ -13,7 +13,7 @@ import Data.Maybe (Maybe(..)) import Data.Newtype (un) import Data.NonEmpty ((:|)) import Data.String (drop, fromCharArray, joinWith, singleton, take, toCharArray, toLower, toUpper) -import Data.Traversable (for, traverse) +import Data.Traversable (for) import Data.Tuple (Tuple(..), uncurry) import Network.Ethereum.Core.HexString (fromByteString) import Network.Ethereum.Core.Keccak256 (keccak256) @@ -146,8 +146,10 @@ data FunTypeDecl = funToTypeDecl :: SolidityFunction -> CodeOptions -> Imported FunTypeDecl funToTypeDecl fun@(SolidityFunction f) opts = do - factorTypes <- for f.inputs $ \(FunctionInput fi) -> - toPSType $ fi.type + factorTypes <- + if f.isUnCurried + then for f.inputs tagInput + else for f.inputs $ \(FunctionInput fi) -> toPSType fi.type pure $ FunTypeDecl { typeName: if isValidType f.name then capitalize $ f.name <> "Fn" else "FnT" <> f.name <> "Fn" @@ -211,8 +213,8 @@ funToHelperFunction isWhereClause fun@(SolidityFunction f) opts = do pure ["TransactionOptions NoPay", "ChainCursor"] else if f.payable then do - import' "Network.Ethereum.Web3.Types" [IType "Wei"] - pure ["TransactionOptions Wei"] + import' "Network.Ethereum.Web3.Types.TokenUnit" [IType "MinorUnit"] + pure ["TransactionOptions MinorUnit"] else do import' "Network.Ethereum.Web3.Types" [IType "NoPay"] pure ["TransactionOptions NoPay"] @@ -232,7 +234,10 @@ funToHelperFunction isWhereClause fun@(SolidityFunction f) opts = do helperTransport <- toTransportPrefix f.isConstructor f.constant $ length f.outputs helperPayload <- toPayload isWhereClause decl.typeName conVars returnType <- toReturnType f.constant f.outputs - ins <- for f.inputs $ \(FunctionInput fi) -> toPSType fi.type + ins <- + if f.isUnCurried + then for f.inputs tagInput + else for f.inputs $ \(FunctionInput fi) -> toPSType fi.type pure { signature: sigPrefix <> ins <> [returnType] , unpackExpr: @@ -263,8 +268,8 @@ funToHelperFunction' fun@(SolidityFunction f) opts = do pure ["TransactionOptions NoPay", "ChainCursor"] else if f.payable then do - import' "Network.Ethereum.Web3.Types" [IType "Wei"] - pure ["TransactionOptions Wei"] + import' "Network.Ethereum.Web3.Types.TokenUnit" [IType "MinorUnit"] + pure ["TransactionOptions MinorUnit"] else do import' "Network.Ethereum.Web3.Types" [IType "NoPay"] pure ["TransactionOptions NoPay"] @@ -292,11 +297,6 @@ funToHelperFunction' fun@(SolidityFunction f) opts = do , whereClause: whereC } where - tagInput (FunctionInput fi) = do - ty <- toPSType fi.type - import' "Data.Functor.Tagged" [IType "Tagged"] - import' "Data.Symbol" [IType "SProxy"] - pure $ "Tagged (SProxy " <> "\"" <> fi.name <> "\") " <> ty recordInput fis = do rowElems <- for fis $ \(FunctionInput fi) -> do ty <- toPSType fi.type @@ -304,7 +304,10 @@ funToHelperFunction' fun@(SolidityFunction f) opts = do pure $ "{ " <> joinWith ", " rowElems <> " }" whereHelper d pre is ret = do helper <- funToHelperFunction true fun opts - tys <- traverse tagInput is + tys <- + if f.isUnCurried + then for f.inputs tagInput + else for f.inputs $ \(FunctionInput fi) -> toPSType fi.type pure $ CurriedHelperFunction helper { constraints = [] , quantifiedVars = [] @@ -312,6 +315,15 @@ funToHelperFunction' fun@(SolidityFunction f) opts = do , signature = pre <> tys <> [ret] } +tagInput + :: FunctionInput + -> Imported String +tagInput (FunctionInput fi) = do + ty <- toPSType fi.type + import' "Data.Functor.Tagged" [IType "Tagged"] + import' "Data.Symbol" [IType "SProxy"] + pure $ "(Tagged (SProxy " <> "\"" <> fi.name <> "\") " <> ty <> ")" + toTransportPrefix :: Boolean -> Boolean -> Int -> Imported String toTransportPrefix isConstructor isCall outputCount = do fun <- if isConstructor @@ -340,13 +352,7 @@ toPayload isWhereClause typeName args = do import' "Data.Functor.Tagged" [IVal "tagged"] let tupleType = "Tuple" <> show (length args) import' "Network.Ethereum.Web3.Solidity" [ITypeCtr tupleType] - args' <- if isWhereClause - then do - import' "Data.Functor.Tagged" [IVal "untagged"] - pure $ map (\s -> "(untagged " <> s <> " )") args - else pure args - - pure $ "((tagged $ " <> tupleType <> " " <> joinWith " " args' <> ") :: " <> typeName <> ")" + pure $ "((tagged $ " <> tupleType <> " " <> joinWith " " args <> ") :: " <> typeName <> ")" toReturnType :: Boolean -> Array SolidityType -> Imported String toReturnType constant outputs' = do @@ -573,13 +579,11 @@ data CodeBlock = funToFunctionCodeBlock :: SolidityFunction -> CodeOptions -> Imported CodeBlock funToFunctionCodeBlock fun@(SolidityFunction f) opts = do - typeDecl <- funToTypeDecl fun opts - helperFunction <- if isUnCurried f - then funToHelperFunction' fun opts - else funToHelperFunction false fun opts <#> CurriedHelperFunction - pure $ FunctionCodeBlock typeDecl helperFunction - where - isUnCurried f' = all (\(FunctionInput fi) -> fi.name /= "") f'.inputs && not (null f'.inputs) + typeDecl <- funToTypeDecl fun opts + helperFunction <- if f.isUnCurried + then funToHelperFunction' fun opts + else funToHelperFunction false fun opts <#> CurriedHelperFunction + pure $ FunctionCodeBlock typeDecl helperFunction newLine1 :: Array String -> String newLine1 = joinWith "\n" @@ -629,6 +633,7 @@ instance codeAbi :: Code (Abi Identity) where , constant : false , payable : false , isConstructor : true + , isUnCurried: c.isUnCurried } functionCodeBlock <- funToFunctionCodeBlock f opts genCode functionCodeBlock opts