packages feed

azimuth-hs 0.2.0 → 0.2.1

raw patch · 7 files changed

+103/−25 lines, 7 files

Files

CHANGELOG view
@@ -1,5 +1,11 @@ # Changelog +- 0.2.1 (2020-08-13)+    * Allows the specification of optional transaction parameters via+      Urbit.Azimuth.runAzimuth' (note the apostrophe).+    * The chain ID must now be passed explicitly to the+      Urbit.Azimuth.Account.toPrivateKey helper (previously it defaulted to 1).+ - 0.2.0 (2020-08-13)     * Generalizes account types to include hs-web3's 'DefaultAccount' and       'PersonalAccount', in addition to the existing 'LocalKeyAccount'.
azimuth-hs.cabal view
@@ -1,6 +1,6 @@ cabal-version: 2.4 name:          azimuth-hs-version:       0.2.0+version:       0.2.1 synopsis:      Interact with Azimuth from Haskell description:   Haskell bindings for Azimuth (https://github.com/urbit/azimuth) homepage:      https://github.com/urbit/azimuth-hs
lib/Urbit/Azimuth/Account.hs view
@@ -34,23 +34,25 @@  type Unlockable p m = (JsonRpc m, A.Account p (AI.AccountT p)) --- | Recover a private key from a BIP39 mnemonic, passphrase, and HD derivation---   path.+-- | Recover a private key from a BIP39 mnemonic, passphrase, HD derivation+--   path, and chain ID. -- --   Note that you can use the monoid unit, 'mempty', to denote an empty or---   absent passphrase.+--   absent passphrase.  It's also worth noting that you'll typically want to+--   use a chain ID of '1' (i.e., the Ethereum mainnet). -- --   >>> let mnem = "benefit crew supreme gesture quantum web media hazard theory mercy wing kitten"---   >>> let hdpath = Deriv :| 44 :| 60 :| 0 :/ 0 :/ 0 -- m/44'/60'/0'/0/0---   >>> toPrivateKey mnem mempty hdpath+--   >>> let hdpath = "m/44'/60'/0'/0/0" :: DerivPath+--   >>> toPrivateKey mnem mempty hdpath 1 toPrivateKey   :: K.Mnemonic   -> K.Passphrase   -> K.DerivPath+  -> Integer   -> Either String A.LocalKey-toPrivateKey mnem pass path = do+toPrivateKey mnem pass path chainId = do   seed <- K.mnemonicToSeed pass mnem-  pure . flip A.LocalKey 1 -- NB this targets mainnet only+  pure . flip A.LocalKey chainId     . C.importKey     . K.getSecKey     . K.xPrvKey
lib/Urbit/Azimuth/Contract.hs view
@@ -1,7 +1,6 @@ {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE NumericUnderscores #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-} @@ -12,16 +11,18 @@    , Azimuth(..)   , runAzimuth+  , runAzimuth'   ) where  import Control.Monad.Trans (lift)-import Control.Monad.Reader (ReaderT(..), ask)+import Control.Monad.Reader (ReaderT(..), asks) import Data.Solidity.Prim.Address (Address) import qualified Network.Ethereum.Account as Ethereum.Account import qualified Network.Ethereum.Account.Internal as AI import qualified Network.Ethereum.Ens as Ethereum.Ens import Network.JsonRpc.TinyClient (JsonRpc) import Urbit.Azimuth.Account+import Urbit.Azimuth.Transaction  -- | Supported Azimuth contracts. data Contracts = Contracts {@@ -29,13 +30,19 @@   , ecliptic :: Address   } deriving stock Show +-- | The environment for any given Azimuth action.+data AzimuthEnv = AzimuthEnv {+    azimuthContracts :: Contracts+  , azimuthTxnParams :: Maybe TxnParams+  } deriving stock Show+ -- | The Azimuth type represents an authenticated connection to a JSON RPC by --   way of a local private key, and has access to a 'Contracts' object. newtype Azimuth p m a =-    Azimuth (ReaderT Contracts (AI.AccountT p m) a)+    Azimuth (ReaderT AzimuthEnv (AI.AccountT p m) a)   deriving newtype (Functor, Applicative, Monad) --- | Run an Azimuth action.+-- | Run an Azimuth action using default optional transaction parameters. runAzimuth   :: Unlockable p m   => Contracts@@ -43,8 +50,21 @@   -> Azimuth p m a   -> m a runAzimuth contracts account (Azimuth action) = withAccount account $-  runReaderT action contracts+  runReaderT action (AzimuthEnv contracts Nothing) +-- | Run an Azimuth action, specifying optional transaction parameters+--   explicitly.+runAzimuth'+  :: Unlockable p m+  => Contracts+  -> TxnParams+  -> p+  -> Azimuth p m a+  -> m a+runAzimuth' contracts params account (Azimuth action) =+  withAccount account $+    runReaderT action (AzimuthEnv contracts (Just params))+ -- | Fetch the Azimuth and Ecliptic contracts by way of their ENS records. getContracts :: JsonRpc m => m Contracts getContracts = withAccount () $ do@@ -59,11 +79,31 @@   -> AI.AccountT p m a   -> Azimuth p m a withContract selector action = Azimuth $ do-  contracts <- ask-  lift $ Ethereum.Account.withParam (\param -> param {-    AI._to    = Just (selector contracts)-  -- NB hardcoded to 40 gwei at present-  -- going to want a better way to specify gas price-  , AI._gasPrice = Just 40_000_000_000-  }) action+  contracts <- asks azimuthContracts+  txnParams <- asks azimuthTxnParams +  let contract = Just (selector contracts)++      TxnParams {..} = case txnParams of+        Nothing -> defaultTxnParams+        Just ps -> ps++      -- NB this can probably be improved with a better understanding of+      --    Network.Ethereum.Api.Types.DefaultBlock+      --+      param pars = case txnBlock of++        Just block -> pars {+            AI._to       = contract+          , AI._gasLimit = fmap fromIntegral txnGasLimit+          , AI._gasPrice = fmap fromIntegral txnGasPrice+          , AI._block    = block+          }++        Nothing -> pars {+            AI._to       = contract+          , AI._gasLimit = fmap fromIntegral txnGasLimit+          , AI._gasPrice = fmap fromIntegral txnGasPrice+          }++  lift $ Ethereum.Account.withParam param action
lib/Urbit/Azimuth/Transaction.hs view
@@ -1,7 +1,28 @@+{-# LANGUAGE DerivingStrategies #-}+{-# LANGUAGE NumericUnderscores #-}  module Urbit.Azimuth.Transaction (     Api.TxReceipt(..)++  , TxnParams(..)+  , defaultTxnParams   ) where  import qualified Network.Ethereum.Api.Types as Api+import Numeric.Natural++-- | Optional transaction parameters for Azimuth actions.+data TxnParams = TxnParams {+    txnGasLimit :: Maybe Natural+  , txnGasPrice :: Maybe Natural+  , txnBlock    :: Maybe Api.DefaultBlock+  } deriving stock Show++-- | Default optional transaction parameters (i.e., a gas price of 80 Gwei).+defaultTxnParams :: TxnParams+defaultTxnParams = TxnParams {+    txnGasLimit = Nothing+  , txnGasPrice = Just 80_000_000_000+  , txnBlock    = Nothing+  } 
test/Doc.hs view
@@ -30,10 +30,13 @@   let mnem = "benefit crew supreme gesture quantum "           <> "web media hazard theory mercy wing kitten" -  -- and a standard HD path+  -- a standard HD path   let hdpath  = "m/44'/60'/0'/0/0" :: A.DerivPath -  let account = case A.toPrivateKey mnem mempty hdpath of+  -- and ethereum mainnet+  let chainId = 1++  let account = case A.toPrivateKey mnem mempty hdpath chainId of         Left _    -> error "bogus creds"         Right acc -> acc 
test/Main.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE NumericUnderscores #-} {-# LANGUAGE RecordWildCards #-}  module Main where@@ -52,9 +53,9 @@ testConfig = Config {..} where   endpt        = "http://localhost:8545"   pbase        = A.Deriv A.:| 44 A.:| 60 A.:| 0 A.:/ 0-  Right pk0    = A.toPrivateKey mnem mempty (pbase A.:/ 0)-  Right pk1    = A.toPrivateKey mnem mempty (pbase A.:/ 1)-  Right pk2    = A.toPrivateKey mnem mempty (pbase A.:/ 2)+  Right pk0    = A.toPrivateKey mnem mempty (pbase A.:/ 0) 1+  Right pk1    = A.toPrivateKey mnem mempty (pbase A.:/ 1) 1+  Right pk2    = A.toPrivateKey mnem mempty (pbase A.:/ 2) 1    mnem         = "benefit crew supreme gesture quantum web media hazard " <>                  "theory mercy wing kitten"@@ -165,3 +166,8 @@       getRift z1 `shouldSatisfy` (> (getRift z0))       getRift n1 `shouldSatisfy` (> (getRift n0)) +    it "works with optional transaction parameters" $ do+      let txnParams = A.defaultTxnParams { A.txnGasPrice = 100_000_000_000 }+      A.runWeb3 endpoint $+        A.runAzimuth' contracts txnParams pk0 $+          A.configureKeys zod keys A.Rotate