├── scripts ├── local │ ├── mint-test-tokens │ │ ├── unit.json │ │ ├── alwaysSucceedsMintingPolicy.plutus │ │ └── mint.sh │ ├── one-way │ │ ├── create-reference-scripts.sh │ │ ├── register-beacon-script.sh │ │ ├── swap-assets.sh │ │ ├── close-swap.sh │ │ ├── create-swap.sh │ │ ├── update-price.sh │ │ └── convert-swap.sh │ └── two-way │ │ ├── create-reference-scripts.sh │ │ ├── register-beacon-script.sh │ │ ├── swap-assets.sh │ │ ├── close-swap.sh │ │ ├── create-swap.sh │ │ ├── update-price.sh │ │ └── convert-swap.sh └── remote │ ├── mint-test-tokens │ ├── unit.json │ ├── alwaysSucceedsMintingPolicy.plutus │ └── mint.sh │ ├── two-way │ ├── create-reference-scripts.sh │ ├── register-beacon-script.sh │ ├── swap-assets.sh │ ├── create-swap.sh │ └── close-swap.sh │ └── one-way │ ├── create-reference-scripts.sh │ ├── register-beacon-script.sh │ ├── swap-assets.sh │ ├── create-swap.sh │ ├── close-swap.sh │ └── update-price.sh ├── .gitignore ├── aiken ├── aiken.lock ├── lib │ └── cardano_swaps │ │ ├── common │ │ ├── types.ak │ │ └── utils.ak │ │ ├── one_way_swap │ │ └── types.ak │ │ └── two_way_swap │ │ └── types.ak └── aiken.toml ├── test ├── Test.hs └── Test │ ├── OneWaySwap.hs │ ├── TwoWaySwap.hs │ ├── OneWaySwap │ ├── UnsafeDatum.hs │ └── BeaconNames.hs │ └── TwoWaySwap │ ├── UnsafeDatum.hs │ └── BeaconNames.hs ├── app ├── Main.hs └── CLI │ ├── Types.hs │ └── Query.hs ├── src └── CardanoSwaps │ ├── Blueprints.hs │ ├── OneWaySwap.hs │ ├── TwoWaySwap.hs │ └── Utils.hs ├── cabal.project ├── cardano-swaps.cabal ├── CHANGELOG.md ├── Benchmarks ├── TwoWaySwap.md └── OneWaySwap.md └── OrderBookExample.md /scripts/local/mint-test-tokens/unit.json: -------------------------------------------------------------------------------- 1 | {"constructor":0,"fields":[]} -------------------------------------------------------------------------------- /scripts/remote/mint-test-tokens/unit.json: -------------------------------------------------------------------------------- 1 | {"constructor":0,"fields":[]} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist-newstyle/ 2 | TODO 3 | ignored/ 4 | aiken/artifacts/ 5 | aiken/build/ 6 | aiken/docs/ 7 | -------------------------------------------------------------------------------- /scripts/local/mint-test-tokens/alwaysSucceedsMintingPolicy.plutus: -------------------------------------------------------------------------------- 1 | { 2 | "type": "PlutusScriptV2", 3 | "description": "", 4 | "cborHex": "484701000022120011" 5 | } 6 | -------------------------------------------------------------------------------- /scripts/remote/mint-test-tokens/alwaysSucceedsMintingPolicy.plutus: -------------------------------------------------------------------------------- 1 | { 2 | "type": "PlutusScriptV2", 3 | "description": "", 4 | "cborHex": "484701000022120011" 5 | } 6 | -------------------------------------------------------------------------------- /aiken/aiken.lock: -------------------------------------------------------------------------------- 1 | # This file was generated by Aiken 2 | # You typically do not need to edit this file 3 | 4 | [[requirements]] 5 | name = "aiken-lang/stdlib" 6 | version = "1.7.0" 7 | source = "github" 8 | 9 | [[packages]] 10 | name = "aiken-lang/stdlib" 11 | version = "1.7.0" 12 | requirements = [] 13 | source = "github" 14 | 15 | [etags] 16 | -------------------------------------------------------------------------------- /test/Test.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | module Main where 4 | 5 | import Test.Tasty 6 | 7 | import Test.OneWaySwap as OneWaySwap 8 | import Test.TwoWaySwap as TwoWaySwap 9 | 10 | main :: IO () 11 | main = do 12 | defaultMain $ testGroup "Cardano-Swaps" 13 | [ OneWaySwap.tests 14 | , TwoWaySwap.tests 15 | ] 16 | -------------------------------------------------------------------------------- /aiken/lib/cardano_swaps/common/types.ak: -------------------------------------------------------------------------------- 1 | use aiken/transaction/value.{PolicyId,AssetName} 2 | 3 | // Allows creating unique minting policies for testing purposes. 4 | pub const app_name = @"" 5 | 6 | pub type AssetConfig { 7 | asset_id: PolicyId, 8 | asset_name: AssetName 9 | } 10 | 11 | pub type Rational { 12 | numerator: Int, 13 | denominator: Int 14 | } 15 | -------------------------------------------------------------------------------- /aiken/aiken.toml: -------------------------------------------------------------------------------- 1 | name = "fallen-icarus/cardano_swaps" 2 | version = "0.0.0" 3 | license = "Apache-2.0" 4 | description = "Aiken contracts for project 'fallen-icarus/cardano_swaps'" 5 | 6 | [repository] 7 | user = "fallen-icarus" 8 | project = "cardano_swaps" 9 | platform = "github" 10 | 11 | [[dependencies]] 12 | name = "aiken-lang/stdlib" 13 | version = "1.7.0" 14 | source = "github" 15 | -------------------------------------------------------------------------------- /app/Main.hs: -------------------------------------------------------------------------------- 1 | module Main where 2 | 3 | import Options.Applicative 4 | 5 | import CLI.Parsers (parseCommand) 6 | import CLI.Run 7 | 8 | main :: IO () 9 | main = do 10 | let preferences = prefs $ showHelpOnError <> showHelpOnEmpty 11 | opts = info (parseCommand <**> helper) (fullDesc <> progDesc "A fully p2p Cardano DEX") 12 | customExecParser preferences opts >>= runCommand 13 | -------------------------------------------------------------------------------- /test/Test/OneWaySwap.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | module Test.OneWaySwap where 4 | 5 | import Test.Tasty 6 | 7 | import qualified Test.OneWaySwap.CreateSwap as CreateSwap 8 | import qualified Test.OneWaySwap.UpdateSwap as UpdateSwap 9 | import qualified Test.OneWaySwap.CloseSwap as CloseSwap 10 | import qualified Test.OneWaySwap.Swap as Swap 11 | import qualified Test.OneWaySwap.BeaconNames as BeaconNames 12 | 13 | tests :: TestTree 14 | tests = testGroup "One-Way Swaps" 15 | [ CreateSwap.tests 16 | , CloseSwap.tests 17 | , UpdateSwap.tests 18 | , Swap.tests 19 | , BeaconNames.tests 20 | ] 21 | -------------------------------------------------------------------------------- /test/Test/TwoWaySwap.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | module Test.TwoWaySwap where 4 | 5 | import Test.Tasty 6 | 7 | import qualified Test.TwoWaySwap.CreateSwap as CreateSwap 8 | import qualified Test.TwoWaySwap.UpdateSwap as UpdateSwap 9 | import qualified Test.TwoWaySwap.CloseSwap as CloseSwap 10 | import qualified Test.TwoWaySwap.Swap as Swap 11 | import qualified Test.TwoWaySwap.BeaconNames as BeaconNames 12 | 13 | tests :: TestTree 14 | tests = testGroup "Two-Way Swaps" 15 | [ CreateSwap.tests 16 | , CloseSwap.tests 17 | , UpdateSwap.tests 18 | , Swap.tests 19 | , BeaconNames.tests 20 | ] 21 | -------------------------------------------------------------------------------- /aiken/lib/cardano_swaps/one_way_swap/types.ak: -------------------------------------------------------------------------------- 1 | use aiken/transaction.{OutputReference} 2 | use aiken/transaction/value.{PolicyId,AssetName} 3 | use cardano_swaps/common/types.{Rational} 4 | 5 | pub type SwapDatum { 6 | SwapDatum { 7 | beacon_id: PolicyId, // The beacon policy id for two-way swaps. 8 | pair_beacon: AssetName, // The asset name for the beacon for this trading pair. 9 | offer_id: PolicyId, // The policy id for the offer asset. 10 | offer_name: AssetName, // The asset name for the offer asset. 11 | offer_beacon: AssetName, // The asset name for the offer beacon. 12 | ask_id: PolicyId, // The policy id for the ask asset. 13 | ask_name: AssetName, // The asset name for the ask asset. 14 | ask_beacon: AssetName, // The asset name for the ask beacon. 15 | swap_price: Rational, // The swap price as a fraction: Ask/Offer. 16 | prev_input: Option 17 | } 18 | } 19 | 20 | pub type SwapRedeemer { 21 | SpendWithMint 22 | SpendWithStake 23 | Swap 24 | } 25 | 26 | pub type BeaconRedeemer { 27 | CreateOrCloseSwaps // Minting execution. 28 | UpdateSwaps // Staking execution. 29 | } 30 | -------------------------------------------------------------------------------- /src/CardanoSwaps/Blueprints.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | {-# LANGUAGE TemplateHaskell #-} 3 | {-# LANGUAGE StrictData #-} 4 | 5 | module CardanoSwaps.Blueprints 6 | ( -- * Blueprints 7 | blueprints 8 | ) where 9 | 10 | import Data.Aeson 11 | import Control.Monad (mzero) 12 | import qualified Data.ByteString.Lazy as LBS 13 | import qualified Data.Map as Map 14 | import Data.FileEmbed (embedFile) 15 | 16 | ------------------------------------------------- 17 | -- Blueprints 18 | ------------------------------------------------- 19 | newtype Blueprints = Blueprints (Map.Map String String) 20 | deriving (Show) 21 | 22 | instance FromJSON Blueprints where 23 | parseJSON (Object o) = 24 | Blueprints . Map.fromList <$> 25 | (o .: "validators" >>= 26 | mapM (withObject "validator" $ \o' -> (,) <$> o' .: "title" <*> o' .: "compiledCode")) 27 | parseJSON _ = mzero 28 | 29 | -- | A map from validator "title" to "compiledCode" for the aiken/plutus.json file. 30 | blueprints :: Map.Map String String 31 | blueprints = 32 | case decode $ LBS.fromStrict $(embedFile "aiken/plutus.json") of 33 | Nothing -> error "Failed to decode cardano-swaps' blueprint file" 34 | Just (Blueprints bs) -> bs 35 | -------------------------------------------------------------------------------- /test/Test/OneWaySwap/UnsafeDatum.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE RecordWildCards #-} 2 | {-# LANGUAGE StrictData #-} 3 | 4 | module Test.OneWaySwap.UnsafeDatum where 5 | 6 | import qualified PlutusTx 7 | 8 | import CardanoSwaps.Utils 9 | 10 | data UnsafeDatum = UnsafeDatum 11 | { unsafeBeaconId :: CurrencySymbol 12 | , unsafePairBeacon :: TokenName 13 | , unsafeOfferId :: CurrencySymbol 14 | , unsafeOfferName :: TokenName 15 | , unsafeOfferBeacon :: TokenName 16 | , unsafeAskId :: CurrencySymbol 17 | , unsafeAskName :: TokenName 18 | , unsafeAskBeacon :: TokenName 19 | , unsafeSwapPrice :: (Integer,Integer) 20 | , unsafePrevInput :: Maybe TxOutRef 21 | } 22 | 23 | instance PlutusTx.ToData UnsafeDatum where 24 | toBuiltinData UnsafeDatum{..} = PlutusTx.dataToBuiltinData $ 25 | PlutusTx.Constr 0 26 | [ PlutusTx.toData unsafeBeaconId 27 | , PlutusTx.toData unsafePairBeacon 28 | , PlutusTx.toData unsafeOfferId 29 | , PlutusTx.toData unsafeOfferName 30 | , PlutusTx.toData unsafeOfferBeacon 31 | , PlutusTx.toData unsafeAskId 32 | , PlutusTx.toData unsafeAskName 33 | , PlutusTx.toData unsafeAskBeacon 34 | , PlutusTx.toData unsafeSwapPrice 35 | , PlutusTx.toData unsafePrevInput 36 | ] 37 | -------------------------------------------------------------------------------- /aiken/lib/cardano_swaps/two_way_swap/types.ak: -------------------------------------------------------------------------------- 1 | use aiken/transaction.{OutputReference} 2 | use aiken/transaction/value.{PolicyId,AssetName} 3 | use cardano_swaps/common/types.{Rational} 4 | 5 | pub type SwapDatum { 6 | SwapDatum { 7 | beacon_id: PolicyId, // The beacon policy id for two-way swaps. 8 | pair_beacon: AssetName, // The asset name for the beacon for this trading pair. 9 | asset1_id: PolicyId, // The policy id for the first asset. 10 | asset1_name: AssetName, // The asset name for the first asset. 11 | asset1_beacon: AssetName, // The asset name for asset1's offer beacon. 12 | asset2_id: PolicyId, // The policy id for the second asset. 13 | asset2_name: AssetName, // The asset name for the second asset. 14 | asset2_beacon: AssetName, // The asset name for asset2's offer beacon. 15 | asset1_price: Rational, // The swap price to take asset 1 as a fraction: Asset2/Asset1 16 | asset2_price: Rational, // The swap price to take asset 2 as a fraction: Asset1/Asset2 17 | prev_input: Option 18 | } 19 | } 20 | 21 | pub type SwapRedeemer { 22 | SpendWithMint 23 | SpendWithStake 24 | TakeAsset1 25 | TakeAsset2 26 | } 27 | 28 | pub type BeaconRedeemer { 29 | CreateOrCloseSwaps // Minting execution. 30 | UpdateSwaps // Staking execution. 31 | } 32 | -------------------------------------------------------------------------------- /test/Test/TwoWaySwap/UnsafeDatum.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE RecordWildCards #-} 2 | {-# LANGUAGE StrictData #-} 3 | 4 | module Test.TwoWaySwap.UnsafeDatum where 5 | 6 | import qualified PlutusTx 7 | 8 | import CardanoSwaps.Utils 9 | 10 | data UnsafeDatum = UnsafeDatum 11 | { unsafeBeaconId :: CurrencySymbol 12 | , unsafePairBeacon :: TokenName 13 | , unsafeAsset1Id :: CurrencySymbol 14 | , unsafeAsset1Name :: TokenName 15 | , unsafeAsset1Beacon :: TokenName 16 | , unsafeAsset2Id :: CurrencySymbol 17 | , unsafeAsset2Name :: TokenName 18 | , unsafeAsset2Beacon :: TokenName 19 | , unsafeAsset1Price :: (Integer,Integer) 20 | , unsafeAsset2Price :: (Integer,Integer) 21 | , unsafePrevInput :: Maybe TxOutRef 22 | } 23 | 24 | instance PlutusTx.ToData UnsafeDatum where 25 | toBuiltinData UnsafeDatum{..} = PlutusTx.dataToBuiltinData $ 26 | PlutusTx.Constr 0 27 | [ PlutusTx.toData unsafeBeaconId 28 | , PlutusTx.toData unsafePairBeacon 29 | , PlutusTx.toData unsafeAsset1Id 30 | , PlutusTx.toData unsafeAsset1Name 31 | , PlutusTx.toData unsafeAsset1Beacon 32 | , PlutusTx.toData unsafeAsset2Id 33 | , PlutusTx.toData unsafeAsset2Name 34 | , PlutusTx.toData unsafeAsset2Beacon 35 | , PlutusTx.toData unsafeAsset1Price 36 | , PlutusTx.toData unsafeAsset2Price 37 | , PlutusTx.toData unsafePrevInput 38 | ] 39 | -------------------------------------------------------------------------------- /scripts/local/mint-test-tokens/mint.sh: -------------------------------------------------------------------------------- 1 | alwaysSucceedSymbol="c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d" 2 | tokenName1=$(echo -n "TestToken1" | xxd -ps) 3 | tokenName2=$(echo -n "TestToken2" | xxd -ps) 4 | tokenName3=$(echo -n "TestToken3" | xxd -ps) 5 | tokenName4=$(echo -n "TestToken4" | xxd -ps) 6 | tmpDir="/tmp/cardano-swaps/" 7 | 8 | # Make the tmpDir if it doesn't already exist. 9 | mkdir -p $tmpDir 10 | 11 | cardano-cli conway transaction build \ 12 | --tx-in b9ede1a18cac5e771fcdcf9012f0005ee9f8baca7d4210a89d796646a52ee586#1 \ 13 | --tx-out "$(cat $HOME/wallets/01.addr) 2000000 lovelace + 1000 ${alwaysSucceedSymbol}.${tokenName1}" \ 14 | --mint "1000 ${alwaysSucceedSymbol}.${tokenName1} + 1000 ${alwaysSucceedSymbol}.${tokenName2} + 1000 ${alwaysSucceedSymbol}.${tokenName3} + 1000 ${alwaysSucceedSymbol}.${tokenName4}" \ 15 | --mint-script-file alwaysSucceedsMintingPolicy.plutus \ 16 | --mint-redeemer-file unit.json \ 17 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 18 | --change-address $(cat $HOME/wallets/01.addr) \ 19 | --testnet-magic 1 \ 20 | --out-file "${tmpDir}tx.body" 21 | 22 | cardano-cli conway transaction sign \ 23 | --tx-body-file "${tmpDir}tx.body" \ 24 | --signing-key-file $HOME/wallets/01.skey \ 25 | --testnet-magic 1 \ 26 | --out-file "${tmpDir}tx.signed" 27 | 28 | cardano-cli conway transaction submit \ 29 | --testnet-magic 1 \ 30 | --tx-file "${tmpDir}tx.signed" 31 | 32 | # Add a newline after the submission response. 33 | echo "" 34 | -------------------------------------------------------------------------------- /cabal.project: -------------------------------------------------------------------------------- 1 | -- Custom repository for cardano haskell packages, see CONTRIBUTING for more 2 | repository cardano-haskell-packages 3 | url: https://chap.intersectmbo.org/ 4 | secure: True 5 | root-keys: 6 | 3e0cce471cf09815f930210f7827266fd09045445d65923e6d0238a6cd15126f 7 | 443abb7fb497a134c343faf52f0b659bd7999bc06b7f63fa76dc99d631f9bea1 8 | a86a1f6ce86c449c46666bda44268677abf29b5b2d2eb5ec7af903ec2f117a82 9 | bcec67e8e99cabfa7764d75ad9b158d72bfacf70ca1d0ec8bc6b4406d1bf8413 10 | c00aae8461a256275598500ea0e187588c35a5d5d7454fb57eac18d9edb86a56 11 | d4a35cd3121aa00d18544bb0ac01c3e1691d618f462c46129271bccf39f7e8ee 12 | 13 | -- See CONTRIBUTING for some Nix commands you will need to run if you 14 | -- update either of these. 15 | index-state: 16 | -- Bump both the following dates if you need newer packages from Hackage 17 | , hackage.haskell.org 2024-01-08T22:38:30Z 18 | -- Bump this if you need newer packages from CHaP 19 | , cardano-haskell-packages 2024-01-16T10:58:01Z 20 | 21 | with-compiler: ghc-9.6.4 22 | 23 | packages: ./. 24 | 25 | tests: true 26 | 27 | package cardano-crypto-praos 28 | flags: -external-libsodium-vrf 29 | package plutus-script-utils 30 | haddock-options: "--optghc=-fplugin-opt PlutusTx.Plugin:defer-errors" 31 | package plutus-ledger 32 | haddock-options: "--optghc=-fplugin-opt PlutusTx.Plugin:defer-errors" 33 | 34 | test-show-details: direct 35 | 36 | source-repository-package 37 | type: git 38 | location: https://github.com/input-output-hk/cardano-addresses 39 | tag: b7273a5d3c21f1a003595ebf1e1f79c28cd72513 40 | subdir: 41 | core 42 | -------------------------------------------------------------------------------- /test/Test/TwoWaySwap/BeaconNames.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | module Test.TwoWaySwap.BeaconNames 4 | ( 5 | uniquenessTest1 6 | , uniquenessTest2 7 | 8 | , tests 9 | ) where 10 | 11 | import Test.Tasty 12 | import Test.Tasty.HUnit 13 | 14 | import CardanoSwaps.TwoWaySwap 15 | import CardanoSwaps.Utils 16 | 17 | import Test.Prelude (testTokenSymbol) 18 | 19 | testToken1 :: (CurrencySymbol,TokenName) 20 | testToken1 = (testTokenSymbol,"TestToken1") 21 | 22 | testToken2 :: (CurrencySymbol,TokenName) 23 | testToken2 = (testTokenSymbol,"TestToken2") 24 | 25 | -- | The reverse direction of a swap yields the same pair beacon name. 26 | uniquenessTest1 :: TestTree 27 | uniquenessTest1 = 28 | testCase "uniquenessTest1" $ assertBool "Fail TwoWaySwap.uniquenessTest1" $ 29 | genPairBeaconName testToken1 (adaSymbol,adaToken) == 30 | genPairBeaconName (adaSymbol,adaToken) testToken1 31 | 32 | -- | The asset beacons are different than the trading pair beacon. 33 | uniquenessTest2 :: TestTree 34 | uniquenessTest2 = 35 | testCase "uniquenessTest2" $ assertBool "Fail TwoWaySwap.uniquenessTest2" $ 36 | genPairBeaconName testToken1 (adaSymbol,adaToken) /= genAssetBeaconName testToken1 && 37 | genPairBeaconName testToken1 (adaSymbol,adaToken) /= genAssetBeaconName (adaSymbol,adaToken) && 38 | genPairBeaconName (adaSymbol,adaToken) testToken1 /= genAssetBeaconName testToken1 && 39 | genPairBeaconName (adaSymbol,adaToken) testToken1 /= genAssetBeaconName (adaSymbol,adaToken) 40 | 41 | tests :: TestTree 42 | tests = testGroup "Beacon Names" 43 | [ uniquenessTest1 44 | , uniquenessTest2 45 | ] 46 | -------------------------------------------------------------------------------- /scripts/local/one-way/create-reference-scripts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # The reference scripts may already be locked on-chain. Check the one-way swap address without a 4 | # staking credential. Both the spending script and the beacon script will be permanently locked in 5 | # this address. 6 | # 7 | # cardano-cli conway address build \ 8 | # --payment-script-file $swapScriptFile \ 9 | # --testnet-magic 1 \ 10 | # --out-file $swapAddrFile 11 | # 12 | # Preprod: addr_test1wqql5djxthlrdcnvy87m7uswf0d0es9cdw6nvl72gcqj74s38ksy4 13 | # Mainnet: addr1wyql5djxthlrdcnvy87m7uswf0d0es9cdw6nvl72gcqj74s20zvts 14 | 15 | # Variables 16 | tmpDir="/tmp/cardano-swaps/" 17 | 18 | # Make the tmpDir if it doesn't already exist. 19 | mkdir -p $tmpDir 20 | 21 | swapScriptFile="${tmpDir}oneWaySwap.plutus" 22 | beaconScriptFile="${tmpDir}oneWayBeacons.plutus" 23 | 24 | ## Export the swap script. 25 | echo "Exporting the swap script..." 26 | cardano-swaps scripts one-way swap-script \ 27 | --out-file $swapScriptFile 28 | 29 | ## Export the beacon script. 30 | echo "Exporting the beacon script..." 31 | cardano-swaps scripts one-way beacon-script \ 32 | --out-file $beaconScriptFile 33 | 34 | ## Create and submit the transaction. 35 | echo "Building the transaction..." 36 | cardano-cli conway transaction build \ 37 | --tx-in edadc501e0da8129a9b6168be85cf4bcafffb79ef5545633028531752949c106#0 \ 38 | --tx-in edadc501e0da8129a9b6168be85cf4bcafffb79ef5545633028531752949c106#1 \ 39 | --tx-in d4fbd706c39717ff0391fcb8dec5c643e9156bae98bb2a07cbf60948b05c28db#1 \ 40 | --tx-out "$(cat $HOME/wallets/01.addr) + 22000000 lovelace " \ 41 | --tx-out-reference-script-file $swapScriptFile \ 42 | --tx-out "$(cat $HOME/wallets/01.addr) + 20000000 lovelace " \ 43 | --tx-out-reference-script-file $beaconScriptFile \ 44 | --change-address "$(cat $HOME/wallets/01.addr)" \ 45 | --testnet-magic 1 \ 46 | --out-file "${tmpDir}tx.body" 47 | 48 | echo "Signing the transaction..." 49 | cardano-cli conway transaction sign \ 50 | --tx-body-file "${tmpDir}tx.body" \ 51 | --signing-key-file $HOME/wallets/01.skey \ 52 | --testnet-magic 1 \ 53 | --out-file "${tmpDir}tx.signed" 54 | 55 | echo "Submitting the transaction..." 56 | cardano-cli conway transaction submit \ 57 | --testnet-magic 1 \ 58 | --tx-file "${tmpDir}tx.signed" 59 | 60 | # Add a newline after the submission response. 61 | echo "" 62 | -------------------------------------------------------------------------------- /scripts/local/two-way/create-reference-scripts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # The reference scripts may already be locked on-chain. Check the two-way swap address without a 4 | # staking credential. Both the spending script and the beacon script will be permanently locked in 5 | # this address. 6 | # 7 | # cardano-cli conway address build \ 8 | # --payment-script-file $swapScriptFile \ 9 | # --testnet-magic 1 \ 10 | # --out-file $swapAddrFile 11 | # 12 | # Preprod: addr_test1wzrns8ct7stw9kh8f97nlnvqsl8kw7eukje2aw3kak8c77g25nluj 13 | # Mainnet: addr1wxrns8ct7stw9kh8f97nlnvqsl8kw7eukje2aw3kak8c77g3u8rnh 14 | 15 | # Variables 16 | tmpDir="/tmp/cardano-swaps/" 17 | 18 | # Make the tmpDir if it doesn't already exist. 19 | mkdir -p $tmpDir 20 | 21 | swapScriptFile="${tmpDir}twoWaySwap.plutus" 22 | beaconScriptFile="${tmpDir}twoWayBeacons.plutus" 23 | 24 | ## Export the swap validator script. 25 | echo "Exporting the swap validator script..." 26 | cardano-swaps scripts two-way swap-script \ 27 | --out-file $swapScriptFile 28 | 29 | ## Export the beacon script. 30 | echo "Exporting the beacon script..." 31 | cardano-swaps scripts two-way beacon-script \ 32 | --out-file $beaconScriptFile 33 | 34 | ## Create and submit the transaction. 35 | echo "Building the transaction..." 36 | cardano-cli conway transaction build \ 37 | --tx-in 892c8e0c1037403c4a92f6abc991a8e21e0d97e9af68d3a36d8aabe7067ac67a#0 \ 38 | --tx-in 892c8e0c1037403c4a92f6abc991a8e21e0d97e9af68d3a36d8aabe7067ac67a#1 \ 39 | --tx-in 9ab26f84b2bab49473216b774b873cf4c6fdeabc8b5780d4d7c4409e522727ff#0 \ 40 | --tx-out "$(cat $HOME/wallets/01.addr) + 24000000 lovelace " \ 41 | --tx-out-reference-script-file $swapScriptFile \ 42 | --tx-out "$(cat $HOME/wallets/01.addr) + 22000000 lovelace " \ 43 | --tx-out-reference-script-file $beaconScriptFile \ 44 | --change-address "$(cat $HOME/wallets/01.addr)" \ 45 | --testnet-magic 1 \ 46 | --out-file "${tmpDir}tx.body" 47 | 48 | echo "Signing the transaction..." 49 | cardano-cli conway transaction sign \ 50 | --tx-body-file "${tmpDir}tx.body" \ 51 | --signing-key-file $HOME/wallets/01.skey \ 52 | --testnet-magic 1 \ 53 | --out-file "${tmpDir}tx.signed" 54 | 55 | echo "Submitting the transaction..." 56 | cardano-cli conway transaction submit \ 57 | --testnet-magic 1 \ 58 | --tx-file "${tmpDir}tx.signed" 59 | 60 | # Add a newline after the submission response. 61 | echo "" 62 | -------------------------------------------------------------------------------- /scripts/local/one-way/register-beacon-script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # WARNING 4 | # It is no longer possible to register the beacon scripts as written since they do not allow 5 | # certificate executions. Prior to the conway error, scripts did not need to be executed to register 6 | # them. Now, they do. The beacon scripts for the current cardano-swaps version were registered prior 7 | # to the conway era. They cannot be de-registered. 8 | # 9 | # This template script is for explanatory purposes only based off the new conway era rules. 10 | 11 | # Variables 12 | tmpDir="/tmp/cardano-swaps/" 13 | 14 | # Make the tmpDir if it doesn't already exist. 15 | mkdir -p $tmpDir 16 | 17 | beaconScriptFile="${tmpDir}oneWayBeacons.plutus" 18 | beaconRedeemer="${tmpDir}registerOneWayBeacons.plutus" 19 | 20 | # The reference scripts are permanently locked in the swap address without a staking credential! 21 | # You can use the `cardano-swaps query personal-address` command to see them. 22 | beaconScriptPreprodTestnetRef="9fecc1d2cf99088facad02aeccbedb6a4f783965dc6c02bd04dc8b348e9a0858#1" 23 | # beaconScriptSize=4432 24 | 25 | # Export the beacon script. 26 | echo "Exporting the beacon script..." 27 | cardano-swaps scripts one-way beacon-script \ 28 | --out-file $beaconScriptFile 29 | 30 | # Create the registration certificate 31 | cardano-cli conway stake-address registration-certificate \ 32 | --stake-script-file $beaconScriptFile \ 33 | --key-reg-deposit-amt 2000000 \ 34 | --out-file "${tmpDir}registration.cert" 35 | 36 | # Create the transaction. 37 | cardano-cli conway transaction build \ 38 | --tx-in 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#1 \ 39 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 40 | --change-address "$(cat $HOME/wallets/01.addr)" \ 41 | --certificate-file "${tmpDir}registration.cert" \ 42 | --certificate-tx-in-reference $beaconScriptPreprodTestnetRef \ 43 | --certificate-plutus-script-v2 \ 44 | --certificate-reference-tx-in-redeemer-file $beaconRedeemer \ 45 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 46 | --testnet-magic 1 \ 47 | --out-file "${tmpDir}tx.body" 48 | 49 | cardano-cli conway transaction sign \ 50 | --tx-body-file "${tmpDir}tx.body" \ 51 | --signing-key-file $HOME/wallets/01.skey \ 52 | --testnet-magic 1 \ 53 | --out-file "${tmpDir}tx.signed" 54 | 55 | cardano-cli conway transaction submit \ 56 | --testnet-magic 1 \ 57 | --tx-file "${tmpDir}tx.signed" 58 | 59 | # Add a newline after the submission response. 60 | echo "" 61 | -------------------------------------------------------------------------------- /scripts/local/two-way/register-beacon-script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # WARNING 4 | # It is no longer possible to register the beacon scripts as written since they do not allow 5 | # certificate executions. Prior to the conway error, scripts did not need to be executed to register 6 | # them. Now, they do. The beacon scripts for the current cardano-swaps version were registered prior 7 | # to the conway era. They cannot be de-registered. 8 | # 9 | # This template script is for explanatory purposes only based off the new conway era rules. 10 | 11 | # Variables 12 | tmpDir="/tmp/cardano-swaps/" 13 | 14 | # Make the tmpDir if it doesn't already exist. 15 | mkdir -p $tmpDir 16 | 17 | beaconScriptFile="${tmpDir}twoWayBeacons.plutus" 18 | beaconRedeemer="${tmpDir}registerTwoWayBeacons.plutus" 19 | 20 | # The reference scripts are permanently locked in the swap address without a staking credential! 21 | # You can use the `cardano-swaps query personal-address` command to see them. 22 | beaconScriptPreprodTestnetRef="115c9ebb9928b8ec6e0c9d1420c43421cfb323639dd9fdcf1e7155e73bec13c5#1" 23 | # beaconScriptSize=4707 24 | 25 | # Export the beacon script. 26 | echo "Exporting the beacon script..." 27 | cardano-swaps scripts two-way beacon-script \ 28 | --out-file $beaconScriptFile 29 | 30 | # Create the registration certificate 31 | cardano-cli conway stake-address registration-certificate \ 32 | --stake-script-file $beaconScriptFile \ 33 | --key-reg-deposit-amt 2000000 \ 34 | --out-file "${tmpDir}registration.cert" 35 | 36 | # Create the transaction. 37 | cardano-cli conway transaction build \ 38 | --tx-in aec62de69f36fc9860d0d4bcf2ff8836dd32e5d27a43169b2df35efc4a16b263#1 \ 39 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 40 | --change-address "$(cat $HOME/wallets/01.addr)" \ 41 | --certificate-file "${tmpDir}registration.cert" \ 42 | --certificate-tx-in-reference $beaconScriptPreprodTestnetRef \ 43 | --certificate-plutus-script-v2 \ 44 | --certificate-reference-tx-in-redeemer-file $beaconRedeemer \ 45 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 46 | --testnet-magic 1 \ 47 | --out-file "${tmpDir}tx.body" 48 | 49 | cardano-cli conway transaction sign \ 50 | --tx-body-file "${tmpDir}tx.body" \ 51 | --signing-key-file $HOME/wallets/01.skey \ 52 | --testnet-magic 1 \ 53 | --out-file "${tmpDir}tx.signed" 54 | 55 | cardano-cli conway transaction submit \ 56 | --testnet-magic 1 \ 57 | --tx-file "${tmpDir}tx.signed" 58 | 59 | # Add a newline after the submission response. 60 | echo "" 61 | -------------------------------------------------------------------------------- /aiken/lib/cardano_swaps/common/utils.ak: -------------------------------------------------------------------------------- 1 | use aiken/bytearray 2 | use aiken/dict.{Dict} 3 | use aiken/hash.{Hash,Blake2b_224} 4 | use aiken/list 5 | use aiken/transaction/credential.{ 6 | Address, 7 | Inline, 8 | StakeCredential, 9 | ScriptCredential, 10 | VerificationKey, 11 | VerificationKeyCredential 12 | } 13 | use aiken/transaction/value.{PolicyId,MintedValue} 14 | 15 | use cardano_swaps/common/types.{AssetConfig} 16 | 17 | pub fn trace_if_false(msg: String, predicate: Bool) { 18 | if !predicate { 19 | trace msg 20 | predicate 21 | } else { 22 | predicate 23 | } 24 | } 25 | 26 | pub fn error_if_false(msg: String, predicate: Bool) { 27 | if !predicate { 28 | error msg 29 | } else { 30 | predicate 31 | } 32 | } 33 | 34 | // Check that either the staking pubkey signed or the staking script was executed. 35 | pub fn staking_credential_approves( 36 | swap_addr: Address, 37 | withdrawals: Dict, 38 | extra_signatories: List> 39 | ) -> Bool { 40 | let Address(_,staking_cred) = swap_addr 41 | when staking_cred is { 42 | // This is to prevent permanent locking of funds. Beacons can never be minted to an address 43 | // without a valid staking credential. 44 | None -> True 45 | 46 | // If the address uses a staking pubkey, it must have signed the tx. 47 | Some(Inline(VerificationKeyCredential(skey))) -> { 48 | list.has(extra_signatories,skey) 49 | } 50 | 51 | // If the address uses a staking script, it must have been executed in the tx. In order for 52 | // the staking credential to show up in this dictionary, it must be registered. 53 | Some(svh) -> { 54 | dict.has_key(withdrawals,svh) 55 | } 56 | } 57 | } 58 | 59 | pub fn compare_asset_config(asset1: AssetConfig, asset2: AssetConfig) -> Ordering { 60 | let AssetConfig(asset1_id,asset1_name) = asset1 61 | let AssetConfig(asset2_id,asset2_name) = asset2 62 | when bytearray.compare(asset1_id,asset2_id) is { 63 | Less -> Less 64 | Greater -> Greater 65 | Equal -> bytearray.compare(asset1_name,asset2_name) 66 | } 67 | } 68 | 69 | pub fn has_beacon_script_minting_execution( 70 | beacon_id: PolicyId, 71 | mint: MintedValue 72 | ) -> Bool { 73 | !(value.from_minted_value(mint) |> value.tokens(_,beacon_id) |> dict.is_empty(_)) 74 | } 75 | 76 | pub fn has_beacon_script_staking_execution( 77 | beacon_id: PolicyId, 78 | withdrawals: Dict, 79 | ) -> Bool { 80 | dict.has_key( 81 | withdrawals, 82 | Inline(ScriptCredential(beacon_id)) 83 | ) 84 | } 85 | -------------------------------------------------------------------------------- /cardano-swaps.cabal: -------------------------------------------------------------------------------- 1 | cabal-version: 3.0 2 | name: cardano-swaps 3 | version: 1.0.0.0 4 | 5 | synopsis: A distributed Cardano DEX PoC 6 | license: Apache-2.0 7 | author: fallen-icarus 8 | maintainer: modern.daidalos+git@gmail.com 9 | copyright: 2022 fallen-icarus 10 | extra-source-files: 11 | CHANGELOG.md, 12 | aiken/plutus.json, 13 | preprod-params.json, 14 | mainnet-params.json 15 | 16 | common lang 17 | build-depends: base 18 | default-language: Haskell2010 19 | ghc-options: -Wall -Wredundant-constraints 20 | default-extensions: 21 | DeriveGeneric 22 | FlexibleContexts 23 | NamedFieldPuns 24 | NumericUnderscores 25 | TupleSections 26 | TypeApplications 27 | 28 | common internals 29 | build-depends: 30 | cardano-api 31 | , plutus-ledger 32 | , plutus-ledger-api 33 | , plutus-tx 34 | , plutus-core 35 | , plutus-script-utils 36 | , containers 37 | , aeson 38 | , text 39 | , bytestring 40 | , prettyprinter 41 | 42 | library 43 | import: 44 | lang 45 | , internals 46 | exposed-modules: 47 | CardanoSwaps.Blueprints 48 | , CardanoSwaps.OneWaySwap 49 | , CardanoSwaps.TwoWaySwap 50 | , CardanoSwaps.Utils 51 | build-depends: 52 | serialise 53 | , file-embed 54 | , base16-bytestring 55 | , relude 56 | , microlens 57 | hs-source-dirs: src 58 | 59 | test-suite cardano-swaps-tests 60 | import: 61 | lang, 62 | internals 63 | type: exitcode-stdio-1.0 64 | main-is: Test.hs 65 | hs-source-dirs: test 66 | ghc-options: 67 | -threaded -rtsopts -with-rtsopts=-N 68 | -Wno-unused-matches -Wno-unused-local-binds 69 | -Wno-unused-top-binds 70 | other-modules: 71 | Test.Prelude 72 | , Test.OneWaySwap 73 | , Test.OneWaySwap.BeaconNames 74 | , Test.OneWaySwap.CloseSwap 75 | , Test.OneWaySwap.CreateSwap 76 | , Test.OneWaySwap.Swap 77 | , Test.OneWaySwap.UpdateSwap 78 | , Test.OneWaySwap.UnsafeDatum 79 | , Test.TwoWaySwap 80 | , Test.TwoWaySwap.BeaconNames 81 | , Test.TwoWaySwap.CloseSwap 82 | , Test.TwoWaySwap.CreateSwap 83 | , Test.TwoWaySwap.Swap 84 | , Test.TwoWaySwap.UpdateSwap 85 | , Test.TwoWaySwap.UnsafeDatum 86 | build-depends: 87 | cardano-swaps 88 | , data-default 89 | , tasty 90 | , tasty-hunit 91 | , microlens 92 | , mtl 93 | , cardano-node-emulator 94 | 95 | executable cardano-swaps 96 | import: 97 | lang, 98 | internals 99 | main-is: Main.hs 100 | other-modules: 101 | CLI.Types 102 | , CLI.Run 103 | , CLI.Query 104 | , CLI.Parsers 105 | , CLI.Query.Koios 106 | build-depends: 107 | cardano-swaps, 108 | optparse-applicative, 109 | servant, 110 | servant-client, 111 | http-client, 112 | http-client-tls, 113 | vector, 114 | aeson-pretty, 115 | file-embed, 116 | prettyprinter-ansi-terminal 117 | hs-source-dirs: app 118 | default-extensions: 119 | OverloadedStrings 120 | RecordWildCards 121 | -------------------------------------------------------------------------------- /scripts/local/one-way/swap-assets.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Variables 4 | tmpDir="/tmp/cardano-swaps/" 5 | 6 | # Make the tmpDir if it doesn't already exist. 7 | mkdir -p $tmpDir 8 | 9 | swapAddr1="addr_test1zqql5djxthlrdcnvy87m7uswf0d0es9cdw6nvl72gcqj743ualkqngnmdz2w9mv60zuucq0sswtn6lq2lwxwez76x0aqv7yg2s" 10 | swapDatumFile1="${tmpDir}swapDatum1.json" 11 | swapRedeemerFile="${tmpDir}oneWaySpendingRedeemer.json" 12 | 13 | # The reference scripts are permanently locked in the swap address without a staking credential! 14 | # You can use the `cardano-swaps query personal-address` command to see them. 15 | spendingScriptPreprodTestnetRef="9fecc1d2cf99088facad02aeccbedb6a4f783965dc6c02bd04dc8b348e9a0858#0" 16 | # spendingScriptSize=4842 17 | 18 | # Create the spending redeemer. 19 | echo "Creating the spending redeemer..." 20 | cardano-swaps spending-redeemers one-way \ 21 | --swap \ 22 | --out-file $swapRedeemerFile 23 | 24 | # Create the new swap datum. 25 | echo "Creating the new swap datum..." 26 | cardano-swaps datums one-way \ 27 | --ask-asset lovelace \ 28 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31 \ 29 | --offer-price 1000000 \ 30 | --input-swap-ref 8f224fb4d358bfc9c05b1784d412c2b9161d66a2246734a400a52578ceef26f5#0 \ 31 | --out-file $swapDatumFile1 32 | 33 | # Helper beacon variables. 34 | echo "Calculating the beacon names..." 35 | beaconPolicyId1=$(cardano-swaps beacon-info one-way policy-id \ 36 | --stdout) 37 | 38 | pairBeaconName1=$(cardano-swaps beacon-info one-way pair-beacon \ 39 | --ask-asset lovelace \ 40 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31 \ 41 | --stdout) 42 | 43 | offerBeaconName1=$(cardano-swaps beacon-info one-way offer-beacon \ 44 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31 \ 45 | --stdout) 46 | 47 | askBeaconName1=$(cardano-swaps beacon-info one-way ask-beacon \ 48 | --ask-asset lovelace \ 49 | --stdout) 50 | 51 | pairBeacon1="${beaconPolicyId1}.${pairBeaconName1}" 52 | offerBeacon1="${beaconPolicyId1}.${offerBeaconName1}" 53 | askBeacon1="${beaconPolicyId1}.${askBeaconName1}" 54 | 55 | # Create the transaction. 56 | cardano-cli conway transaction build \ 57 | --tx-in 67b735bc6f14e5639ad49ad226a052281cf96616ba9b1dfc498e75e6ecca09d1#0 \ 58 | --tx-in 8f224fb4d358bfc9c05b1784d412c2b9161d66a2246734a400a52578ceef26f5#0 \ 59 | --spending-tx-in-reference $spendingScriptPreprodTestnetRef \ 60 | --spending-plutus-script-v2 \ 61 | --spending-reference-tx-in-inline-datum-present \ 62 | --spending-reference-tx-in-redeemer-file $swapRedeemerFile \ 63 | --tx-out "${swapAddr1} + 5000000 lovelace + 1 ${pairBeacon1} + 1 ${offerBeacon1} + 1 ${askBeacon1} + 8 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31" \ 64 | --tx-out-inline-datum-file $swapDatumFile1 \ 65 | --tx-in-collateral 11ed603b92e6164c6bb0c83e0f4d54a954976db7c39e2a82d3cbf70f098da1e0#0 \ 66 | --change-address "$(cat $HOME/wallets/02.addr)" \ 67 | --testnet-magic 1 \ 68 | --out-file "${tmpDir}tx.body" 69 | 70 | cardano-cli conway transaction sign \ 71 | --tx-body-file "${tmpDir}tx.body" \ 72 | --signing-key-file $HOME/wallets/02.skey \ 73 | --testnet-magic 1 \ 74 | --out-file "${tmpDir}tx.signed" 75 | 76 | cardano-cli conway transaction submit \ 77 | --testnet-magic 1 \ 78 | --tx-file "${tmpDir}tx.signed" 79 | 80 | # Add a newline after the submission response. 81 | echo "" 82 | -------------------------------------------------------------------------------- /scripts/remote/two-way/create-reference-scripts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # The reference scripts may already be locked on-chain. Check the two-way swap address without a 4 | # staking credential. Both the spending script and the beacon script will be permanently locked in 5 | # this address. 6 | # 7 | # cardano-cli conway address build \ 8 | # --payment-script-file $swapScriptFile \ 9 | # --testnet-magic 1 \ 10 | # --out-file $swapAddrFile 11 | # 12 | # Preprod: addr_test1wzrns8ct7stw9kh8f97nlnvqsl8kw7eukje2aw3kak8c77g25nluj 13 | # Mainnet: addr1wxrns8ct7stw9kh8f97nlnvqsl8kw7eukje2aw3kak8c77g3u8rnh 14 | 15 | # Variables 16 | tmpDir="/tmp/cardano-swaps/" 17 | 18 | # Make the tmpDir if it doesn't already exist. 19 | mkdir -p $tmpDir 20 | 21 | swapScriptFile="${tmpDir}twoWaySwap.plutus" 22 | beaconPolicyFile="${tmpDir}twoWayBeacon.plutus" 23 | 24 | ## Export the swap validator script. 25 | echo "Exporting the swap validator script..." 26 | cardano-swaps scripts two-way swap-script \ 27 | --out-file $swapScriptFile 28 | 29 | ## Export the beacon script. 30 | echo "Exporting the beacon script..." 31 | cardano-swaps scripts two-way beacon-script \ 32 | --out-file $beaconPolicyFile 33 | 34 | ## Create and submit the transaction. 35 | echo "Exporting the current protocol parameters..." 36 | cardano-swaps query protocol-params \ 37 | --testnet \ 38 | --out-file "${tmpDir}protocol.json" 39 | 40 | initial_change=$((8180352038)) 41 | 42 | echo "Building the initial transaction..." 43 | cardano-cli conway build-raw \ 44 | --tx-in 38fd18f4ca7c6587eb2703ac3bfd42e1406d089901e2c29f158358fdda5b196a#0 \ 45 | --tx-in 38fd18f4ca7c6587eb2703ac3bfd42e1406d089901e2c29f158358fdda5b196a#1 \ 46 | --tx-in 44f58115ad9738de64bb5624b495a2e7abddfdbe055df474d7d980af1244d64e#1 \ 47 | --tx-out "$(cat $HOME/wallets/01.addr) + 24000000 lovelace " \ 48 | --tx-out-reference-script-file $swapScriptFile \ 49 | --tx-out "$(cat $HOME/wallets/01.addr) + 22000000 lovelace " \ 50 | --tx-out-reference-script-file $beaconPolicyFile \ 51 | --tx-out "$(cat $HOME/wallets/01.addr) + ${initial_change} lovelace " \ 52 | --fee 5000000 \ 53 | --out-file "${tmpDir}tx.body" 54 | 55 | echo "Calculating the required fee..." 56 | req_fee=$(cardano-cli conway transaction calculate-min-fee \ 57 | --tx-body-file "${tmpDir}tx.body" \ 58 | --protocol-params-file "${tmpDir}protocol.json" \ 59 | --witness-count 1 | cut -d' ' -f1) 60 | 61 | echo "Rebuilding the transaction with the required fee..." 62 | cardano-cli conway build-raw \ 63 | --tx-in 38fd18f4ca7c6587eb2703ac3bfd42e1406d089901e2c29f158358fdda5b196a#0 \ 64 | --tx-in 38fd18f4ca7c6587eb2703ac3bfd42e1406d089901e2c29f158358fdda5b196a#1 \ 65 | --tx-in 44f58115ad9738de64bb5624b495a2e7abddfdbe055df474d7d980af1244d64e#1 \ 66 | --tx-out "$(cat $HOME/wallets/01.addr) + 24000000 lovelace " \ 67 | --tx-out-reference-script-file $swapScriptFile \ 68 | --tx-out "$(cat $HOME/wallets/01.addr) + 22000000 lovelace " \ 69 | --tx-out-reference-script-file $beaconPolicyFile \ 70 | --tx-out "$(cat $HOME/wallets/01.addr) + $((initial_change-req_fee)) lovelace " \ 71 | --fee "$req_fee" \ 72 | --out-file "${tmpDir}tx.body" 73 | 74 | echo "Signing the transaction..." 75 | cardano-cli conway transaction sign \ 76 | --tx-body-file "${tmpDir}tx.body" \ 77 | --signing-key-file $HOME/wallets/01.skey \ 78 | --testnet-magic 1 \ 79 | --out-file "${tmpDir}tx.signed" 80 | 81 | echo "Submitting the transaction..." 82 | cardano-swaps submit \ 83 | --testnet \ 84 | --tx-file "${tmpDir}tx.signed" 85 | 86 | # Add a newline after the submission response. 87 | echo "" 88 | -------------------------------------------------------------------------------- /scripts/remote/one-way/create-reference-scripts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # The reference scripts may already be locked on-chain. Check the one-way swap address without a 4 | # staking credential. Both the spending script and the beacon script will be permanently locked in 5 | # this address. 6 | # 7 | # cardano-cli conway address build \ 8 | # --payment-script-file $swapScriptFile \ 9 | # --testnet-magic 1 \ 10 | # --out-file $swapAddrFile 11 | # 12 | # Preprod: addr_test1wqql5djxthlrdcnvy87m7uswf0d0es9cdw6nvl72gcqj74s38ksy4 13 | # Mainnet: addr1wyql5djxthlrdcnvy87m7uswf0d0es9cdw6nvl72gcqj74s20zvts 14 | 15 | # Variables 16 | tmpDir="/tmp/cardano-swaps/" 17 | 18 | # Make the tmpDir if it doesn't already exist. 19 | mkdir -p $tmpDir 20 | 21 | swapScriptFile="${tmpDir}oneWaySwap.plutus" 22 | beaconPolicyFile="${tmpDir}oneWayBeacons.plutus" 23 | 24 | ## Export the swap validator script. 25 | echo "Exporting the swap validator script..." 26 | cardano-swaps scripts one-way swap-script \ 27 | --out-file $swapScriptFile 28 | 29 | ## Export the beacon script. 30 | echo "Exporting the beacon script..." 31 | cardano-swaps scripts one-way beacon-script \ 32 | --out-file $beaconPolicyFile 33 | 34 | ## Create and submit the transaction. 35 | echo "Exporting the current protocol parameters..." 36 | cardano-swaps query protocol-params \ 37 | --testnet \ 38 | --out-file "${tmpDir}protocol.json" 39 | 40 | initial_change=8181764766 41 | 42 | echo "Building the initial transaction..." 43 | cardano-cli conway transaction build-raw \ 44 | --tx-in 8f224fb4d358bfc9c05b1784d412c2b9161d66a2246734a400a52578ceef26f5#2 \ 45 | --tx-in 8762f07fef0c5137ee7d6d8bce962f29554f1ddff3883f1b2d2fc39f213df94c#0 \ 46 | --tx-in 8762f07fef0c5137ee7d6d8bce962f29554f1ddff3883f1b2d2fc39f213df94c#1 \ 47 | --tx-out "$(cat $HOME/wallets/01.addr) + 22000000 lovelace" \ 48 | --tx-out-reference-script-file $swapScriptFile \ 49 | --tx-out "$(cat $HOME/wallets/01.addr) + 20000000 lovelace" \ 50 | --tx-out-reference-script-file $beaconPolicyFile \ 51 | --tx-out "$(cat $HOME/wallets/01.addr) + ${initial_change} lovelace" \ 52 | --fee 5000000 \ 53 | --out-file "${tmpDir}tx.body" 54 | 55 | echo "Calculating the required fee..." 56 | req_fee=$(cardano-cli conway transaction calculate-min-fee \ 57 | --tx-body-file "${tmpDir}tx.body" \ 58 | --protocol-params-file "${tmpDir}protocol.json" \ 59 | --witness-count 1 | cut -d' ' -f1) 60 | 61 | echo "Rebuilding the transaction with the required fee..." 62 | cardano-cli conway transaction build-raw \ 63 | --tx-in 8f224fb4d358bfc9c05b1784d412c2b9161d66a2246734a400a52578ceef26f5#2 \ 64 | --tx-in 8762f07fef0c5137ee7d6d8bce962f29554f1ddff3883f1b2d2fc39f213df94c#0 \ 65 | --tx-in 8762f07fef0c5137ee7d6d8bce962f29554f1ddff3883f1b2d2fc39f213df94c#1 \ 66 | --tx-out "$(cat $HOME/wallets/01.addr) + 22000000 lovelace" \ 67 | --tx-out-reference-script-file $swapScriptFile \ 68 | --tx-out "$(cat $HOME/wallets/01.addr) + 20000000 lovelace" \ 69 | --tx-out-reference-script-file $beaconPolicyFile \ 70 | --tx-out "$(cat $HOME/wallets/01.addr) + $((initial_change-req_fee)) lovelace " \ 71 | --fee "$req_fee" \ 72 | --out-file "${tmpDir}tx.body" 73 | 74 | echo "Signing the transaction..." 75 | cardano-cli conway transaction sign \ 76 | --tx-body-file "${tmpDir}tx.body" \ 77 | --signing-key-file $HOME/wallets/01.skey \ 78 | --testnet-magic 1 \ 79 | --out-file "${tmpDir}tx.signed" 80 | 81 | echo "Submitting the transaction..." 82 | cardano-swaps submit \ 83 | --testnet \ 84 | --tx-file "${tmpDir}tx.signed" 85 | 86 | # Add a newline after the submission response. 87 | echo "" 88 | -------------------------------------------------------------------------------- /scripts/local/two-way/swap-assets.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Variables 4 | tmpDir="/tmp/cardano-swaps/" 5 | 6 | # Make the tmpDir if it doesn't already exist. 7 | mkdir -p $tmpDir 8 | 9 | swapAddr1="addr_test1zzrns8ct7stw9kh8f97nlnvqsl8kw7eukje2aw3kak8c77fualkqngnmdz2w9mv60zuucq0sswtn6lq2lwxwez76x0aq3y05nq" 10 | swapDatumFile1="${tmpDir}swapDatum1.json" 11 | swapRedeemerFile="${tmpDir}oneWaySpendingRedeemer.json" 12 | 13 | # The reference scripts are permanently locked in the swap address without a staking credential! 14 | # You can use the `cardano-swaps query personal-address` command to see them. 15 | spendingScriptPreprodTestnetRef="115c9ebb9928b8ec6e0c9d1420c43421cfb323639dd9fdcf1e7155e73bec13c5#0" 16 | # spendingScriptSize=5343 17 | 18 | # Create the Swap redeemer. 19 | echo "Creating the spending redeemer..." 20 | cardano-swaps spending-redeemers two-way \ 21 | --ask-asset lovelace \ 22 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 23 | --out-file $swapRedeemerFile 24 | 25 | # Create the swap datum. 26 | echo "Creating the swap datum..." 27 | cardano-swaps datums two-way \ 28 | --first-asset lovelace \ 29 | --second-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 30 | --first-price '1 / 1000000' \ 31 | --second-price 1000000 \ 32 | --input-swap-ref f6538bb7a6a0365f3c295aed389df29e752df504ebe691e34f45c0ab9f96272c#0 \ 33 | --out-file $swapDatumFile1 34 | 35 | # Helper beacon variables. 36 | echo "Calculating the beacon names..." 37 | beaconPolicyId1=$(cardano-swaps beacon-info two-way policy-id \ 38 | --stdout) 39 | 40 | pairBeaconName1=$(cardano-swaps beacon-info two-way pair-beacon \ 41 | --first-asset lovelace \ 42 | --second-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 43 | --stdout) 44 | 45 | asset1BeaconName1=$(cardano-swaps beacon-info two-way asset-beacon \ 46 | --first-asset lovelace \ 47 | --stdout) 48 | 49 | asset2BeaconName1=$(cardano-swaps beacon-info two-way asset-beacon \ 50 | --second-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 51 | --stdout) 52 | 53 | pairBeacon1="${beaconPolicyId1}.${pairBeaconName1}" 54 | asset1Beacon1="${beaconPolicyId1}.${asset1BeaconName1}" 55 | asset2Beacon1="${beaconPolicyId1}.${asset2BeaconName1}" 56 | 57 | # Create the transaction. 58 | cardano-cli conway transaction build \ 59 | --tx-in 8064545d5c06fcd051eedf4f2d5a2e6efdc08b376720f21b1b3457d48bb536e1#2 \ 60 | --tx-in f6538bb7a6a0365f3c295aed389df29e752df504ebe691e34f45c0ab9f96272c#0 \ 61 | --spending-tx-in-reference $spendingScriptPreprodTestnetRef \ 62 | --spending-plutus-script-v2 \ 63 | --spending-reference-tx-in-inline-datum-present \ 64 | --spending-reference-tx-in-redeemer-file $swapRedeemerFile \ 65 | --tx-out "${swapAddr1} + 13000000 lovelace + 1 ${pairBeacon1} + 1 ${asset1Beacon1} + 1 ${asset2Beacon1} + 10 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a" \ 66 | --tx-out-inline-datum-file $swapDatumFile1 \ 67 | --tx-in-collateral 11ed603b92e6164c6bb0c83e0f4d54a954976db7c39e2a82d3cbf70f098da1e0#0 \ 68 | --change-address "$(cat $HOME/wallets/02.addr)" \ 69 | --testnet-magic 1 \ 70 | --out-file "${tmpDir}tx.body" 71 | 72 | cardano-cli conway transaction sign \ 73 | --tx-body-file "${tmpDir}tx.body" \ 74 | --signing-key-file $HOME/wallets/02.skey \ 75 | --testnet-magic 1 \ 76 | --out-file "${tmpDir}tx.signed" 77 | 78 | cardano-cli conway transaction submit \ 79 | --testnet-magic 1 \ 80 | --tx-file "${tmpDir}tx.signed" 81 | 82 | # Add a newline after the submission response. 83 | echo "" 84 | -------------------------------------------------------------------------------- /scripts/local/one-way/close-swap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Variables 4 | tmpDir="/tmp/cardano-swaps/" 5 | 6 | # Make the tmpDir if it doesn't already exist. 7 | mkdir -p $tmpDir 8 | 9 | ownerPubKeyFile="$HOME/wallets/01Stake.vkey" 10 | swapRedeemerFile="${tmpDir}oneWaySpendingRedeemer.json" 11 | beaconRedeemerFile="${tmpDir}oneWayBeaconRedeemer.json" 12 | 13 | # The reference scripts are permanently locked in the swap address without a staking credential! 14 | # You can use the `cardano-swaps query personal-address` command to see them. 15 | beaconScriptPreprodTestnetRef="9fecc1d2cf99088facad02aeccbedb6a4f783965dc6c02bd04dc8b348e9a0858#1" 16 | # beaconScriptSize=4432 17 | 18 | spendingScriptPreprodTestnetRef="9fecc1d2cf99088facad02aeccbedb6a4f783965dc6c02bd04dc8b348e9a0858#0" 19 | # spendingScriptSize=4842 20 | 21 | # Generate the hash for the staking verification key. 22 | echo "Calculating the staking pubkey hash for the borrower..." 23 | ownerPubKeyHash=$(cardano-cli conway stake-address key-hash \ 24 | --stake-verification-key-file $ownerPubKeyFile) 25 | 26 | # Create the spending redeemer. 27 | echo "Creating the spending redeemer..." 28 | cardano-swaps spending-redeemers one-way \ 29 | --close \ 30 | --out-file $swapRedeemerFile 31 | 32 | # Helper beacon variables. 33 | echo "Calculating the beacon names..." 34 | beaconPolicyId=$(cardano-swaps beacon-info one-way policy-id \ 35 | --stdout) 36 | 37 | pairBeaconName=$(cardano-swaps beacon-info one-way pair-beacon \ 38 | --ask-asset lovelace \ 39 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31 \ 40 | --stdout) 41 | 42 | offerBeaconName=$(cardano-swaps beacon-info one-way offer-beacon \ 43 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31 \ 44 | --stdout) 45 | 46 | askBeaconName=$(cardano-swaps beacon-info one-way ask-beacon \ 47 | --ask-asset lovelace \ 48 | --stdout) 49 | 50 | pairBeacon="${beaconPolicyId}.${pairBeaconName}" 51 | offerBeacon="${beaconPolicyId}.${offerBeaconName}" 52 | askBeacon="${beaconPolicyId}.${askBeaconName}" 53 | 54 | # Creating the beacon script redeemer. 55 | echo "Creating the beacon script redeemer..." 56 | cardano-swaps beacon-redeemers one-way \ 57 | --mint-or-burn \ 58 | --out-file $beaconRedeemerFile 59 | 60 | # Create the transaction. 61 | cardano-cli conway transaction build \ 62 | --tx-in 44101845b0301455ec2a3dd7b98a3b22623011fb38a6216ae1fa78358c5a61fc#1 \ 63 | --tx-in 4cbb75a3ee32c6d6b0a79bb3fff90c009e13f20772c21a8c668c8e94e02d0212#0 \ 64 | --spending-tx-in-reference $spendingScriptPreprodTestnetRef \ 65 | --spending-plutus-script-v2 \ 66 | --spending-reference-tx-in-inline-datum-present \ 67 | --spending-reference-tx-in-redeemer-file $swapRedeemerFile \ 68 | --tx-out "$(cat $HOME/wallets/01.addr) + 3000000 lovelace + 8 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31" \ 69 | --mint "-1 ${pairBeacon} + -1 ${offerBeacon} + -1 ${askBeacon}" \ 70 | --mint-tx-in-reference $beaconScriptPreprodTestnetRef \ 71 | --mint-plutus-script-v2 \ 72 | --mint-reference-tx-in-redeemer-file $beaconRedeemerFile \ 73 | --policy-id "$beaconPolicyId" \ 74 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 75 | --change-address "$(cat $HOME/wallets/01.addr)" \ 76 | --required-signer-hash "$ownerPubKeyHash" \ 77 | --testnet-magic 1 \ 78 | --out-file "${tmpDir}tx.body" 79 | 80 | cardano-cli conway transaction sign \ 81 | --tx-body-file "${tmpDir}tx.body" \ 82 | --signing-key-file $HOME/wallets/01.skey \ 83 | --signing-key-file $HOME/wallets/01Stake.skey \ 84 | --testnet-magic 1 \ 85 | --out-file "${tmpDir}tx.signed" 86 | 87 | cardano-cli conway transaction submit \ 88 | --testnet-magic 1 \ 89 | --tx-file "${tmpDir}tx.signed" 90 | 91 | # Add a newline after the submission response. 92 | echo "" 93 | -------------------------------------------------------------------------------- /scripts/local/two-way/close-swap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Variables 4 | tmpDir="/tmp/cardano-swaps/" 5 | 6 | # Make the tmpDir if it doesn't already exist. 7 | mkdir -p $tmpDir 8 | 9 | ownerPubKeyFile="$HOME/wallets/01Stake.vkey" 10 | swapRedeemerFile="${tmpDir}twoWaySpendingRedeemer.json" 11 | beaconRedeemerFile="${tmpDir}twoWayBeaconRedeemer.json" 12 | 13 | # The reference scripts are permanently locked in the swap address without a staking credential! 14 | # You can use the `cardano-swaps query personal-address` command to see them. 15 | beaconScriptPreprodTestnetRef="115c9ebb9928b8ec6e0c9d1420c43421cfb323639dd9fdcf1e7155e73bec13c5#1" 16 | # beaconScriptSize=4707 17 | 18 | spendingScriptPreprodTestnetRef="115c9ebb9928b8ec6e0c9d1420c43421cfb323639dd9fdcf1e7155e73bec13c5#0" 19 | # spendingScriptSize=5343 20 | 21 | # Generate the hash for the staking verification key. 22 | echo "Calculating the staking pubkey hash for the borrower..." 23 | ownerPubKeyHash=$(cardano-cli conway stake-address key-hash \ 24 | --stake-verification-key-file $ownerPubKeyFile) 25 | 26 | # Create the spending redeemer. 27 | echo "Creating the spending redeemer..." 28 | cardano-swaps spending-redeemers two-way \ 29 | --close \ 30 | --out-file $swapRedeemerFile 31 | 32 | # Helper beacon variables. 33 | echo "Calculating the beacon names..." 34 | beaconPolicyId=$(cardano-swaps beacon-info two-way policy-id \ 35 | --stdout) 36 | 37 | pairBeaconName=$(cardano-swaps beacon-info two-way pair-beacon \ 38 | --first-asset lovelace \ 39 | --second-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 40 | --stdout) 41 | 42 | asset1BeaconName=$(cardano-swaps beacon-info two-way asset-beacon \ 43 | --first-asset lovelace \ 44 | --stdout) 45 | 46 | asset2BeaconName=$(cardano-swaps beacon-info two-way asset-beacon \ 47 | --second-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 48 | --stdout) 49 | 50 | pairBeacon="${beaconPolicyId}.${pairBeaconName}" 51 | asset1Beacon="${beaconPolicyId}.${asset1BeaconName}" 52 | asset2Beacon="${beaconPolicyId}.${asset2BeaconName}" 53 | 54 | # Creating the beacon script redeemer. 55 | echo "Creating the beacon script redeemer..." 56 | cardano-swaps beacon-redeemers two-way \ 57 | --mint-or-burn \ 58 | --out-file $beaconRedeemerFile 59 | 60 | # Create the transaction. 61 | cardano-cli conway transaction build \ 62 | --tx-in f6538bb7a6a0365f3c295aed389df29e752df504ebe691e34f45c0ab9f96272c#2 \ 63 | --tx-in a3ceb781e7d8429eb72e34e9219a99918dbb01db67dbeaf97a4ab5d5f893c873#0 \ 64 | --spending-tx-in-reference $spendingScriptPreprodTestnetRef \ 65 | --spending-plutus-script-v2 \ 66 | --spending-reference-tx-in-inline-datum-present \ 67 | --spending-reference-tx-in-redeemer-file $swapRedeemerFile \ 68 | --tx-out "$(cat $HOME/wallets/01.addr) + 3000000 lovelace + 10 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a" \ 69 | --mint "-1 ${pairBeacon} + -1 ${asset1Beacon} + -1 ${asset2Beacon}" \ 70 | --mint-tx-in-reference $beaconScriptPreprodTestnetRef \ 71 | --mint-plutus-script-v2 \ 72 | --mint-reference-tx-in-redeemer-file $beaconRedeemerFile \ 73 | --policy-id "$beaconPolicyId" \ 74 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 75 | --change-address "$(cat $HOME/wallets/01.addr)" \ 76 | --required-signer-hash "$ownerPubKeyHash" \ 77 | --testnet-magic 1 \ 78 | --out-file "${tmpDir}tx.body" 79 | 80 | cardano-cli conway transaction sign \ 81 | --tx-body-file "${tmpDir}tx.body" \ 82 | --signing-key-file $HOME/wallets/01.skey \ 83 | --signing-key-file $HOME/wallets/01Stake.skey \ 84 | --testnet-magic 1 \ 85 | --out-file "${tmpDir}tx.signed" 86 | 87 | cardano-cli conway transaction submit \ 88 | --testnet-magic 1 \ 89 | --tx-file "${tmpDir}tx.signed" 90 | 91 | # Add a newline after the submission response. 92 | echo "" 93 | -------------------------------------------------------------------------------- /test/Test/OneWaySwap/BeaconNames.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE OverloadedStrings #-} 2 | 3 | module Test.OneWaySwap.BeaconNames 4 | ( 5 | uniquenessTest1 6 | , uniquenessTest2 7 | , uniquenessTest3 8 | , uniquenessTest4 9 | , uniquenessTest5 10 | 11 | , tests 12 | ) where 13 | 14 | import Test.Tasty 15 | import Test.Tasty.HUnit 16 | 17 | import CardanoSwaps.OneWaySwap 18 | import CardanoSwaps.Utils 19 | 20 | import Test.Prelude (testTokenSymbol) 21 | 22 | testToken1 :: (CurrencySymbol,TokenName) 23 | testToken1 = (testTokenSymbol,"TestToken1") 24 | 25 | testToken2 :: (CurrencySymbol,TokenName) 26 | testToken2 = (testTokenSymbol,"TestToken2") 27 | 28 | -- | The reverse direction of a swap yields a different pair beacon name. 29 | uniquenessTest1 :: TestTree 30 | uniquenessTest1 = 31 | testCase "uniquenessTest1" $ assertBool "Fail OneWaySwap.uniquenessTest1" $ 32 | genPairBeaconName (OfferAsset testToken1) (AskAsset (adaSymbol,adaToken)) /= 33 | genPairBeaconName (OfferAsset (adaSymbol,adaToken)) (AskAsset testToken1) 34 | 35 | -- | The offer beacon is different than the trading pair beacon. 36 | uniquenessTest2 :: TestTree 37 | uniquenessTest2 = 38 | testCase "uniquenessTest2" $ assertBool "Fail OneWaySwap.uniquenessTest2" $ 39 | genPairBeaconName (OfferAsset testToken1) (AskAsset (adaSymbol,adaToken)) /= 40 | genOfferBeaconName (OfferAsset testToken1) && 41 | 42 | genPairBeaconName (OfferAsset testToken1) (AskAsset (adaSymbol,adaToken)) /= 43 | genOfferBeaconName (OfferAsset (adaSymbol,adaToken)) && 44 | 45 | genPairBeaconName (OfferAsset (adaSymbol,adaToken)) (AskAsset testToken1) /= 46 | genOfferBeaconName (OfferAsset testToken1) && 47 | 48 | genPairBeaconName (OfferAsset (adaSymbol,adaToken)) (AskAsset testToken1) /= 49 | genOfferBeaconName (OfferAsset (adaSymbol,adaToken)) 50 | 51 | -- | The ask beacon is different than the trading pair beacon. 52 | uniquenessTest3 :: TestTree 53 | uniquenessTest3 = 54 | testCase "uniquenessTest3" $ assertBool "Fail OneWaySwap.uniquenessTest3" $ 55 | genPairBeaconName (OfferAsset testToken1) (AskAsset (adaSymbol,adaToken)) /= 56 | genAskBeaconName (AskAsset testToken1) && 57 | 58 | genPairBeaconName (OfferAsset testToken1) (AskAsset (adaSymbol,adaToken)) /= 59 | genAskBeaconName (AskAsset (adaSymbol,adaToken)) && 60 | 61 | genPairBeaconName (OfferAsset (adaSymbol,adaToken)) (AskAsset testToken1) /= 62 | genAskBeaconName (AskAsset testToken1) && 63 | 64 | genPairBeaconName (OfferAsset (adaSymbol,adaToken)) (AskAsset testToken1) /= 65 | genAskBeaconName (AskAsset (adaSymbol,adaToken)) 66 | 67 | -- | The ask beacon is different than the offer beacon. 68 | uniquenessTest4 :: TestTree 69 | uniquenessTest4 = 70 | testCase "uniquenessTest4" $ assertBool "Fail OneWaySwap.uniquenessTest4" $ 71 | genOfferBeaconName (OfferAsset testToken1) /= 72 | genAskBeaconName (AskAsset testToken1) && 73 | 74 | genOfferBeaconName (OfferAsset (adaSymbol,adaToken)) /= 75 | genAskBeaconName (AskAsset (adaSymbol,adaToken)) 76 | 77 | -- | Two assets have different offer and ask beacons. 78 | uniquenessTest5 :: TestTree 79 | uniquenessTest5 = 80 | testCase "uniquenessTest5" $ assertBool "Fail OneWaySwap.uniquenessTest5" $ 81 | genOfferBeaconName (OfferAsset testToken1) /= 82 | genOfferBeaconName (OfferAsset (adaSymbol,adaToken)) && 83 | 84 | genAskBeaconName (AskAsset testToken1) /= 85 | genAskBeaconName (AskAsset (adaSymbol,adaToken)) && 86 | 87 | genOfferBeaconName (OfferAsset testToken1) /= 88 | genOfferBeaconName (OfferAsset testToken2) && 89 | 90 | genAskBeaconName (AskAsset testToken1) /= 91 | genAskBeaconName (AskAsset testToken2) 92 | 93 | tests :: TestTree 94 | tests = testGroup "Beacon Names" 95 | [ uniquenessTest1 96 | , uniquenessTest2 97 | , uniquenessTest3 98 | , uniquenessTest4 99 | , uniquenessTest5 100 | ] 101 | -------------------------------------------------------------------------------- /scripts/local/one-way/create-swap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Variables 4 | tmpDir="/tmp/cardano-swaps/" 5 | 6 | # Make the tmpDir if it doesn't already exist. 7 | mkdir -p $tmpDir 8 | 9 | swapScriptFile="${tmpDir}oneWaySwap.plutus" # This is used to create the swap address. 10 | ownerPubKeyFile="$HOME/wallets/01Stake.vkey" 11 | swapAddrFile="${tmpDir}oneWaySwap.addr" 12 | swapDatumFile="${tmpDir}swapDatum.json" 13 | beaconRedeemerFile="${tmpDir}oneWayBeaconRedeemer.json" 14 | 15 | # The reference scripts are permanently locked in the swap address without a staking credential! 16 | # You can use the `cardano-swaps query personal-address` command to see them. 17 | beaconScriptPreprodTestnetRef="9fecc1d2cf99088facad02aeccbedb6a4f783965dc6c02bd04dc8b348e9a0858#1" 18 | # beaconScriptSize=4432 19 | 20 | # Export the swap validator script. 21 | echo "Exporting the swap validator script..." 22 | cardano-swaps scripts one-way swap-script \ 23 | --out-file $swapScriptFile 24 | 25 | # Create the swap address. 26 | echo -n "Creating the swap address... " 27 | cardano-cli conway address build \ 28 | --payment-script-file $swapScriptFile \ 29 | --stake-verification-key-file $ownerPubKeyFile \ 30 | --testnet-magic 1 \ 31 | --out-file $swapAddrFile 32 | 33 | echo "$(cat $swapAddrFile)" 34 | 35 | # Helper beacon variables. 36 | echo "Calculating the beacon names..." 37 | beaconPolicyId=$(cardano-swaps beacon-info one-way policy-id \ 38 | --stdout) 39 | 40 | pairBeaconName=$(cardano-swaps beacon-info one-way pair-beacon \ 41 | --ask-asset lovelace \ 42 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 43 | --stdout) 44 | 45 | offerBeaconName=$(cardano-swaps beacon-info one-way offer-beacon \ 46 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 47 | --stdout) 48 | 49 | askBeaconName=$(cardano-swaps beacon-info one-way ask-beacon \ 50 | --ask-asset lovelace \ 51 | --stdout) 52 | 53 | pairBeacon="${beaconPolicyId}.${pairBeaconName}" 54 | offerBeacon="${beaconPolicyId}.${offerBeaconName}" 55 | askBeacon="${beaconPolicyId}.${askBeaconName}" 56 | 57 | # Get the beacon script redeemer. 58 | echo "Creating the minting redeemer..." 59 | cardano-swaps beacon-redeemers one-way \ 60 | --mint-or-burn \ 61 | --out-file $beaconRedeemerFile 62 | 63 | # Create the swap datum. 64 | echo "Creating the swap datum..." 65 | cardano-swaps datums one-way \ 66 | --ask-asset lovelace \ 67 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 68 | --offer-price '1000000 / 1' \ 69 | --out-file $swapDatumFile 70 | 71 | # Create the transaction. 72 | echo "Building the transaction..." 73 | cardano-cli conway transaction build \ 74 | --tx-in e421457ad39e6c01c4ff53343af64b8c26efc22d57e3ea28b219cbb9002aa7ca#0 \ 75 | --tx-in 8795ca8ae3ec2fed3813e99f0e9d683c4f3d4e5a7916e5858dab7756c5104589#0 \ 76 | --tx-out "$(cat ${swapAddrFile}) + 3000000 lovelace + 1 ${pairBeacon} + 1 ${offerBeacon} + 1 ${askBeacon} + 15 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a" \ 77 | --tx-out-inline-datum-file $swapDatumFile \ 78 | --mint "1 ${pairBeacon} + 1 ${offerBeacon} + 1 ${askBeacon}" \ 79 | --mint-tx-in-reference $beaconScriptPreprodTestnetRef \ 80 | --mint-plutus-script-v2 \ 81 | --mint-reference-tx-in-redeemer-file $beaconRedeemerFile \ 82 | --policy-id "$beaconPolicyId" \ 83 | --change-address "$(cat $HOME/wallets/01.addr)" \ 84 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 85 | --testnet-magic 1 \ 86 | --out-file "${tmpDir}tx.body" 87 | 88 | cardano-cli conway transaction sign \ 89 | --tx-body-file "${tmpDir}tx.body" \ 90 | --signing-key-file $HOME/wallets/01.skey \ 91 | --testnet-magic 1 \ 92 | --out-file "${tmpDir}tx.signed" 93 | 94 | cardano-cli conway transaction submit \ 95 | --testnet-magic 1 \ 96 | --tx-file "${tmpDir}tx.signed" 97 | 98 | # Add a newline after the submission response. 99 | echo "" 100 | -------------------------------------------------------------------------------- /scripts/local/two-way/create-swap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Variables 4 | tmpDir="/tmp/cardano-swaps/" 5 | 6 | # Make the tmpDir if it doesn't already exist. 7 | mkdir -p $tmpDir 8 | 9 | swapScriptFile="${tmpDir}twoWaySwap.plutus" # This is used to create the swap address. 10 | ownerPubKeyFile="$HOME/wallets/01Stake.vkey" 11 | swapAddrFile="${tmpDir}twoWaySwap.addr" 12 | swapDatumFile="${tmpDir}swapDatum.json" 13 | beaconRedeemerFile="${tmpDir}twoWaySwapBeaconRedeemer.json" 14 | 15 | # The reference scripts are permanently locked in the swap address without a staking credential! 16 | # You can use the `cardano-swaps query personal-address` command to see them. 17 | beaconScriptPreprodTestnetRef="115c9ebb9928b8ec6e0c9d1420c43421cfb323639dd9fdcf1e7155e73bec13c5#1" 18 | # beaconScriptSize=4707 19 | 20 | # Export the swap validator script. 21 | echo "Exporting the swap validator script..." 22 | cardano-swaps scripts two-way swap-script \ 23 | --out-file $swapScriptFile 24 | 25 | # Create the swap address. 26 | echo -n "Creating the swap address... " 27 | cardano-cli conway address build \ 28 | --payment-script-file $swapScriptFile \ 29 | --stake-verification-key-file $ownerPubKeyFile \ 30 | --testnet-magic 1 \ 31 | --out-file $swapAddrFile 32 | 33 | echo "$(cat $swapAddrFile)" 34 | 35 | # Helper beacon variables. 36 | echo "Calculating the beacon names..." 37 | beaconPolicyId=$(cardano-swaps beacon-info two-way policy-id \ 38 | --stdout) 39 | 40 | pairBeaconName=$(cardano-swaps beacon-info two-way pair-beacon \ 41 | --first-asset lovelace \ 42 | --second-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31 \ 43 | --stdout) 44 | 45 | asset1BeaconName=$(cardano-swaps beacon-info two-way asset-beacon \ 46 | --first-asset lovelace \ 47 | --stdout) 48 | 49 | asset2BeaconName=$(cardano-swaps beacon-info two-way asset-beacon \ 50 | --second-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31 \ 51 | --stdout) 52 | 53 | pairBeacon="${beaconPolicyId}.${pairBeaconName}" 54 | asset1Beacon="${beaconPolicyId}.${asset1BeaconName}" 55 | asset2Beacon="${beaconPolicyId}.${asset2BeaconName}" 56 | 57 | # Get the mint beacon redeemer. 58 | echo "Creating the minting redeemer..." 59 | cardano-swaps beacon-redeemers two-way \ 60 | --mint-or-burn \ 61 | --out-file $beaconRedeemerFile 62 | 63 | # Create the swap datum. 64 | echo "Creating the swap datum..." 65 | cardano-swaps datums two-way \ 66 | --first-asset lovelace \ 67 | --second-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31 \ 68 | --first-price '1 / 1000000' \ 69 | --second-price 2000000 \ 70 | --out-file $swapDatumFile 71 | 72 | # Create the transaction. 73 | echo "Building the transaction..." 74 | cardano-cli conway transaction build \ 75 | --tx-in 38fd18f4ca7c6587eb2703ac3bfd42e1406d089901e2c29f158358fdda5b196a#2 \ 76 | --tx-in 338945b8cc6d4c49aa0b94452b2f99c29c4b68efa89fcda8ed691e6fc81c97b0#0 \ 77 | --tx-in 44f58115ad9738de64bb5624b495a2e7abddfdbe055df474d7d980af1244d64e#0 \ 78 | --tx-out "$(cat ${swapAddrFile}) + 3000000 lovelace + 1 ${pairBeacon} + 1 ${asset1Beacon} + 1 ${asset2Beacon} + 11 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31" \ 79 | --tx-out-inline-datum-file $swapDatumFile \ 80 | --mint "1 ${pairBeacon} + 1 ${asset1Beacon} + 1 ${asset2Beacon}" \ 81 | --mint-tx-in-reference $beaconScriptPreprodTestnetRef \ 82 | --mint-plutus-script-v2 \ 83 | --mint-reference-tx-in-redeemer-file $beaconRedeemerFile \ 84 | --policy-id "$beaconPolicyId" \ 85 | --change-address "$(cat $HOME/wallets/01.addr)" \ 86 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 87 | --testnet-magic 1 \ 88 | --out-file "${tmpDir}tx.body" 89 | 90 | cardano-cli conway transaction sign \ 91 | --tx-body-file "${tmpDir}tx.body" \ 92 | --signing-key-file $HOME/wallets/01.skey \ 93 | --testnet-magic 1 \ 94 | --out-file "${tmpDir}tx.signed" 95 | 96 | cardano-cli conway transaction submit \ 97 | --testnet-magic 1 \ 98 | --tx-file "${tmpDir}tx.signed" 99 | 100 | # Add a newline after the submission response. 101 | echo "" 102 | -------------------------------------------------------------------------------- /scripts/remote/mint-test-tokens/mint.sh: -------------------------------------------------------------------------------- 1 | alwaysSucceedSymbol="c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d" 2 | tokenName1=$(echo -n "TestToken1" | xxd -ps) 3 | tmpDir="/tmp/cardano-swaps/" 4 | 5 | # Make the tmpDir if it doesn't already exist. 6 | mkdir -p $tmpDir 7 | 8 | # Create the transaction. 9 | echo "Exporting the current protocol parameters..." 10 | cardano-swaps query protocol-params \ 11 | --testnet \ 12 | --out-file "${tmpDir}protocol.json" 13 | 14 | initial_change=$((19759481-2000000)) 15 | 16 | echo "Building the initial transaction..." 17 | cardano-cli conway transaction build-raw \ 18 | --tx-in b6b5bd23fa762b2630dc9dedc10d0bac61d6ffa3617f451df8a8ee31a83c441f#1 \ 19 | --tx-out "$(cat $HOME/wallets/01.addr) 2000000 lovelace + 1000 ${alwaysSucceedSymbol}.${tokenName1}" \ 20 | --tx-out "$(cat $HOME/wallets/01.addr) ${initial_change} lovelace" \ 21 | --mint "1000 ${alwaysSucceedSymbol}.${tokenName1}" \ 22 | --mint-script-file alwaysSucceedsMintingPolicy.plutus \ 23 | --mint-redeemer-file unit.json \ 24 | --mint-execution-units "(0,0)" \ 25 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 26 | --protocol-params-file "${tmpDir}protocol.json" \ 27 | --tx-total-collateral 21000000 \ 28 | --tx-out-return-collateral "$(cat $HOME/wallets/01.addr) 21000000 lovelace" \ 29 | --fee 5000000 \ 30 | --out-file "${tmpDir}tx.body" 31 | 32 | echo "Getting the execution units estimations..." 33 | exec_units=$(cardano-swaps evaluate-tx \ 34 | --testnet \ 35 | --tx-file "${tmpDir}tx.body") 36 | 37 | mint_mem=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="mint" and .validator.index==0) | .budget.memory' ) 38 | mint_steps=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="mint" and .validator.index==0) | .budget.cpu' ) 39 | 40 | echo "Rebuilding the transaction with proper executions budgets..." 41 | cardano-cli conway transaction build-raw \ 42 | --tx-in b6b5bd23fa762b2630dc9dedc10d0bac61d6ffa3617f451df8a8ee31a83c441f#1 \ 43 | --tx-out "$(cat $HOME/wallets/01.addr) 2000000 lovelace + 1000 ${alwaysSucceedSymbol}.${tokenName1}" \ 44 | --tx-out "$(cat $HOME/wallets/01.addr) ${initial_change} lovelace" \ 45 | --mint "1000 ${alwaysSucceedSymbol}.${tokenName1}" \ 46 | --mint-script-file alwaysSucceedsMintingPolicy.plutus \ 47 | --mint-redeemer-file unit.json \ 48 | --mint-execution-units "(${mint_steps},${mint_mem})" \ 49 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 50 | --protocol-params-file "${tmpDir}protocol.json" \ 51 | --tx-total-collateral 21000000 \ 52 | --tx-out-return-collateral "$(cat $HOME/wallets/01.addr) 21000000 lovelace" \ 53 | --fee 5000000 \ 54 | --out-file "${tmpDir}tx.body" 55 | 56 | echo "Calculating the required fee..." 57 | calculated_fee=$(cardano-cli conway transaction calculate-min-fee \ 58 | --tx-body-file "${tmpDir}tx.body" \ 59 | --protocol-params-file "${tmpDir}protocol.json" \ 60 | --witness-count 1 | cut -d' ' -f1) 61 | req_fee=$(($calculated_fee+50000)) # Add 0.05 ADA to be safe since the fee must still be updated. 62 | req_collateral=$(printf %.0f $(echo "${req_fee}*1.5" | bc)) 63 | 64 | echo "Rebuilding the transaction with required transaction fee..." 65 | cardano-cli conway transaction build-raw \ 66 | --tx-in b6b5bd23fa762b2630dc9dedc10d0bac61d6ffa3617f451df8a8ee31a83c441f#1 \ 67 | --tx-out "$(cat $HOME/wallets/01.addr) 2000000 lovelace + 1000 ${alwaysSucceedSymbol}.${tokenName1}" \ 68 | --tx-out "$(cat $HOME/wallets/01.addr) + $(($initial_change-$req_fee)) lovelace " \ 69 | --mint "1000 ${alwaysSucceedSymbol}.${tokenName1}" \ 70 | --mint-script-file alwaysSucceedsMintingPolicy.plutus \ 71 | --mint-redeemer-file unit.json \ 72 | --mint-execution-units "(${mint_steps},${mint_mem})" \ 73 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 74 | --protocol-params-file "${tmpDir}protocol.json" \ 75 | --tx-total-collateral $req_collateral \ 76 | --tx-out-return-collateral "$(cat $HOME/wallets/01.addr) $((21000000-$req_collateral)) lovelace" \ 77 | --fee $req_fee \ 78 | --out-file "${tmpDir}tx.body" 79 | 80 | cardano-cli conway transaction sign \ 81 | --tx-body-file "${tmpDir}tx.body" \ 82 | --signing-key-file $HOME/wallets/01.skey \ 83 | --testnet-magic 1 \ 84 | --out-file "${tmpDir}tx.signed" 85 | 86 | echo "Submitting the transaction..." 87 | cardano-swaps submit \ 88 | --testnet \ 89 | --tx-file "${tmpDir}tx.signed" 90 | 91 | # Add a newline after the submission response. 92 | echo "" 93 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Revision history for cardano-swaps 2 | 3 | ## Next 4 | 5 | #### Off-Chain Changes 6 | 7 | - Updated off-chain CLI to lookup the current protocol parameters from Koios instead of them 8 | being hard-coded into the executable. 9 | - Added GettingStarted instructions for building required aiken compiler from source. **The same 10 | compiler version must be used by everyone.** 11 | - Added two more failure test cases to the smart contract unit tests. 12 | - Simplified and updated example scripts for conway era. 13 | - Added missing `--tx-out-return-collateral` fields to example remote scripts. 14 | 15 | ## 2.1.0.0rc 16 | 17 | - Updated off-chain code to allow building with ghc-9.x. The new default ghc version is set to 18 | 9.6.4. 19 | - Refactored the CardanoSwaps haskell library to make it easier to maintain separate versions 20 | going forward. 21 | 22 | ## 2.0.0.0rc 23 | 24 | #### Added 25 | 26 | - Added staking execution option to the beacon scripts and changed the spending scripts to delegate 27 | actions to the staking executions when appropriate. 28 | 29 | #### Changed 30 | 31 | - Bumped aiken stdlib version to 1.7.0. 32 | - Changed the internal representation of prices from `Rational` to Int. (Optimization) 33 | - Changed how swap output datums were checked during swap executions. (Optimization) 34 | - Changed how UTxO values were checked. (Optimization) 35 | - Renamed the two-way swap redeemers and datum price fields to be more intuitive. (UX improvement) 36 | - Simplified the CLI by merging fields when appropriate. (UX improvement) 37 | 38 | ## 1.0.0.0rc 39 | 40 | - Added two-way swaps to provide a mechanism to naturally incentivize liquidity providers. 41 | - Changed one-way swaps to use a single beacon policy for all swaps. The asset name now 42 | distinguishes the beacon. 43 | - Changed one-way swaps to not support merging swap outputs. This dramatically improved performance. 44 | - Support for Blockfrost was dropped in the CLI because it does not allow server-side filtering of 45 | swaps like Koios does. For example, querying swaps by trading pair also needs to filter out all 46 | finished swaps. Koios can do this *before* returning the results. Blockfrost requires this filtering 47 | to be done locally. 48 | - Added CLI support for using Koios as a remote node. 49 | - Added template bash scripts for using a remote node. 50 | - Added CLI support for querying personal addresses using Koios. 51 | 52 | ## 0.4.0.0 53 | 54 | - Universal spending script used instead of one spending script for each trading pair. 55 | - One beacon policy for each asset being offered. The asset name is: sha2_256( ask_asset policy id ++ ask_asset asset name ). This allows for offer based queries in addition to trading pair based queries. 56 | - The minimum deposit of 20 ADA was removed. Instead the proper beacon must be stored with each swap UTxO. This requires the minUTxO value due to the protocol parameters. 57 | - The swap datum was expanded to include information about the swap UTxO: beacon policy id and name, offer asset policy id and name, ask asset policy id and name, and price. 58 | - Added check for the beacon to be stored with some of the offer asset during creating and updating swaps. 59 | - Added check for price to have a denominator > 0. 60 | - Added check that no extraneous assets can be stored in the swap UTxO. 61 | - Merged Close and Update redeemer into one redeemer. 62 | 63 | ## 0.3.0.0 64 | 65 | - Plutus scripts written using Aiken. 66 | - `SwapDatum` changed to a sum (enum) type. 67 | - Reference scripts are no longer required to be stored with the beacons. Instead, a minimum UTxO value of 20 ADA is enforced. Users and arbitragers are expected to use there own reference scripts or share using a program like [cardano-reference-scripts](https://github.com/fallen-icarus/cardano-reference-scripts). This is to cut down on unnecessary blockchain bloat due to multiple copies of the same script being stored on chain. 68 | - The `Close` redeemer no longer checks for outputs to the swap address since that is not what it is meant for. 69 | - plutus-apps bumped to v1.2.0. 70 | - Decoding datums from api query results now uses `decodeDatum` to minimize boilerplate. 71 | - Koios support added. 72 | - Swap contracts no longer convert prices from ADA to lovelace. All prices for ADA are assumed to be in units of lovelace. This cuts down on cost used per execution. 73 | - The CLI commands have changed. See the [GettingStarted](GettingStarted.md). 74 | 75 | ## 0.2.0.0 76 | 77 | - All users get the same spending script for a given trading pair. 78 | - There is a separate beacon policy for every trading pair. 79 | - User addresses must have a staking credential. 80 | 81 | ## 0.1.0.0 82 | 83 | * First version. Released on an unsuspecting world. 84 | -------------------------------------------------------------------------------- /scripts/local/one-way/update-price.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Variables 4 | tmpDir="/tmp/cardano-swaps/" 5 | 6 | # Make the tmpDir if it doesn't already exist. 7 | mkdir -p $tmpDir 8 | 9 | ownerPubKeyFile="$HOME/wallets/01Stake.vkey" 10 | beaconScriptFile="${tmpDir}oneWayBeacons.plutus" 11 | beaconAddrFile="${tmpDir}oneWayBeaconStake.addr" 12 | swapAddrFile="${tmpDir}oneWaySwap.addr" 13 | swapDatumFile="${tmpDir}swapDatum.json" 14 | swapRedeemerFile="${tmpDir}oneWaySpendingRedeemer.json" 15 | beaconRedeemerFile="${tmpDir}oneWayBeaconRedeemer.json" 16 | 17 | # The reference scripts are permanently locked in the swap address without a staking credential! 18 | # You can use the `cardano-swaps query personal-address` command to see them. 19 | beaconScriptPreprodTestnetRef="9fecc1d2cf99088facad02aeccbedb6a4f783965dc6c02bd04dc8b348e9a0858#1" 20 | # beaconScriptSize=4432 21 | 22 | spendingScriptPreprodTestnetRef="9fecc1d2cf99088facad02aeccbedb6a4f783965dc6c02bd04dc8b348e9a0858#0" 23 | # spendingScriptSize=4842 24 | 25 | # Generate the hash for the staking verification key. 26 | echo "Calculating the staking pubkey hash for the borrower..." 27 | ownerPubKeyHash=$(cardano-cli conway stake-address key-hash \ 28 | --stake-verification-key-file $ownerPubKeyFile) 29 | 30 | # Export the beacon script. 31 | echo "Exporting the beacon script..." 32 | cardano-swaps scripts one-way beacon-script \ 33 | --out-file $beaconScriptFile 34 | 35 | # Create the meta beacon stake address. 36 | echo "Creating the beacon reward address..." 37 | cardano-cli conway stake-address build \ 38 | --stake-script-file $beaconScriptFile \ 39 | --testnet-magic 1 \ 40 | --out-file $beaconAddrFile 41 | 42 | # Create the spending redeemer. 43 | echo "Creating the spending redeemer..." 44 | cardano-swaps spending-redeemers one-way \ 45 | --update-with-stake \ 46 | --out-file $swapRedeemerFile 47 | 48 | # Create the beacon script redeemer. 49 | echo "Creating the beacon redeemer..." 50 | cardano-swaps beacon-redeemers one-way \ 51 | --update-only \ 52 | --out-file $beaconRedeemerFile 53 | 54 | # Create the new swap datum. 55 | echo "Creating the new swap datum..." 56 | cardano-swaps datums one-way \ 57 | --ask-asset lovelace \ 58 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 59 | --offer-price 2000000 \ 60 | --out-file $swapDatumFile 61 | 62 | # Helper beacon variables. 63 | echo "Calculating the beacon names..." 64 | beaconPolicyId=$(cardano-swaps beacon-info one-way policy-id \ 65 | --stdout) 66 | 67 | pairBeaconName=$(cardano-swaps beacon-info one-way pair-beacon \ 68 | --ask-asset lovelace \ 69 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 70 | --stdout) 71 | 72 | offerBeaconName=$(cardano-swaps beacon-info one-way offer-beacon \ 73 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 74 | --stdout) 75 | 76 | askBeaconName=$(cardano-swaps beacon-info one-way ask-beacon \ 77 | --ask-asset lovelace \ 78 | --stdout) 79 | 80 | pairBeacon="${beaconPolicyId}.${pairBeaconName}" 81 | offerBeacon="${beaconPolicyId}.${offerBeaconName}" 82 | askBeacon="${beaconPolicyId}.${askBeaconName}" 83 | 84 | # Create the transaction. 85 | cardano-cli conway transaction build \ 86 | --tx-in 8762f07fef0c5137ee7d6d8bce962f29554f1ddff3883f1b2d2fc39f213df94c#2 \ 87 | --tx-in 44101845b0301455ec2a3dd7b98a3b22623011fb38a6216ae1fa78358c5a61fc#0 \ 88 | --spending-tx-in-reference $spendingScriptPreprodTestnetRef \ 89 | --spending-plutus-script-v2 \ 90 | --spending-reference-tx-in-inline-datum-present \ 91 | --spending-reference-tx-in-redeemer-file $swapRedeemerFile \ 92 | --withdrawal "$(cat ${beaconAddrFile})+0" \ 93 | --withdrawal-tx-in-reference $beaconScriptPreprodTestnetRef \ 94 | --withdrawal-plutus-script-v2 \ 95 | --withdrawal-reference-tx-in-redeemer-file $beaconRedeemerFile \ 96 | --tx-out "$(cat ${swapAddrFile}) + 3000000 lovelace + 1 ${pairBeacon} + 1 ${offerBeacon} + 1 ${askBeacon} + 15 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a" \ 97 | --tx-out-inline-datum-file $swapDatumFile \ 98 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 99 | --change-address "$(cat $HOME/wallets/01.addr)" \ 100 | --required-signer-hash "$ownerPubKeyHash" \ 101 | --testnet-magic 1 \ 102 | --out-file "${tmpDir}tx.body" 103 | 104 | cardano-cli conway transaction sign \ 105 | --tx-body-file "${tmpDir}tx.body" \ 106 | --signing-key-file $HOME/wallets/01.skey \ 107 | --signing-key-file $HOME/wallets/01Stake.skey \ 108 | --testnet-magic 1 \ 109 | --out-file "${tmpDir}tx.signed" 110 | 111 | cardano-cli conway transaction submit \ 112 | --testnet-magic 1 \ 113 | --tx-file "${tmpDir}tx.signed" 114 | 115 | # Add a newline after the submission response. 116 | echo "" 117 | -------------------------------------------------------------------------------- /scripts/local/two-way/update-price.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Variables 4 | tmpDir="/tmp/cardano-swaps/" 5 | 6 | # Make the tmpDir if it doesn't already exist. 7 | mkdir -p $tmpDir 8 | 9 | ownerPubKeyFile="$HOME/wallets/01Stake.vkey" 10 | beaconScriptFile="${tmpDir}twoWayBeacons.plutus" 11 | beaconAddrFile="${tmpDir}twoWayBeaconStake.addr" 12 | swapAddrFile="${tmpDir}twoWaySwap.addr" 13 | swapDatumFile="${tmpDir}swapDatum.json" 14 | swapRedeemerFile="${tmpDir}twoWaySpendingRedeemer.json" 15 | beaconRedeemerFile="${tmpDir}twoWayBeaconRedeemer.json" 16 | 17 | # The reference scripts are permanently locked in the swap address without a staking credential! 18 | # You can use the `cardano-swaps query personal-address` command to see them. 19 | beaconScriptPreprodTestnetRef="115c9ebb9928b8ec6e0c9d1420c43421cfb323639dd9fdcf1e7155e73bec13c5#1" 20 | # beaconScriptSize=4707 21 | 22 | spendingScriptPreprodTestnetRef="115c9ebb9928b8ec6e0c9d1420c43421cfb323639dd9fdcf1e7155e73bec13c5#0" 23 | # spendingScriptSize=5343 24 | 25 | # Generate the hash for the staking verification key. 26 | echo "Calculating the staking pubkey hash for the borrower..." 27 | ownerPubKeyHash=$(cardano-cli conway stake-address key-hash \ 28 | --stake-verification-key-file $ownerPubKeyFile) 29 | 30 | # Export the beacon script. 31 | echo "Exporting the beacon script..." 32 | cardano-swaps scripts two-way beacon-script \ 33 | --out-file $beaconScriptFile 34 | 35 | # Create the meta beacon stake address. 36 | echo "Creating the beacon reward address..." 37 | cardano-cli conway stake-address build \ 38 | --stake-script-file $beaconScriptFile \ 39 | --testnet-magic 1 \ 40 | --out-file $beaconAddrFile 41 | 42 | # Create the spending redeemer. 43 | echo "Creating the spending redeemer..." 44 | cardano-swaps spending-redeemers two-way \ 45 | --update-with-stake \ 46 | --out-file $swapRedeemerFile 47 | 48 | # Create the beacon script redeemer. 49 | echo "Creating the beacon redeemer..." 50 | cardano-swaps beacon-redeemers two-way \ 51 | --update-only \ 52 | --out-file $beaconRedeemerFile 53 | 54 | # Create the swap datum. 55 | echo "Creating the swap datum..." 56 | cardano-swaps datums two-way \ 57 | --second-asset lovelace \ 58 | --first-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31 \ 59 | --second-price '2 / 1000000' \ 60 | --first-price 2000000 \ 61 | --out-file $swapDatumFile 62 | 63 | # Helper beacon variables. 64 | echo "Calculating the beacon names..." 65 | beaconPolicyId=$(cardano-swaps beacon-info two-way policy-id \ 66 | --stdout) 67 | 68 | pairBeaconName=$(cardano-swaps beacon-info two-way pair-beacon \ 69 | --first-asset lovelace \ 70 | --second-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31 \ 71 | --stdout) 72 | 73 | asset1BeaconName=$(cardano-swaps beacon-info two-way asset-beacon \ 74 | --first-asset lovelace \ 75 | --stdout) 76 | 77 | asset2BeaconName=$(cardano-swaps beacon-info two-way asset-beacon \ 78 | --second-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31 \ 79 | --stdout) 80 | 81 | pairBeacon="${beaconPolicyId}.${pairBeaconName}" 82 | asset1Beacon="${beaconPolicyId}.${asset1BeaconName}" 83 | asset2Beacon="${beaconPolicyId}.${asset2BeaconName}" 84 | 85 | # Create the transaction. 86 | cardano-cli conway transaction build \ 87 | --tx-in 22e60774851d6db2c2e4600e3c6daebe3b68d52e1d9d7070f6c2fc6ee8c8efcf#1 \ 88 | --tx-in 22e60774851d6db2c2e4600e3c6daebe3b68d52e1d9d7070f6c2fc6ee8c8efcf#0 \ 89 | --spending-tx-in-reference $spendingScriptPreprodTestnetRef \ 90 | --spending-plutus-script-v2 \ 91 | --spending-reference-tx-in-inline-datum-present \ 92 | --spending-reference-tx-in-redeemer-file $swapRedeemerFile \ 93 | --withdrawal "$(cat ${beaconAddrFile})+0" \ 94 | --withdrawal-tx-in-reference $beaconScriptPreprodTestnetRef \ 95 | --withdrawal-plutus-script-v2 \ 96 | --withdrawal-reference-tx-in-redeemer-file $beaconRedeemerFile \ 97 | --tx-out "$(cat ${swapAddrFile}) + 3000000 lovelace + 1 ${pairBeacon} + 1 ${asset1Beacon} + 1 ${asset2Beacon} + 11 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31" \ 98 | --tx-out-inline-datum-file $swapDatumFile \ 99 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 100 | --change-address "$(cat $HOME/wallets/01.addr)" \ 101 | --required-signer-hash "$ownerPubKeyHash" \ 102 | --testnet-magic 1 \ 103 | --out-file "${tmpDir}tx.body" 104 | 105 | cardano-cli conway transaction sign \ 106 | --tx-body-file "${tmpDir}tx.body" \ 107 | --signing-key-file $HOME/wallets/01.skey \ 108 | --signing-key-file $HOME/wallets/01Stake.skey \ 109 | --testnet-magic 1 \ 110 | --out-file "${tmpDir}tx.signed" 111 | 112 | cardano-cli conway transaction submit \ 113 | --testnet-magic 1 \ 114 | --tx-file "${tmpDir}tx.signed" 115 | 116 | # Add a newline after the submission response. 117 | echo "" 118 | -------------------------------------------------------------------------------- /scripts/local/one-way/convert-swap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Variables 4 | tmpDir="/tmp/cardano-swaps/" 5 | 6 | # Make the tmpDir if it doesn't already exist. 7 | mkdir -p $tmpDir 8 | 9 | ownerPubKeyFile="$HOME/wallets/01Stake.vkey" 10 | swapAddrFile="${tmpDir}oneWaySwap.addr" 11 | swapDatumFile="${tmpDir}swapDatum.json" 12 | swapRedeemerFile="${tmpDir}oneWaySpendingRedeemer.json" 13 | beaconRedeemerFile="${tmpDir}oneWayBeaconRedeemer.json" 14 | 15 | # The reference scripts are permanently locked in the swap address without a staking credential! 16 | # You can use the `cardano-swaps query personal-address` command to see them. 17 | beaconScriptPreprodTestnetRef="9fecc1d2cf99088facad02aeccbedb6a4f783965dc6c02bd04dc8b348e9a0858#1" 18 | # beaconScriptSize=4432 19 | 20 | spendingScriptPreprodTestnetRef="9fecc1d2cf99088facad02aeccbedb6a4f783965dc6c02bd04dc8b348e9a0858#0" 21 | # spendingScriptSize=4842 22 | 23 | # Generate the hash for the staking verification key. 24 | echo "Calculating the staking pubkey hash for the borrower..." 25 | ownerPubKeyHash=$(cardano-cli conway stake-address key-hash \ 26 | --stake-verification-key-file $ownerPubKeyFile) 27 | 28 | # Create the spending redeemer. 29 | echo "Creating the spending redeemer..." 30 | cardano-swaps spending-redeemers one-way \ 31 | --update-with-mint \ 32 | --out-file $swapRedeemerFile 33 | 34 | # Create the new swap datum. 35 | echo "Creating the new swap datum..." 36 | cardano-swaps datums one-way \ 37 | --ask-asset lovelace \ 38 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31 \ 39 | --offer-price 1000000 \ 40 | --out-file $swapDatumFile 41 | 42 | # Helper beacon variables. 43 | echo "Calculating the beacon names..." 44 | beaconPolicyId=$(cardano-swaps beacon-info one-way policy-id \ 45 | --stdout) 46 | 47 | oldPairBeaconName=$(cardano-swaps beacon-info one-way pair-beacon \ 48 | --ask-asset lovelace \ 49 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 50 | --stdout) 51 | 52 | oldOfferBeaconName=$(cardano-swaps beacon-info one-way offer-beacon \ 53 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 54 | --stdout) 55 | 56 | oldAskBeaconName=$(cardano-swaps beacon-info one-way ask-beacon \ 57 | --ask-asset lovelace \ 58 | --stdout) 59 | 60 | oldPairBeacon="${beaconPolicyId}.${oldPairBeaconName}" 61 | oldOfferBeacon="${beaconPolicyId}.${oldOfferBeaconName}" 62 | oldAskBeacon="${beaconPolicyId}.${oldAskBeaconName}" 63 | 64 | newPairBeaconName=$(cardano-swaps beacon-info one-way pair-beacon \ 65 | --ask-asset lovelace \ 66 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31 \ 67 | --stdout) 68 | 69 | newOfferBeaconName=$(cardano-swaps beacon-info one-way offer-beacon \ 70 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31 \ 71 | --stdout) 72 | 73 | newAskBeaconName=$(cardano-swaps beacon-info one-way ask-beacon \ 74 | --ask-asset lovelace \ 75 | --stdout) 76 | 77 | newPairBeacon="${beaconPolicyId}.${newPairBeaconName}" 78 | newOfferBeacon="${beaconPolicyId}.${newOfferBeaconName}" 79 | newAskBeacon="${beaconPolicyId}.${newAskBeaconName}" 80 | 81 | # Creating the beacon script redeemer. 82 | cardano-swaps beacon-redeemers one-way \ 83 | --mint-or-burn \ 84 | --out-file $beaconRedeemerFile 85 | 86 | # Create the transaction. 87 | cardano-cli conway transaction build \ 88 | --tx-in 2015079d9e4878290e32f1c3c5698b20dec00af1798c4be2062c7a09cb2b66cb#0 \ 89 | --tx-in 42298d5edf1866d29ab73ec10f2c3b88761035d03d078069416651a0f27df915#1 \ 90 | --tx-in 42298d5edf1866d29ab73ec10f2c3b88761035d03d078069416651a0f27df915#0 \ 91 | --spending-tx-in-reference $spendingScriptPreprodTestnetRef \ 92 | --spending-plutus-script-v2 \ 93 | --spending-reference-tx-in-inline-datum-present \ 94 | --spending-reference-tx-in-redeemer-file $swapRedeemerFile \ 95 | --tx-out "$(cat ${swapAddrFile}) + 3000000 lovelace + 1 ${newPairBeacon} + 1 ${newOfferBeacon} + 1 ${newAskBeacon} + 10 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31" \ 96 | --tx-out-inline-datum-file $swapDatumFile \ 97 | --tx-out "$(cat $HOME/wallets/01.addr) + 3000000 lovelace + 15 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a" \ 98 | --mint "-1 ${oldPairBeacon} + -1 ${oldOfferBeacon} + -1 ${oldAskBeacon} + 1 ${newPairBeacon} + 1 ${newOfferBeacon} + 1 ${newAskBeacon}" \ 99 | --mint-tx-in-reference $beaconScriptPreprodTestnetRef \ 100 | --mint-plutus-script-v2 \ 101 | --mint-reference-tx-in-redeemer-file $beaconRedeemerFile \ 102 | --policy-id "$beaconPolicyId" \ 103 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 104 | --change-address "$(cat $HOME/wallets/01.addr)" \ 105 | --required-signer-hash "$ownerPubKeyHash" \ 106 | --testnet-magic 1 \ 107 | --out-file "${tmpDir}tx.body" 108 | 109 | cardano-cli conway transaction sign \ 110 | --tx-body-file "${tmpDir}tx.body" \ 111 | --signing-key-file $HOME/wallets/01.skey \ 112 | --signing-key-file $HOME/wallets/01Stake.skey \ 113 | --testnet-magic 1 \ 114 | --out-file "${tmpDir}tx.signed" 115 | 116 | cardano-cli conway transaction submit \ 117 | --testnet-magic 1 \ 118 | --tx-file "${tmpDir}tx.signed" 119 | 120 | # Add a newline after the submission response. 121 | echo "" 122 | -------------------------------------------------------------------------------- /scripts/local/two-way/convert-swap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Variables 4 | tmpDir="/tmp/cardano-swaps/" 5 | 6 | # Make the tmpDir if it doesn't already exist. 7 | mkdir -p $tmpDir 8 | 9 | ownerPubKeyFile="$HOME/wallets/01Stake.vkey" 10 | swapAddrFile="${tmpDir}twoWaySwap.addr" 11 | swapDatumFile="${tmpDir}swapDatum.json" 12 | swapRedeemerFile="${tmpDir}twoWaySpendingRedeemer.json" 13 | beaconRedeemerFile="${tmpDir}twoWayBeaconRedeemer.json" 14 | 15 | # The reference scripts are permanently locked in the swap address without a staking credential! 16 | # You can use the `cardano-swaps query personal-address` command to see them. 17 | beaconScriptPreprodTestnetRef="115c9ebb9928b8ec6e0c9d1420c43421cfb323639dd9fdcf1e7155e73bec13c5#1" 18 | # beaconScriptSize=4707 19 | 20 | spendingScriptPreprodTestnetRef="115c9ebb9928b8ec6e0c9d1420c43421cfb323639dd9fdcf1e7155e73bec13c5#0" 21 | # spendingScriptSize=5343 22 | 23 | # Generate the hash for the staking verification key. 24 | echo "Calculating the staking pubkey hash for the borrower..." 25 | ownerPubKeyHash=$(cardano-cli conway stake-address key-hash \ 26 | --stake-verification-key-file $ownerPubKeyFile) 27 | 28 | # Create the spending redeemer. 29 | echo "Creating the spending redeemer..." 30 | cardano-swaps spending-redeemers two-way \ 31 | --update-with-mint \ 32 | --out-file $swapRedeemerFile 33 | 34 | # Create the swap datum. 35 | echo "Creating the swap datum..." 36 | cardano-swaps datums two-way \ 37 | --first-asset lovelace \ 38 | --second-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 39 | --second-price 1000000 \ 40 | --first-price '1 / 1000000' \ 41 | --out-file $swapDatumFile 42 | 43 | # Helper beacon variables. 44 | echo "Calculating the beacon names..." 45 | beaconPolicyId=$(cardano-swaps beacon-info two-way policy-id \ 46 | --stdout) 47 | 48 | oldPairBeaconName=$(cardano-swaps beacon-info two-way pair-beacon \ 49 | --first-asset lovelace \ 50 | --second-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31 \ 51 | --stdout) 52 | 53 | oldAsset1BeaconName=$(cardano-swaps beacon-info two-way asset-beacon \ 54 | --first-asset lovelace \ 55 | --stdout) 56 | 57 | oldAsset2BeaconName=$(cardano-swaps beacon-info two-way asset-beacon \ 58 | --second-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31 \ 59 | --stdout) 60 | 61 | oldPairBeacon="${beaconPolicyId}.${oldPairBeaconName}" 62 | oldAsset1Beacon="${beaconPolicyId}.${oldAsset1BeaconName}" 63 | oldAsset2Beacon="${beaconPolicyId}.${oldAsset2BeaconName}" 64 | 65 | newPairBeaconName=$(cardano-swaps beacon-info two-way pair-beacon \ 66 | --first-asset lovelace \ 67 | --second-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 68 | --stdout) 69 | 70 | newAsset1BeaconName=$(cardano-swaps beacon-info two-way asset-beacon \ 71 | --first-asset lovelace \ 72 | --stdout) 73 | 74 | newAsset2BeaconName=$(cardano-swaps beacon-info two-way asset-beacon \ 75 | --second-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 76 | --stdout) 77 | 78 | newPairBeacon="${beaconPolicyId}.${newPairBeaconName}" 79 | newAsset1Beacon="${beaconPolicyId}.${newAsset1BeaconName}" 80 | newAsset2Beacon="${beaconPolicyId}.${newAsset2BeaconName}" 81 | 82 | # Create the beacon script redeemer. 83 | echo "Creating the minting redeemer..." 84 | cardano-swaps beacon-redeemers two-way \ 85 | --mint-or-burn \ 86 | --out-file $beaconRedeemerFile 87 | 88 | # Create the transaction. 89 | cardano-cli conway transaction build \ 90 | --tx-in 74a88e679036309f21154746ddc813c97f5d5bb0e4ebaa0244997ac13e44eb77#1 \ 91 | --tx-in 397ceab35a092814871ba5bf9a946a55508afee4edc26c8728caa53837b67fcf#1 \ 92 | --tx-in 74a88e679036309f21154746ddc813c97f5d5bb0e4ebaa0244997ac13e44eb77#0 \ 93 | --spending-tx-in-reference $spendingScriptPreprodTestnetRef \ 94 | --spending-plutus-script-v2 \ 95 | --spending-reference-tx-in-inline-datum-present \ 96 | --spending-reference-tx-in-redeemer-file $swapRedeemerFile \ 97 | --tx-out "$(cat ${swapAddrFile}) + 3000000 lovelace + 1 ${newPairBeacon} + 1 ${newAsset1Beacon} + 1 ${newAsset2Beacon} + 20 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a" \ 98 | --tx-out-inline-datum-file $swapDatumFile \ 99 | --tx-out "$(cat $HOME/wallets/01.addr) + 3000000 lovelace + 11 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31" \ 100 | --mint "-1 ${oldPairBeacon} + -1 ${oldAsset1Beacon} + -1 ${oldAsset2Beacon} + 1 ${newPairBeacon} + 1 ${newAsset1Beacon} + 1 ${newAsset2Beacon}" \ 101 | --mint-tx-in-reference $beaconScriptPreprodTestnetRef \ 102 | --mint-plutus-script-v2 \ 103 | --mint-reference-tx-in-redeemer-file $beaconRedeemerFile \ 104 | --policy-id "$beaconPolicyId" \ 105 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 106 | --change-address "$(cat $HOME/wallets/01.addr)" \ 107 | --required-signer-hash "$ownerPubKeyHash" \ 108 | --testnet-magic 1 \ 109 | --out-file "${tmpDir}tx.body" 110 | 111 | cardano-cli conway transaction sign \ 112 | --tx-body-file "${tmpDir}tx.body" \ 113 | --signing-key-file $HOME/wallets/01.skey \ 114 | --signing-key-file $HOME/wallets/01Stake.skey \ 115 | --testnet-magic 1 \ 116 | --out-file "${tmpDir}tx.signed" 117 | 118 | cardano-cli conway transaction submit \ 119 | --testnet-magic 1 \ 120 | --tx-file "${tmpDir}tx.signed" 121 | 122 | # Add a newline after the submission response. 123 | echo "" 124 | -------------------------------------------------------------------------------- /scripts/remote/one-way/register-beacon-script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # WARNING 4 | # It is no longer possible to register the beacon scripts as written since they do not allow 5 | # certificate executions. Prior to the conway error, scripts did not need to be executed to register 6 | # them. Now, they do. The beacon scripts for the current cardano-swaps version were registered prior 7 | # to the conway era. They cannot be de-registered. 8 | # 9 | # This template script is for explanatory purposes only based off the new conway era rules. 10 | 11 | # Variables 12 | tmpDir="/tmp/cardano-swaps/" 13 | 14 | # Make the tmpDir if it doesn't already exist. 15 | mkdir -p $tmpDir 16 | 17 | beaconScriptFile="${tmpDir}oneWayBeacons.plutus" 18 | beaconRedeemer="${tmpDir}registerOneWayBeacons.plutus" 19 | 20 | # The reference scripts are permanently locked in the swap address without a staking credential! 21 | # You can use the `cardano-swaps query personal-address` command to see them. 22 | beaconScriptPreprodTestnetRef="9fecc1d2cf99088facad02aeccbedb6a4f783965dc6c02bd04dc8b348e9a0858#1" 23 | beaconScriptSize=4432 24 | 25 | # Export the beacon script. 26 | echo "Exporting the beacon script..." 27 | cardano-swaps scripts one-way beacon-script \ 28 | --out-file $beaconScriptFile 29 | 30 | # Create the registration certificate 31 | cardano-cli conway stake-address registration-certificate \ 32 | --stake-script-file $beaconScriptFile \ 33 | --key-reg-deposit-amt 2000000 \ 34 | --out-file "${tmpDir}registration.cert" 35 | 36 | # Create the transaction. 37 | echo "Exporting the current protocol parameters..." 38 | cardano-swaps query protocol-params \ 39 | --testnet \ 40 | --out-file "${tmpDir}protocol.json" 41 | 42 | initial_change=$((59627618-2000000)) # registration requires 2 ADA deposit. 43 | 44 | echo "Building the initial transaction..." 45 | cardano-cli conway transaction build-raw \ 46 | --tx-in e39e1414f0ba51220be1e1a11b8379a3ef629ebb6bca8d4e11ad11076c762263#1 \ 47 | --tx-out "$(cat $HOME/wallets/01.addr) + $initial_change lovelace" \ 48 | --certificate-file "${tmpDir}registration.cert" \ 49 | --certificate-tx-in-reference $beaconScriptPreprodTestnetRef \ 50 | --certificate-plutus-script-v2 \ 51 | --certificate-reference-tx-in-redeemer-file $beaconRedeemer \ 52 | --certificate-reference-tx-in-execution-units "(0,0)" \ 53 | --protocol-params-file "${tmpDir}protocol.json" \ 54 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 55 | --tx-total-collateral 21000000 \ 56 | --tx-out-return-collateral "$(cat $HOME/wallets/01.addr) 21000000 lovelace" \ 57 | --fee 5000000 \ 58 | --out-file "${tmpDir}tx.body" 59 | 60 | echo "Getting the execution units estimations..." 61 | exec_units=$(cardano-swaps evaluate-tx \ 62 | --testnet \ 63 | --tx-file "${tmpDir}tx.body") 64 | 65 | # MAKE SURE THE INDEXES MATCH THE LEXICOGRAPHICAL ORDERING FOR INPUTS AND POLICY IDS. 66 | # You can use `cardano-cli debug transaction view --tx-file "${tmpDir}tx.body` to view the prior 67 | # transaction with everything in the correct order. 68 | cert_mem=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="certificate" and .validator.index==0) | .budget.memory' ) 69 | cert_steps=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="certificate" and .validator.index==0) | .budget.cpu' ) 70 | 71 | echo "Rebuilding the transaction with proper executions budgets..." 72 | cardano-cli conway transaction build-raw \ 73 | --tx-in e39e1414f0ba51220be1e1a11b8379a3ef629ebb6bca8d4e11ad11076c762263#1 \ 74 | --tx-out "$(cat $HOME/wallets/01.addr) + $initial_change lovelace" \ 75 | --certificate-file "${tmpDir}registration.cert" \ 76 | --certificate-tx-in-reference $beaconScriptPreprodTestnetRef \ 77 | --certificate-plutus-script-v2 \ 78 | --certificate-reference-tx-in-redeemer-file $beaconRedeemer \ 79 | --certificate-reference-tx-in-execution-units "(${cert_steps},${cert_mem})" \ 80 | --protocol-params-file "${tmpDir}protocol.json" \ 81 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 82 | --tx-total-collateral 21000000 \ 83 | --tx-out-return-collateral "$(cat $HOME/wallets/01.addr) 21000000 lovelace" \ 84 | --fee 5000000 \ 85 | --out-file "${tmpDir}tx.body" 86 | 87 | echo "Calculating the required fee..." 88 | calculated_fee=$(cardano-cli conway transaction calculate-min-fee \ 89 | --tx-body-file "${tmpDir}tx.body" \ 90 | --protocol-params-file "${tmpDir}protocol.json" \ 91 | --reference-script-size $((beaconScriptSize)) \ 92 | --witness-count 1 | cut -d' ' -f1) 93 | req_fee=$((calculated_fee+50000)) # Add 0.05 ADA to be safe since the fee must still be updated. 94 | req_collateral=$(printf %.0f $(echo "${req_fee}*1.5" | bc)) 95 | 96 | echo "Building the final transaction..." 97 | cardano-cli conway transaction build-raw \ 98 | --tx-in e39e1414f0ba51220be1e1a11b8379a3ef629ebb6bca8d4e11ad11076c762263#1 \ 99 | --tx-out "$(cat $HOME/wallets/01.addr) + $((initial_change-req_fee)) lovelace" \ 100 | --certificate-file "${tmpDir}registration.cert" \ 101 | --certificate-tx-in-reference $beaconScriptPreprodTestnetRef \ 102 | --certificate-plutus-script-v2 \ 103 | --certificate-reference-tx-in-redeemer-file $beaconRedeemer \ 104 | --certificate-reference-tx-in-execution-units "(${cert_steps},${cert_mem})" \ 105 | --protocol-params-file "${tmpDir}protocol.json" \ 106 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 107 | --tx-total-collateral $req_collateral \ 108 | --tx-out-return-collateral "$(cat $HOME/wallets/01.addr) $((21000000-$req_collateral)) lovelace" \ 109 | --fee $req_fee \ 110 | --out-file "${tmpDir}tx.body" 111 | 112 | echo "Signing the transaction..." 113 | cardano-cli conway transaction sign \ 114 | --tx-body-file "${tmpDir}tx.body" \ 115 | --signing-key-file $HOME/wallets/01.skey \ 116 | --testnet-magic 1 \ 117 | --out-file "${tmpDir}tx.signed" 118 | 119 | echo "Submitting the transaction..." 120 | cardano-swaps submit \ 121 | --testnet \ 122 | --tx-file "${tmpDir}tx.signed" 123 | 124 | # Add a newline after the submission response. 125 | echo "" 126 | -------------------------------------------------------------------------------- /scripts/remote/two-way/register-beacon-script.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # WARNING 4 | # It is no longer possible to register the beacon scripts as written since they do not allow 5 | # certificate executions. Prior to the conway error, scripts did not need to be executed to register 6 | # them. Now, they do. The beacon scripts for the current cardano-swaps version were registered prior 7 | # to the conway era. They cannot be de-registered. 8 | # 9 | # This template script is for explanatory purposes only based off the new conway era rules. 10 | 11 | # Variables 12 | tmpDir="/tmp/cardano-swaps/" 13 | 14 | # Make the tmpDir if it doesn't already exist. 15 | mkdir -p $tmpDir 16 | 17 | beaconScriptFile="${tmpDir}twoWayBeacons.plutus" 18 | beaconRedeemer="${tmpDir}registerTwoWayBeacons.plutus" 19 | 20 | # The reference scripts are permanently locked in the swap address without a staking credential! 21 | # You can use the `cardano-swaps query personal-address` command to see them. 22 | beaconScriptPreprodTestnetRef="115c9ebb9928b8ec6e0c9d1420c43421cfb323639dd9fdcf1e7155e73bec13c5#1" 23 | beaconScriptSize=4707 24 | 25 | # Export the beacon script. 26 | echo "Exporting the beacon script..." 27 | cardano-swaps scripts two-way beacon-script \ 28 | --out-file $beaconScriptFile 29 | 30 | # Create the registration certificate 31 | cardano-cli conway stake-address registration-certificate \ 32 | --stake-script-file $beaconScriptFile \ 33 | --key-reg-deposit-amt 2000000 \ 34 | --out-file "${tmpDir}registration.cert" 35 | 36 | # Create the transaction. 37 | echo "Exporting the current protocol parameters..." 38 | cardano-swaps query protocol-params \ 39 | --testnet \ 40 | --out-file "${tmpDir}protocol.json" 41 | 42 | initial_change=$((59627618-2000000)) # registration requires 2 ADA deposit. 43 | 44 | echo "Building the initial transaction..." 45 | cardano-cli conway transaction build-raw \ 46 | --tx-in e39e1414f0ba51220be1e1a11b8379a3ef629ebb6bca8d4e11ad11076c762263#1 \ 47 | --tx-out "$(cat $HOME/wallets/01.addr) + $initial_change lovelace" \ 48 | --certificate-file "${tmpDir}registration.cert" \ 49 | --certificate-tx-in-reference $beaconScriptPreprodTestnetRef \ 50 | --certificate-plutus-script-v2 \ 51 | --certificate-reference-tx-in-redeemer-file $beaconRedeemer \ 52 | --certificate-reference-tx-in-execution-units "(0,0)" \ 53 | --protocol-params-file "${tmpDir}protocol.json" \ 54 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 55 | --tx-total-collateral 21000000 \ 56 | --tx-out-return-collateral "$(cat $HOME/wallets/01.addr) 21000000 lovelace" \ 57 | --fee 5000000 \ 58 | --out-file "${tmpDir}tx.body" 59 | 60 | echo "Getting the execution units estimations..." 61 | exec_units=$(cardano-swaps evaluate-tx \ 62 | --testnet \ 63 | --tx-file "${tmpDir}tx.body") 64 | 65 | # MAKE SURE THE INDEXES MATCH THE LEXICOGRAPHICAL ORDERING FOR INPUTS AND POLICY IDS. 66 | # You can use `cardano-cli debug transaction view --tx-file "${tmpDir}tx.body` to view the prior 67 | # transaction with everything in the correct order. 68 | cert_mem=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="certificate" and .validator.index==0) | .budget.memory' ) 69 | cert_steps=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="certificate" and .validator.index==0) | .budget.cpu' ) 70 | 71 | echo "Rebuilding the transaction with proper executions budgets..." 72 | cardano-cli conway transaction build-raw \ 73 | --tx-in e39e1414f0ba51220be1e1a11b8379a3ef629ebb6bca8d4e11ad11076c762263#1 \ 74 | --tx-out "$(cat $HOME/wallets/01.addr) + $initial_change lovelace" \ 75 | --certificate-file "${tmpDir}registration.cert" \ 76 | --certificate-tx-in-reference $beaconScriptPreprodTestnetRef \ 77 | --certificate-plutus-script-v2 \ 78 | --certificate-reference-tx-in-redeemer-file $beaconRedeemer \ 79 | --certificate-reference-tx-in-execution-units "(${cert_steps},${cert_mem})" \ 80 | --protocol-params-file "${tmpDir}protocol.json" \ 81 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 82 | --tx-total-collateral 21000000 \ 83 | --tx-out-return-collateral "$(cat $HOME/wallets/01.addr) 21000000 lovelace" \ 84 | --fee 5000000 \ 85 | --out-file "${tmpDir}tx.body" 86 | 87 | echo "Calculating the required fee..." 88 | calculated_fee=$(cardano-cli conway transaction calculate-min-fee \ 89 | --tx-body-file "${tmpDir}tx.body" \ 90 | --protocol-params-file "${tmpDir}protocol.json" \ 91 | --reference-script-size $((beaconScriptSize)) \ 92 | --witness-count 1 | cut -d' ' -f1) 93 | req_fee=$((calculated_fee+50000)) # Add 0.05 ADA to be safe since the fee must still be updated. 94 | req_collateral=$(printf %.0f $(echo "${req_fee}*1.5" | bc)) 95 | 96 | echo "Building the final transaction..." 97 | cardano-cli conway transaction build-raw \ 98 | --tx-in e39e1414f0ba51220be1e1a11b8379a3ef629ebb6bca8d4e11ad11076c762263#1 \ 99 | --tx-out "$(cat $HOME/wallets/01.addr) + $((initial_change-req_fee)) lovelace" \ 100 | --certificate-file "${tmpDir}registration.cert" \ 101 | --certificate-tx-in-reference $beaconScriptPreprodTestnetRef \ 102 | --certificate-plutus-script-v2 \ 103 | --certificate-reference-tx-in-redeemer-file $beaconRedeemer \ 104 | --certificate-reference-tx-in-execution-units "(${cert_steps},${cert_mem})" \ 105 | --protocol-params-file "${tmpDir}protocol.json" \ 106 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 107 | --tx-total-collateral $req_collateral \ 108 | --tx-out-return-collateral "$(cat $HOME/wallets/01.addr) $((21000000-$req_collateral)) lovelace" \ 109 | --fee $req_fee \ 110 | --out-file "${tmpDir}tx.body" 111 | 112 | echo "Signing the transaction..." 113 | cardano-cli conway transaction sign \ 114 | --tx-body-file "${tmpDir}tx.body" \ 115 | --signing-key-file $HOME/wallets/01.skey \ 116 | --testnet-magic 1 \ 117 | --out-file "${tmpDir}tx.signed" 118 | 119 | echo "Submitting the transaction..." 120 | cardano-swaps submit \ 121 | --testnet \ 122 | --tx-file "${tmpDir}tx.signed" 123 | 124 | # Add a newline after the submission response. 125 | echo "" 126 | -------------------------------------------------------------------------------- /app/CLI/Types.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE StrictData #-} 2 | {-# LANGUAGE MultiParamTypeClasses #-} 3 | 4 | module CLI.Types where 5 | 6 | import Data.Aeson 7 | import Data.Text (Text) 8 | import Prettyprinter 9 | import Control.Monad (mzero) 10 | 11 | import CardanoSwaps.Utils 12 | import qualified CardanoSwaps.OneWaySwap as OneWay 13 | import qualified CardanoSwaps.TwoWaySwap as TwoWay 14 | 15 | data Command 16 | = ExportScript Script FilePath 17 | | CreateDatum InternalDatum FilePath 18 | | CreateSpendingRedeemer SpendingRedeemer FilePath 19 | | CreateMintingRedeemer MintingRedeemer FilePath 20 | | BeaconInfo BeaconInfo Output 21 | | Query Query 22 | | Submit Network Endpoint FilePath 23 | | EvaluateTx Network Endpoint FilePath 24 | 25 | data Script 26 | = OneWayBeaconScript 27 | | OneWaySwapScript 28 | | TwoWayBeaconScript 29 | | TwoWaySwapScript 30 | 31 | -- | This has all the info necessary to create the actual SwapDatums. 32 | data InternalDatum 33 | = InternalOneWaySwapDatum 34 | OfferAsset 35 | AskAsset 36 | PlutusRational -- ^ Swap price 37 | (Maybe TxOutRef) 38 | | InternalTwoWaySwapDatum 39 | TwoWayPair 40 | PlutusRational -- ^ ForwardSwap price. 41 | PlutusRational -- ^ reverseSwap price. 42 | (Maybe TxOutRef) 43 | 44 | data SpendingRedeemer 45 | = OneWaySpendingRedeemer OneWay.SwapRedeemer 46 | | TwoWaySpendingRedeemer InternalTwoWaySwapRedeemer 47 | 48 | data InternalTwoWaySwapRedeemer 49 | = KnownTwoWaySwapRedeemer TwoWay.SwapRedeemer 50 | | UnknownTwoWaySwapRedeemer OfferAsset AskAsset 51 | -- ^ For when the swap direction is unknown (eg, ForwardSwap vs ReverseSwap) 52 | 53 | data MintingRedeemer 54 | = OneWayMintingRedeemer OneWay.BeaconRedeemer 55 | | TwoWayMintingRedeemer TwoWay.BeaconRedeemer 56 | 57 | data BeaconInfo 58 | = OneWayPolicyId 59 | | OneWayOfferBeaconName OfferAsset 60 | | OneWayAskBeaconName AskAsset 61 | | OneWayPairBeaconName (OfferAsset,AskAsset) 62 | | TwoWayPolicyId 63 | | TwoWayAssetBeaconName AssetConfig 64 | | TwoWayPairBeaconName TwoWayPair 65 | 66 | -- | For when saving to file is optional 67 | data Output = Stdout | File FilePath 68 | 69 | data Network 70 | = PreProdTestnet 71 | | Mainnet 72 | 73 | data Endpoint 74 | = Koios 75 | 76 | newtype TxCBOR = TxCBOR Text 77 | 78 | instance FromJSON TxCBOR where 79 | parseJSON (Object o) = TxCBOR <$> o .: "cborHex" 80 | parseJSON _ = mzero 81 | 82 | data Format = JSON | Pretty | Plain 83 | 84 | newtype UserAddress = UserAddress Text 85 | deriving (Show,Eq) 86 | 87 | instance Pretty UserAddress where 88 | pretty (UserAddress addr) = pretty addr 89 | 90 | data Query 91 | = QueryOwnSwaps QueryOwnSwaps 92 | | QueryAllSwaps QueryAll 93 | | QueryPersonal Network Endpoint UserAddress Format Output 94 | -- | Query the current protocol parameters. 95 | | QueryParameters Network Output 96 | 97 | data QueryOwnSwaps 98 | = QueryOwnOneWaySwaps Network Endpoint UserAddress Format Output 99 | | QueryOwnOneWaySwapsByOffer Network Endpoint UserAddress OfferAsset Format Output 100 | | QueryOwnOneWaySwapsByAsk Network Endpoint UserAddress AskAsset Format Output 101 | | QueryOwnOneWaySwapsByTradingPair Network Endpoint UserAddress OfferAsset AskAsset Format Output 102 | | QueryOwnTwoWaySwaps Network Endpoint UserAddress Format Output 103 | | QueryOwnTwoWaySwapsByOffer Network Endpoint UserAddress AssetConfig Format Output 104 | | QueryOwnTwoWaySwapsByAsk Network Endpoint UserAddress AssetConfig Format Output 105 | | QueryOwnTwoWaySwapsByTradingPair Network Endpoint UserAddress TwoWayPair Format Output 106 | 107 | data QueryAll 108 | = QueryAllSwapsByOffer Network Endpoint OfferAsset Format Output 109 | | QueryAllSwapsByAsk Network Endpoint AskAsset Format Output 110 | | QueryAllSwapsByTradingPair Network Endpoint OfferAsset AskAsset Format Output 111 | 112 | data Asset = Asset 113 | { assetPolicyId :: Text 114 | , assetTokenName :: Text 115 | , assetQuantity :: Text 116 | } deriving (Show,Eq) 117 | 118 | instance Pretty Asset where 119 | pretty Asset{..} = 120 | if assetPolicyId == "" 121 | then pretty assetQuantity <+> pretty @Text "lovelace" 122 | else pretty assetQuantity <+> pretty (assetPolicyId <> "." <> assetTokenName) 123 | 124 | instance ToJSON Asset where 125 | toJSON Asset{..} = 126 | object [ "asset" .= if assetPolicyId == "lovelace" || assetPolicyId == "" 127 | then "lovelace" 128 | else assetPolicyId <> "." <> assetTokenName 129 | , "quantity" .= assetQuantity 130 | ] 131 | 132 | data PersonalUTxO = PersonalUTxO 133 | { personalTxHash :: Text 134 | , personalOutputIndex :: Integer 135 | , personalValue :: [Asset] 136 | , personalDatumHash :: Maybe Text 137 | , personalReferenceScriptHash :: Maybe Text 138 | } deriving (Show,Eq) 139 | 140 | instance Ord PersonalUTxO where 141 | (PersonalUTxO hash1 _ _ _ _) <= (PersonalUTxO hash2 _ _ _ _) = hash1 <= hash2 142 | 143 | instance ToJSON PersonalUTxO where 144 | toJSON PersonalUTxO{..} = 145 | object [ "tx_hash" .= personalTxHash 146 | , "output_index" .= personalOutputIndex 147 | , "reference_script_hash" .= personalReferenceScriptHash 148 | , "datum_hash" .= personalDatumHash 149 | , "assets" .= personalValue 150 | ] 151 | 152 | data SwapDatum 153 | = OneWayDatum OneWay.SwapDatum 154 | | TwoWayDatum TwoWay.SwapDatum 155 | deriving (Show) 156 | 157 | instance ToJSON SwapDatum where 158 | toJSON (OneWayDatum datum) = 159 | object [ "type" .= ("one-way" :: Text) 160 | , "datum" .= datum 161 | ] 162 | toJSON (TwoWayDatum datum) = 163 | object [ "type" .= ("two-way" :: Text) 164 | , "datum" .= datum 165 | ] 166 | 167 | -- | Type that captures all info a user needs to interact with available swaps. 168 | data SwapUTxO = SwapUTxO 169 | { swapAddress :: UserAddress 170 | , swapTxHash :: Text 171 | , swapOutputIndex :: Integer 172 | , swapValue :: [Asset] 173 | , swapDatum :: Maybe SwapDatum 174 | } deriving (Show) 175 | 176 | instance ToJSON SwapUTxO where 177 | toJSON SwapUTxO{swapAddress=(UserAddress addr),..} = 178 | object [ "swap_address" .= addr 179 | , "tx_hash" .= swapTxHash 180 | , "output_index" .= swapOutputIndex 181 | , "amount" .= swapValue 182 | , "swap_info" .= swapDatum 183 | ] 184 | 185 | -------------------------------------------------------------------------------- /src/CardanoSwaps/OneWaySwap.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE TemplateHaskell #-} 2 | {-# LANGUAGE StrictData #-} 3 | {-# LANGUAGE OverloadedStrings #-} 4 | {-# LANGUAGE RecordWildCards #-} 5 | 6 | module CardanoSwaps.OneWaySwap 7 | ( 8 | -- * On-Chain Data Types 9 | SwapDatum(..) 10 | , SwapRedeemer(..) 11 | , BeaconRedeemer(..) 12 | 13 | -- * Contracts 14 | , swapScript 15 | , swapValidatorHash 16 | , beaconScript 17 | , beaconCurrencySymbol 18 | 19 | -- * Beacon Names 20 | , genPairBeaconName 21 | , genOfferBeaconName 22 | , genAskBeaconName 23 | 24 | -- * Datums 25 | , genSwapDatum 26 | ) where 27 | 28 | import qualified PlutusTx 29 | import qualified PlutusTx.Prelude as PlutusTx 30 | import GHC.Generics (Generic) 31 | import qualified Data.Map as Map 32 | import Data.Aeson 33 | import qualified Plutus.Script.Utils.Scripts as PV2 34 | import qualified PlutusLedgerApi.V2 as PV2 35 | 36 | import CardanoSwaps.Utils 37 | import CardanoSwaps.Blueprints 38 | 39 | ------------------------------------------------- 40 | -- On-Chain Data Types 41 | ------------------------------------------------- 42 | data SwapDatum = SwapDatum 43 | { beaconId :: CurrencySymbol -- ^ `CurrencySymbol` for the `beaconScript`. 44 | , pairBeacon :: TokenName -- ^ The pair beacon's `TokenName` for this trading pair. 45 | , offerId :: CurrencySymbol -- ^ The `CurrencySymbol` for the offer asset. 46 | , offerName :: TokenName -- ^ The `TokenName` for the offer asset. 47 | , offerBeacon :: TokenName -- ^ The offer beacon's `TokenName`. 48 | , askId :: CurrencySymbol -- ^ The `CurrencySymbol` for the ask asset. 49 | , askName :: TokenName -- ^ The `TokenName` for the ask asset. 50 | , askBeacon :: TokenName -- ^ The ask beacon's `TokenName`. 51 | , swapPrice :: PlutusRational -- ^ The price to take the offer asset as a fraction (Ask/Offer). 52 | , prevInput :: Maybe TxOutRef -- ^ The corresponding swap input's output reference. 53 | } deriving (Generic,Show,Eq) 54 | 55 | instance ToJSON SwapDatum where 56 | toJSON SwapDatum{..} = 57 | object [ "beacon_id" .= show beaconId 58 | , "pair_beacon" .= showTokenName pairBeacon 59 | , "offer_id" .= show offerId 60 | , "offer_name" .= showTokenName offerName 61 | , "offer_beacon" .= showTokenName offerBeacon 62 | , "ask_id" .= show askId 63 | , "ask_name" .= showTokenName askName 64 | , "ask_beacon" .= showTokenName askBeacon 65 | , "price" .= swapPrice 66 | , "prev_input" .= prevInput 67 | ] 68 | 69 | data SwapRedeemer 70 | -- | Spend the swap as the owner using the beacon script as a minting policy. 71 | = SpendWithMint 72 | -- | Spend the swap as the owner using the beacon script as a staking validator. This is only 73 | -- for when no beacons need to be minted or burned in the transaction. 74 | | SpendWithStake 75 | -- | Take the offer asset and deposit the ask asset. 76 | | Swap 77 | deriving (Generic,Show) 78 | 79 | data BeaconRedeemer 80 | -- | Execute the beacon script as a minting policy. Used anytime beacons must be minted or burned. 81 | = CreateOrCloseSwaps 82 | -- | Execute the beacon script as a staking validtor. Used anytime beacons do not need to be 83 | -- minted or burned. 84 | | UpdateSwaps 85 | deriving (Generic,Show) 86 | 87 | PlutusTx.unstableMakeIsData ''SwapDatum 88 | PlutusTx.unstableMakeIsData ''SwapRedeemer 89 | PlutusTx.unstableMakeIsData ''BeaconRedeemer 90 | 91 | ------------------------------------------------- 92 | -- Contracts 93 | ------------------------------------------------- 94 | swapScript :: SerialisedScript 95 | swapScript = parseScriptFromCBOR $ blueprints Map.! "one_way_swap.swap_script" 96 | 97 | swapValidatorHash :: PV2.ValidatorHash 98 | swapValidatorHash = PV2.ValidatorHash $ PV2.getScriptHash $ scriptHash swapScript 99 | 100 | beaconScript :: SerialisedScript 101 | beaconScript = 102 | applyArguments 103 | (parseScriptFromCBOR $ blueprints Map.! "one_way_swap.beacon_script") 104 | [PlutusTx.toData swapValidatorHash] 105 | 106 | beaconCurrencySymbol :: PV2.CurrencySymbol 107 | beaconCurrencySymbol = PV2.CurrencySymbol $ PV2.getScriptHash $ scriptHash beaconScript 108 | 109 | ------------------------------------------------- 110 | -- Beacon Names 111 | ------------------------------------------------- 112 | -- | Generate the beacon asset name by hashing offer ++ ask. The policy id for 113 | -- ADA is set to "00". 114 | -- 115 | -- > sha2_256 ( offerId ++ offerName ++ askId ++ askName ) 116 | genPairBeaconName :: OfferAsset -> AskAsset -> TokenName 117 | genPairBeaconName (OfferAsset assetX) (AskAsset assetY) = 118 | let ((CurrencySymbol sym1',TokenName name1),(CurrencySymbol sym2',TokenName name2)) = 119 | (assetX,assetY) 120 | sym1 = 121 | if sym1' == "" 122 | then unsafeToBuiltinByteString "00" 123 | else sym1' 124 | sym2 = 125 | if sym2' == "" 126 | then unsafeToBuiltinByteString "00" 127 | else sym2' 128 | in TokenName $ PlutusTx.sha2_256 $ sym1 <> name1 <> sym2 <> name2 129 | 130 | -- | Generate the beacon asset name by hashing the offer asset policy id and name. 131 | -- 132 | -- > sha2_256 ( "01" ++ offerId ++ offerName ) 133 | genOfferBeaconName :: OfferAsset -> TokenName 134 | genOfferBeaconName (OfferAsset (CurrencySymbol sym,TokenName name)) = 135 | TokenName $ PlutusTx.sha2_256 $ unsafeToBuiltinByteString "01" <> sym <> name 136 | 137 | -- | Generate the beacon asset name by hashing the ask asset policy id and name. 138 | -- 139 | -- > sha2_256 ( "02" ++ askId ++ askName ) 140 | genAskBeaconName :: AskAsset -> TokenName 141 | genAskBeaconName (AskAsset (CurrencySymbol sym,TokenName name)) = 142 | TokenName $ PlutusTx.sha2_256 $ unsafeToBuiltinByteString "02" <> sym <> name 143 | 144 | ------------------------------------------------- 145 | -- Datums 146 | ------------------------------------------------- 147 | genSwapDatum :: OfferAsset -> AskAsset -> PlutusRational -> Maybe TxOutRef -> SwapDatum 148 | genSwapDatum o@(OfferAsset offerCfg) a@(AskAsset askCfg) price mPrev = 149 | SwapDatum 150 | { beaconId = beaconCurrencySymbol 151 | , pairBeacon = genPairBeaconName o a 152 | , offerId = fst offerCfg 153 | , offerName = snd offerCfg 154 | , offerBeacon = genOfferBeaconName o 155 | , askId = fst askCfg 156 | , askName = snd askCfg 157 | , askBeacon = genAskBeaconName a 158 | , swapPrice = price 159 | , prevInput = mPrev 160 | } 161 | -------------------------------------------------------------------------------- /Benchmarks/TwoWaySwap.md: -------------------------------------------------------------------------------- 1 | # Benchmarks (YMMV) 2 | 3 | The node emulator from [plutus-apps](https://github.com/input-output-hk/plutus-apps) was used to do 4 | all benchmarking tests. All scripts were used as reference scripts to get the best performance 5 | possible. 6 | 7 | - The universal swap spending script requires about 24 ADA to store on-chain. 8 | - The universal minting policy requires about 22 ADA to be stored on-chain. 9 | 10 | ## Creating swaps 11 | 12 | Each swap requires a mininum UTxO value of about 2 ADA. This is due to the current protocol 13 | parameters, however, this is desired since it helps prevent denial-of-service attacks for the 14 | beacon queries. 15 | 16 | #### All swaps are for the same trading pair. The trading pair was (native asset,ADA). 17 | | Number of Swaps Created | Tx Fee | Collateral Required | 18 | |:--:|:--:|:--:| 19 | | 1 | 0.289983 ADA | 0.434975 ADA | 20 | | 10 | 0.810030 ADA | 1.215045 ADA | 21 | | 20 | 1.387860 ADA | 2.081790 ADA | 22 | | 30 | 1.966042 ADA | 2.949063 ADA | 23 | | 32 | 2.023825 ADA | 3.035738 ADA | 24 | 25 | The maximum number of swaps that could be created was 32. 26 | 27 | #### All swaps are for different trading pairs. 28 | | Number of Swaps Created | Tx Fee | Collateral Required | 29 | |:--:|:--:|:--:| 30 | | 1 | 0.292235 ADA | 0.438353 ADA | 31 | | 5 | 0.550943 ADA | 0.826415 ADA | 32 | | 10 | 0.874526 ADA | 1.311789 ADA | 33 | | 15 | 1.198240 ADA | 1.797360 ADA | 34 | | 20 | 1.521955 ADA | 2.282933 ADA | 35 | | 25 | 1.845714 ADA | 2.768571 ADA | 36 | 37 | The maximum number of swaps that could be created was 25. 38 | 39 | 40 | 41 | ## Swap Assets 42 | Swaps are validated by checking each output in the transaction. The checks are essentially: 43 | 1) Does this output have the beacon from the input? 44 | 2) If "Yes" to (1), is this output locked at the address where the input comes from? 45 | 3) If "Yes" to (2), does this output have the proper datum for the corresponding output? 46 | 47 | #### Execute multiple swap UTxOs for the same trading pair and from the same address. 48 | | Number of Swaps | Tx Fee | Collateral Required | 49 | |:--:|:--:|:--:| 50 | | 1 | 0.239760 ADA | 0.359640 ADA | 51 | | 2 | 0.297693 ADA | 0.446540 ADA | 52 | | 3 | 0.356943 ADA | 0.535415 ADA | 53 | | 4 | 0.417423 ADA | 0.626135 ADA | 54 | | 5 | 0.479177 ADA | 0.718766 ADA | 55 | | 6 | 0.542204 ADA | 0.813306 ADA | 56 | | 7 | 0.606505 ADA | 0.909758 ADA | 57 | | 8 | 0.672079 ADA | 1.008119 ADA | 58 | | 9 | 0.738928 ADA | 1.108392 ADA | 59 | | 10 | 0.813077 ADA | 1.219616 ADA | 60 | | 15 | 1.172791 ADA | 1.759187 ADA | 61 | | 20 | 1.570418 ADA | 2.355627 ADA | 62 | | 25 | 1.994078 ADA | 2.991117 ADA | 63 | 64 | The maximum number of swaps that could fit in the transaction was 25. 65 | 66 | #### Execute multiple swap UTxOs for the different trading pairs. 67 | | Number of Swaps | Tx Fee | Collateral Required | 68 | |:--:|:--:|:--:| 69 | | 1 | 0.272797 ADA | 0.409196 ADA | 70 | | 2 | 0.332174 ADA | 0.498261 ADA | 71 | | 3 | 0.392825 ADA | 0.589238 ADA | 72 | | 4 | 0.454749 ADA | 0.682124 ADA | 73 | | 5 | 0.517948 ADA | 0.776922 ADA | 74 | | 6 | 0.582419 ADA | 0.873629 ADA | 75 | | 7 | 0.648165 ADA | 0.972248 ADA | 76 | | 8 | 0.715184 ADA | 1.072776 ADA | 77 | | 9 | 0.783476 ADA | 1.175214 ADA | 78 | | 10 | 0.853131 ADA | 1.279697 ADA | 79 | | 15 | 1.220507 ADA | 1.830761 ADA | 80 | | 20 | 1.619725 ADA | 2.429588 ADA | 81 | | 25 | 2.051048 ADA | 3.076572 ADA | 82 | 83 | The maximum number of swaps that could fit in the transaction was 25. 84 | 85 | 86 | 87 | ## Closing swaps 88 | #### Closing swaps for the same trading pair. 89 | | Number Closed | Tx Fee | Collateral Required | 90 | |:--:|:--:|:--:| 91 | | 1 | 0.200986 ADA | 0.301479 ADA | 92 | | 10 | 0.347039 ADA | 0.520559 ADA | 93 | | 20 | 0.554603 ADA | 0.831905 ADA | 94 | | 30 | 0.810590 ADA | 1.215885 ADA | 95 | | 40 | 1.114472 ADA | 1.671708 ADA | 96 | | 50 | 1.465852 ADA | 2.198778 ADA | 97 | | 55 | 1.604203 ADA | 2.406305 ADA | 98 | 99 | The maximum number of swaps that could be closed in the transaction was 55. 100 | 101 | #### Closing swaps for different trading pairs. 102 | | Number Closed | Tx Fee | Collateral Required | 103 | |:--:|:--:|:--:| 104 | | 1 | 0.198565 ADA | 0.297848 ADA | 105 | | 10 | 0.358720 ADA | 0.538080 ADA | 106 | | 20 | 0.581906 ADA | 0.872859 ADA | 107 | | 30 | 0.853206 ADA | 1.279809 ADA | 108 | | 40 | 1.172268 ADA | 1.758402 ADA | 109 | | 50 | 1.539049 ADA | 2.308574 ADA | 110 | | 55 | 1.752569 ADA | 2.628854 ADA | 111 | 112 | The maximum number of swaps that could be closed in the transaction was 55. 113 | 114 | 115 | 116 | ## Updating swap prices 117 | #### Updating swaps for the same trading pair. 118 | | Number Updated | Tx Fee | Collateral Required | 119 | |:--:|:--:|:--:| 120 | | 1 | 0.202881 ADA | 0.304322 ADA | 121 | | 5 | 0.473208 ADA | 0.709812 ADA | 122 | | 10 | 0.821743 ADA | 1.232615 ADA | 123 | | 15 | 1.182208 ADA | 1.773312 ADA | 124 | | 20 | 1.554603 ADA | 2.331905 ADA | 125 | | 25 | 1.897395 ADA | 2.846093 ADA | 126 | | 29 | 2.031634 ADA | 3.047451 ADA | 127 | 128 | The maximum number of swaps that could be updated in the transaction was 29. 129 | 130 | #### Updating swaps for different trading pairs. 131 | | Number Updated | Tx Fee | Collateral Required | 132 | |:--:|:--:|:--:| 133 | | 1 | 0.200459 ADA | 0.300689 ADA | 134 | | 5 | 0.454681 ADA | 0.682022 ADA | 135 | | 10 | 0.783085 ADA | 1.174628 ADA | 136 | | 15 | 1.123418 ADA | 1.685127 ADA | 137 | | 20 | 1.475681 ADA | 2.213522 ADA | 138 | | 25 | 1.840094 ADA | 2.760141 ADA | 139 | | 30 | 1.973048 ADA | 2.959572 ADA | 140 | 141 | The maximum number of swaps that could be updated in the transaction was 30. 142 | 143 | 144 | 145 | ## Changing Swap Trading Pair 146 | By composing both the `CreateOrCloseSwaps` minting redeemer and the `SpendWithMint` spending 147 | redeemer, it is possible change what trading pair a swap is for in a single transaction (ie, you do 148 | not need to first close the swap in one tx and then open the new swap in another tx). 149 | 150 | Since there are many different scenarios that are possible, instead of testing all of them only the 151 | worst possible scenario was benchmarked. All other scenarios should have better performance. If 152 | you are aware of an even worse scenario, please open an issue so its benchmarks can be added. 153 | 154 | #### All swaps start as different trading pairs and end as different trading pairs. 155 | | Number Updated | Tx Fee | Collateral Required | 156 | |:--:|:--:|:--:| 157 | | 1 | 0.257566 ADA | 0.386349 ADA | 158 | | 5 | 0.536339 ADA | 0.804509 ADA | 159 | | 10 | 0.895587 ADA | 1.343381 ADA | 160 | | 15 | 1.266721 ADA | 1.900082 ADA | 161 | | 20 | 1.649784 ADA | 2.474676 ADA | 162 | | 25 | 1.835465 ADA | 2.753198 ADA | 163 | | 26 | 1.908041 ADA | 2.862062 ADA | 164 | 165 | The maximum number of swaps that could be updated in the transaction was 26. 166 | -------------------------------------------------------------------------------- /Benchmarks/OneWaySwap.md: -------------------------------------------------------------------------------- 1 | # Benchmarks (YMMV) 2 | 3 | The node emulator from [plutus-apps](https://github.com/input-output-hk/plutus-apps) was used to do 4 | all benchmarking tests. All scripts were used as reference scripts to get the best performance 5 | possible. 6 | 7 | - The universal swap spending script requires about 22 ADA to store on-chain. 8 | - The universal minting policy requires about 20 ADA to be stored on-chain. 9 | 10 | ## Creating swaps 11 | 12 | Each swap requires a mininum UTxO value of about 2 ADA. This is due to the current protocol 13 | parameters, however, this is desired since it helps prevent denial-of-service attacks for the 14 | beacon queries. 15 | 16 | #### All swaps are for the same trading pair. The trading pair was (native asset,ADA). 17 | | Number of Swaps Created | Tx Fee | Collateral Required | 18 | |:--:|:--:|:--:| 19 | | 1 | 0.282218 ADA | 0.423327 ADA | 20 | | 10 | 0.732779 ADA | 1.099169 ADA | 21 | | 20 | 1.233402 ADA | 1.850103 ADA | 22 | | 30 | 1.734201 ADA | 2.601302 ADA | 23 | | 33 | 1.890636 ADA | 2.835954 ADA | 24 | 25 | The maximum number of swaps that could be created was 33. 26 | 27 | #### All swaps are for different trading pairs. 28 | | Number of Swaps Created | Tx Fee | Collateral Required | 29 | |:--:|:--:|:--:| 30 | | 1 | 0.283829 ADA | 0.425744 ADA | 31 | | 10 | 0.790601 ADA | 1.185902 ADA | 32 | | 20 | 1.254414 ADA | 2.031621 ADA | 33 | | 25 | 1.636365 ADA | 2.454548 ADA | 34 | 35 | The maximum number of swaps that could be created was 25. 36 | 37 | 38 | 39 | ## Swap Assets 40 | Swaps are validated by checking each output in the transaction. The checks are essentially: 41 | 1) Does this output have the beacon from the input? 42 | 2) If "Yes" to (1), is this output locked at the address where the input comes from? 43 | 3) If "Yes" to (2), does this output have the proper datum for the corresponding output? 44 | 45 | #### Execute multiple swap UTxOs for the same trading pair and from the same address. 46 | | Number of Swaps | Tx Fee | Collateral Required | 47 | |:--:|:--:|:--:| 48 | | 1 | 0.237237 ADA | 0.355856 ADA | 49 | | 2 | 0.292634 ADA | 0.438951 ADA | 50 | | 3 | 0.349335 ADA | 0.524003 ADA | 51 | | 4 | 0.407354 ADA | 0.610881 ADA | 52 | | 5 | 0.466433 ADA | 0.699650 ADA | 53 | | 6 | 0.526874 ADA | 0.790311 ADA | 54 | | 7 | 0.588575 ADA | 0.882863 ADA | 55 | | 8 | 0.651537 ADA | 0.977306 ADA | 56 | | 9 | 0.715761 ADA | 1.073642 ADA | 57 | | 10 | 0.787273 ADA | 1.180910 ADA | 58 | | 15 | 1.133608 ADA | 1.700412 ADA | 59 | | 20 | 1.517539 ADA | 2.276309 ADA | 60 | | 25 | 1.927185 ADA | 2.890778 ADA | 61 | | 26 | 2.012932 ADA | 3.019398 ADA | 62 | 63 | The maximum number of swaps that could fit in the transaction was 26. 64 | 65 | #### Execute multiple swap UTxOs for the different trading pairs. 66 | | Number of Swaps | Tx Fee | Collateral Required | 67 | |:--:|:--:|:--:| 68 | | 1 | 0.237237 ADA | 0.355856 ADA | 69 | | 2 | 0.292634 ADA | 0.438951 ADA | 70 | | 3 | 0.349335 ADA | 0.524003 ADA | 71 | | 4 | 0.407354 ADA | 0.610881 ADA | 72 | | 5 | 0.466433 ADA | 0.699650 ADA | 73 | | 6 | 0.526874 ADA | 0.790311 ADA | 74 | | 7 | 0.588575 ADA | 0.882863 ADA | 75 | | 8 | 0.651537 ADA | 0.977306 ADA | 76 | | 9 | 0.715761 ADA | 1.073642 ADA | 77 | | 10 | 0.787273 ADA | 1.180910 ADA | 78 | | 15 | 1.133608 ADA | 1.700412 ADA | 79 | | 20 | 1.517539 ADA | 2.276309 ADA | 80 | | 25 | 1.927185 ADA | 2.890778 ADA | 81 | | 26 | 2.012932 ADA | 3.019398 ADA | 82 | 83 | The maximum number of swaps that could fit in the transaction was 26. 84 | 85 | 86 | 87 | ## Closing swaps 88 | #### Closing swaps for the same trading pair. 89 | | Number Closed | Tx Fee | Collateral Required | 90 | |:--:|:--:|:--:| 91 | | 1 | 0.200986 ADA | 0.301479 ADA | 92 | | 10 | 0.347039 ADA | 0.520559 ADA | 93 | | 20 | 0.554603 ADA | 0.831905 ADA | 94 | | 30 | 0.810590 ADA | 1.215885 ADA | 95 | | 40 | 1.114472 ADA | 1.671708 ADA | 96 | | 50 | 1.465852 ADA | 2.198778 ADA | 97 | | 56 | 1.610740 ADA | 2.416110 ADA | 98 | 99 | The maximum number of swaps that could be closed in the transaction was 56. 100 | 101 | #### Closing swaps for different trading pairs. 102 | | Number Closed | Tx Fee | Collateral Required | 103 | |:--:|:--:|:--:| 104 | | 1 | 0.198565 ADA | 0.297848 ADA | 105 | | 10 | 0.358720 ADA | 0.538080 ADA | 106 | | 20 | 0.581906 ADA | 0.872859 ADA | 107 | | 30 | 0.853206 ADA | 1.279809 ADA | 108 | | 40 | 1.172268 ADA | 1.758402 ADA | 109 | | 50 | 1.539049 ADA | 2.308574 ADA | 110 | | 56 | 1.759106 ADA | 2.638659 ADA | 111 | 112 | The maximum number of swaps that could be closed in the transaction was 56. 113 | 114 | 115 | 116 | ## Updating swap prices 117 | #### Updating swaps for the same trading pair. 118 | | Number Updated | Tx Fee | Collateral Required | 119 | |:--:|:--:|:--:| 120 | | 1 | 0.201809 ADA | 0.302714 ADA | 121 | | 5 | 0.425520 ADA | 0.638280 ADA | 122 | | 10 | 0.715786 ADA | 1.073679 ADA | 123 | | 15 | 1.017981 ADA | 1.526972 ADA | 124 | | 20 | 1.332106 ADA | 1.998159 ADA | 125 | | 25 | 1.658381 ADA | 2.487572 ADA | 126 | | 30 | 2.002657 ADA | 3.003986 ADA | 127 | | 31 | 2.071729 ADA | 3.107594 ADA | 128 | 129 | The maximum number of swaps that could be updated in the transaction was 31. 130 | 131 | #### Updating swaps for different trading pairs. 132 | | Number Updated | Tx Fee | Collateral Required | 133 | |:--:|:--:|:--:| 134 | | 1 | 0.199632 ADA | 0.299448 ADA | 135 | | 5 | 0.406626 ADA | 0.609939 ADA | 136 | | 10 | 0.676344 ADA | 1.014516 ADA | 137 | | 15 | 0.958169 ADA | 1.437254 ADA | 138 | | 20 | 1.251923 ADA | 1.877885 ADA | 139 | | 25 | 1.557827 ADA | 2.336741 ADA | 140 | | 30 | 1.875660 ADA | 2.813490 ADA | 141 | | 32 | 2.006134 ADA | 3.009201 ADA | 142 | 143 | The maximum number of swaps that could be updated in the transaction was 32. 144 | 145 | 146 | 147 | ## Changing Swap Trading Pair 148 | By composing both the `CreateOrCloseSwaps` minting redeemer and the `SpendWithMint` spending 149 | redeemer, it is possible change what trading pair a swap is for in a single transaction (ie, you do 150 | not need to first close the swap in one tx and then open the new swap in another tx). 151 | 152 | Since there are many different scenarios that are possible, instead of testing all of them only the 153 | worst possible scenario was benchmarked. All other scenarios should have better performance. If you 154 | are aware of an even worse scenario, please open an issue so its benchmarks can be added. 155 | 156 | #### All swaps start as different trading pairs and end as different trading pairs. 157 | | Number Updated | Tx Fee | Collateral Required | 158 | |:--:|:--:|:--:| 159 | | 1 | 0.253238 ADA | 0.379857 ADA | 160 | | 5 | 0.515147 ADA | 0.772721 ADA | 161 | | 10 | 0.853314 ADA | 1.279971 ADA | 162 | | 15 | 1.203367 ADA | 1.805051 ADA | 163 | | 20 | 1.565349 ADA | 2.348024 ADA | 164 | | 25 | 1.939481 ADA | 2.909222 ADA | 165 | | 26 | 2.015739 ADA | 3.023609 ADA | 166 | 167 | The maximum number of swaps that could be updated in the transaction was 26. 168 | -------------------------------------------------------------------------------- /OrderBookExample.md: -------------------------------------------------------------------------------- 1 | # Order Book Example 2 | 3 | This document walks you through how to query the current order book for a given trading pair. To be 4 | programming language agnostic, it will only involve using the command line. Koios' free 5 | preproduction endpoints will be used. 6 | 7 | ## Target Order Book 8 | 9 | I'm going to assume you know what trading pair you want. You will need to know each assets' on-chain 10 | name (eg, policy ID and hexadecimal asset name). For this example, we will use ADA -> TestDJED (a 11 | test token I created using the always succeeding minting policy). These are their on-chain names: 12 | 13 | ```bash 14 | # ADA 15 | policy_id="" # The empty bytestring. 16 | asset_name="" # The empty bytestring. 17 | 18 | # TestDJED 19 | policy_id="c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d" 20 | asset_name="4f74686572546f6b656e0a" 21 | ``` 22 | 23 | ## One-Way Swaps 24 | 25 | One-Way swap beacons all have the same policy id: 26 | ```bash 27 | policy_id="47cec2a1404ed91fc31124f29db15dc1aae77e0617868bcef351b8fd" 28 | ``` 29 | 30 | We just need to derive the `asset_names`. According to the One-Way Swap specification, the asset 31 | name is: 32 | 33 | ```txt 34 | sha2_256( offer_id ++ offer_name ++ ask_id ++ ask_name ) 35 | 36 | But if ADA is part of the pair, replace it's policy id with "00". 37 | ``` 38 | 39 | So for the direction ADA -> TestDJED, ADA is the offer asset and TestDJED is the ask asset so the 40 | derivation is: 41 | 42 | ```txt 43 | sha2_256( "00" ++ "" ++ "c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d" ++ "4f74686572546f6b656e0a" ) 44 | ``` 45 | 46 | which simplifies to: 47 | 48 | ```txt 49 | sha2_256( "00c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d4f74686572546f6b656e0a" ) 50 | ``` 51 | 52 | Hashing this gives: `5e23340d7a9c22745a2f2f907c8c17a8962cfac2292a4cb1d3832b4b88cdee95` 53 | 54 | > [!IMPORTANT] 55 | > The input to the hashing algorithm must be hexadecimally encoded. The above pre-hash is already in 56 | > hexadecimal, but if you copy/paste it into the terminal it will likely be encoded as something 57 | > else. You can test it with this [website](https://emn178.github.io/online-tools/sha256.html), but 58 | > make sure to set the input encoding to 'Hex'. 59 | 60 | So the One-Way swap beacon for ADA -> TestDJED is: 61 | 62 | ```bash 63 | policy_id="47cec2a1404ed91fc31124f29db15dc1aae77e0617868bcef351b8fd" 64 | asset_name="5e23340d7a9c22745a2f2f907c8c17a8962cfac2292a4cb1d3832b4b88cdee95" 65 | ``` 66 | 67 | To determine the One-Way swap beacon name for the other direction (TestDJED -> ADA), you just need 68 | to switch which asset is the offer and the ask in the `sha2_256` hash formula. 69 | 70 | Here is the One-Way swap beacon for TestDJED -> ADA: 71 | 72 | ```bash 73 | policy_id="47cec2a1404ed91fc31124f29db15dc1aae77e0617868bcef351b8fd" 74 | asset_name="5e09a478610895febe6afe42db300dd3bb985f3ff2e26125dbd4bf966d473350" 75 | ``` 76 | 77 | Now to query the One-Way swaps, we can use [this Koios 78 | query](https://preprod.koios.rest/#post-/asset_utxos). We will need two separate queries, one for 79 | each direction: 80 | 81 | ```bash 82 | # ADA -> TestDJED 83 | curl -X POST "https://preprod.koios.rest/api/v1/asset_utxos" -H 'accept: application/json' -H 'content-type: application/json' -d '{"_asset_list":[["47cec2a1404ed91fc31124f29db15dc1aae77e0617868bcef351b8fd","5e23340d7a9c22745a2f2f907c8c17a8962cfac2292a4cb1d3832b4b88cdee95"]],"_extended":true}' 84 | 85 | # TestDJED -> ADA 86 | curl -X POST "https://preprod.koios.rest/api/v1/asset_utxos" -H 'accept: application/json' -H 'content-type: application/json' -d '{"_asset_list":[["47cec2a1404ed91fc31124f29db15dc1aae77e0617868bcef351b8fd","5e09a478610895febe6afe42db300dd3bb985f3ff2e26125dbd4bf966d473350"]],"_extended":true}' 87 | ``` 88 | 89 | ## Two-Way Swaps 90 | 91 | Two-way swaps can go in either direction as long as they have the required asset for that direction. 92 | But the process to query them is the same as with One-Way swaps. 93 | 94 | Two-Way swap beacons all have the same policy id: 95 | ```bash 96 | policy_id="84662c22dc5c0cadad7b2ebf9757ce9ea61dbd8fe64bc8c43c112a40" 97 | ``` 98 | 99 | Again, we just need to derive the `asset_names`. According to the Two-Way Swap specification, the asset 100 | name is: 101 | 102 | ```txt 103 | sha2_256( asset1_id ++ asset1_name ++ asset2_id ++ asset2_name ) 104 | 105 | Sort the two assets in the trading pair lexicographically: the smaller asset is asset1 and the 106 | larger one is asset2. 107 | 108 | If ADA is part of the pair, replace it's policy id with "00" AFTER SORTING. 109 | ``` 110 | 111 | So unlike with One-Way swaps, the beacons for Two-Way swaps is independent of the swap direction. 112 | Sorting ADA and TestDJED lexicographically results in ADA being `asset1` because the empty 113 | bytestring comes first. Thus, the equation to use is: 114 | 115 | ```txt 116 | sha2_256( "00" ++ "" ++ "c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d" ++ "4f74686572546f6b656e0a" ) 117 | ``` 118 | 119 | which simplifies to: 120 | 121 | ```txt 122 | sha2_256( "00c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d4f74686572546f6b656e0a" ) 123 | ``` 124 | 125 | Hashing this gives: `5e23340d7a9c22745a2f2f907c8c17a8962cfac2292a4cb1d3832b4b88cdee95` 126 | 127 | > [!IMPORTANT] 128 | > The input to the hashing algorithm must be hexadecimally encoded. The above pre-hash is already in 129 | > hexadecimal, but if you copy/paste it into the terminal it will likely be encoded as something 130 | > else. You can test it with this [website](https://emn178.github.io/online-tools/sha256.html), but 131 | > make sure to set the input encoding to 'Hex'. 132 | 133 | Finaly, the Two-Way swap beacon for ADA <--> TestDJED is: 134 | 135 | ```bash 136 | policy_id="84662c22dc5c0cadad7b2ebf9757ce9ea61dbd8fe64bc8c43c112a40" 137 | asset_name="5e23340d7a9c22745a2f2f907c8c17a8962cfac2292a4cb1d3832b4b88cdee95" 138 | ``` 139 | 140 | Now we just need to query it using the same Koios query as before. Here is the exact command: 141 | 142 | ```bash 143 | # ADA <--> TestDJED 144 | curl -X POST "https://preprod.koios.rest/api/v1/asset_utxos" -H 'accept: application/json' -H 'content-type: application/json' -d '{"_asset_list":[["84662c22dc5c0cadad7b2ebf9757ce9ea61dbd8fe64bc8c43c112a40","5e23340d7a9c22745a2f2f907c8c17a8962cfac2292a4cb1d3832b4b88cdee95"]],"_extended":true}' 145 | ``` 146 | 147 | ## Next Steps 148 | 149 | At this point, you should have all of the current open orders for the trading pair. You just need to 150 | filter out finished orders and organize them into a typical order book chart. 151 | 152 | > [!NOTE] 153 | > For filtering out empty orders, Koios actually allows filtering them out server-side. You just 154 | > need to augment the above queries slightly. The following query will only return UTxOs that 155 | > contain some of the native asset specified in the `cs.[]` part. 156 | > ```bash 157 | > curl -g -X POST -H "content-type: application/json" 'https://preprod.koios.rest/api/v1/asset_utxos?select=is_spent,asset_list&is_spent=eq.false&asset_list=cs.[{"policy_id":"c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d","asset_name":"4f74686572546f6b656e0a"}]' -d '{"_asset_list":[ ["84662c22dc5c0cadad7b2ebf9757ce9ea61dbd8fe64bc8c43c112a40","5e23340d7a9c22745a2f2f907c8c17a8962cfac2292a4cb1d3832b4b88cdee95"] ], "_extended": true }' 158 | > ``` 159 | -------------------------------------------------------------------------------- /app/CLI/Query.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE DataKinds #-} 2 | {-# LANGUAGE StrictData #-} 3 | 4 | module CLI.Query 5 | ( 6 | runQueryAllSwapsByOffer 7 | , runQueryAllSwapsByAsk 8 | , runQueryAllSwapsByTradingPair 9 | , runQueryOwnSwaps 10 | , runQueryOwnSwapsByBeacon 11 | , runQueryPersonalAddress 12 | , runSubmit 13 | , runEvaluateTx 14 | , runGetParams 15 | ) where 16 | 17 | import Servant.Client 18 | import Network.HTTP.Client hiding (responseBody) 19 | import Network.HTTP.Client.TLS 20 | import Control.Exception 21 | import qualified Data.ByteString.Lazy as LBS 22 | import Data.Aeson (decode,Value) 23 | 24 | import CLI.Query.Koios as Koios 25 | import CLI.Types 26 | import CardanoSwaps.Utils 27 | 28 | runQueryAllSwapsByTradingPair 29 | :: Network 30 | -> Endpoint 31 | -> OfferAsset 32 | -> AskAsset 33 | -> IO [SwapUTxO] 34 | runQueryAllSwapsByTradingPair network api offer ask = do 35 | manager' <- newManager tlsManagerSettings 36 | res <- case (network,api) of 37 | (PreProdTestnet,Koios) -> do 38 | let env = mkClientEnv manager' (BaseUrl Https "preprod.koios.rest" 443 "api/v1") 39 | runClientM (Koios.queryAllSwapsByTradingPair offer ask) env 40 | (Mainnet,Koios) -> do 41 | let env = mkClientEnv manager' (BaseUrl Https "api.koios.rest" 443 "api/v1") 42 | runClientM (Koios.queryAllSwapsByTradingPair offer ask) env 43 | case res of 44 | Right r -> return r 45 | Left err -> throw err 46 | 47 | runQueryAllSwapsByOffer 48 | :: Network 49 | -> Endpoint 50 | -> OfferAsset 51 | -> IO [SwapUTxO] 52 | runQueryAllSwapsByOffer network api offer = do 53 | manager' <- newManager tlsManagerSettings 54 | res <- case (network,api) of 55 | (PreProdTestnet,Koios) -> do 56 | let env = mkClientEnv manager' (BaseUrl Https "preprod.koios.rest" 443 "api/v1") 57 | runClientM (Koios.queryAllSwapsByOffer offer) env 58 | (Mainnet,Koios) -> do 59 | let env = mkClientEnv manager' (BaseUrl Https "api.koios.rest" 443 "api/v1") 60 | runClientM (Koios.queryAllSwapsByOffer offer) env 61 | case res of 62 | Right r -> return r 63 | Left err -> throw err 64 | 65 | runQueryAllSwapsByAsk 66 | :: Network 67 | -> Endpoint 68 | -> AskAsset 69 | -> IO [SwapUTxO] 70 | runQueryAllSwapsByAsk network api ask = do 71 | manager' <- newManager tlsManagerSettings 72 | res <- case (network,api) of 73 | (PreProdTestnet,Koios) -> do 74 | let env = mkClientEnv manager' (BaseUrl Https "preprod.koios.rest" 443 "api/v1") 75 | runClientM (Koios.queryAllSwapsByAsk ask) env 76 | (Mainnet,Koios) -> do 77 | let env = mkClientEnv manager' (BaseUrl Https "api.koios.rest" 443 "api/v1") 78 | runClientM (Koios.queryAllSwapsByAsk ask) env 79 | case res of 80 | Right r -> return r 81 | Left err -> throw err 82 | 83 | runQueryOwnSwaps 84 | :: Network 85 | -> Endpoint 86 | -> UserAddress 87 | -> IO [SwapUTxO] 88 | runQueryOwnSwaps network api addr = do 89 | manager' <- newManager tlsManagerSettings 90 | res <- case (network,api) of 91 | (PreProdTestnet,Koios) -> do 92 | let env = mkClientEnv manager' (BaseUrl Https "preprod.koios.rest" 443 "api/v1") 93 | runClientM (Koios.queryOwnSwaps addr) env 94 | (Mainnet,Koios) -> do 95 | let env = mkClientEnv manager' (BaseUrl Https "api.koios.rest" 443 "api/v1") 96 | runClientM (Koios.queryOwnSwaps addr) env 97 | case res of 98 | Right r -> return r 99 | Left err -> throw err 100 | 101 | runQueryOwnSwapsByBeacon 102 | :: Network 103 | -> Endpoint 104 | -> UserAddress 105 | -> CurrencySymbol 106 | -> TokenName 107 | -> IO [SwapUTxO] 108 | runQueryOwnSwapsByBeacon network api addr beaconId beaconName = do 109 | manager' <- newManager tlsManagerSettings 110 | res <- case (network,api) of 111 | (PreProdTestnet,Koios) -> do 112 | let env = mkClientEnv manager' (BaseUrl Https "preprod.koios.rest" 443 "api/v1") 113 | runClientM (Koios.queryOwnSwapsByBeacon addr beaconId beaconName) env 114 | (Mainnet,Koios) -> do 115 | let env = mkClientEnv manager' (BaseUrl Https "api.koios.rest" 443 "api/v1") 116 | runClientM (Koios.queryOwnSwapsByBeacon addr beaconId beaconName) env 117 | case res of 118 | Right r -> return r 119 | Left err -> throw err 120 | 121 | runQueryPersonalAddress :: Network -> Endpoint -> UserAddress -> IO [PersonalUTxO] 122 | runQueryPersonalAddress network api addr = do 123 | manager' <- newManager tlsManagerSettings 124 | res <- case (network,api) of 125 | (PreProdTestnet,Koios) -> do 126 | let env = mkClientEnv manager' (BaseUrl Https "preprod.koios.rest" 443 "api/v1") 127 | runClientM (Koios.queryPersonalAddress addr) env 128 | (Mainnet,Koios) -> do 129 | let env = mkClientEnv manager' (BaseUrl Https "api.koios.rest" 443 "api/v1") 130 | runClientM (Koios.queryPersonalAddress addr) env 131 | case res of 132 | Right r -> return r 133 | Left err -> throw err 134 | 135 | runSubmit :: Network -> Endpoint -> FilePath -> IO Value 136 | runSubmit network api txFile = do 137 | tx' <- decode @TxCBOR <$> LBS.readFile txFile 138 | case tx' of 139 | Nothing -> return "Failed to deserialise transaction file" 140 | Just tx -> do 141 | manager' <- newManager tlsManagerSettings 142 | res <- case (network,api) of 143 | (PreProdTestnet,Koios) -> do 144 | let env = mkClientEnv manager' (BaseUrl Https "preprod.koios.rest" 443 "api/v1/ogmios") 145 | runClientM (Koios.submitTx tx) env 146 | (Mainnet,Koios) -> do 147 | let env = mkClientEnv manager' (BaseUrl Https "api.koios.rest" 443 "api/v1/ogmios") 148 | runClientM (Koios.submitTx tx) env 149 | case res of 150 | Right r -> return r 151 | Left e@(FailureResponse _ err) -> case decode $ responseBody err of 152 | Just response -> return response 153 | Nothing -> throw e 154 | Left err -> throw err 155 | 156 | runEvaluateTx :: Network -> Endpoint -> FilePath -> IO Value 157 | runEvaluateTx network api txFile = do 158 | tx' <- decode @TxCBOR <$> LBS.readFile txFile 159 | case tx' of 160 | Nothing -> return "Failed to deserialise transaction file" 161 | Just tx -> do 162 | manager' <- newManager tlsManagerSettings 163 | res <- case (network,api) of 164 | (PreProdTestnet,Koios) -> do 165 | let env = mkClientEnv manager' (BaseUrl Https "preprod.koios.rest" 443 "api/v1/ogmios") 166 | runClientM (Koios.evaluateTx tx) env 167 | (Mainnet,Koios) -> do 168 | let env = mkClientEnv manager' (BaseUrl Https "api.koios.rest" 443 "api/v1/ogmios") 169 | runClientM (Koios.evaluateTx tx) env 170 | case res of 171 | Right r -> return r 172 | Left e@(FailureResponse _ err) -> case decode $ responseBody err of 173 | Just response -> return response 174 | Nothing -> throw e 175 | Left err -> throw err 176 | 177 | runGetParams :: Network -> IO Value 178 | runGetParams network = do 179 | manager' <- newManager tlsManagerSettings 180 | either throw return =<< case network of 181 | PreProdTestnet -> do 182 | let env = mkClientEnv manager' (BaseUrl Https "preprod.koios.rest" 443 "api/v1") 183 | runClientM Koios.getParams env 184 | Mainnet -> do 185 | let env = mkClientEnv manager' (BaseUrl Https "api.koios.rest" 443 "api/v1") 186 | runClientM Koios.getParams env 187 | -------------------------------------------------------------------------------- /src/CardanoSwaps/TwoWaySwap.hs: -------------------------------------------------------------------------------- 1 | {-# LANGUAGE TemplateHaskell #-} 2 | {-# LANGUAGE StrictData #-} 3 | {-# LANGUAGE RecordWildCards #-} 4 | {-# LANGUAGE OverloadedStrings #-} 5 | 6 | module CardanoSwaps.TwoWaySwap 7 | ( 8 | -- * On-Chain Data Types 9 | SwapDatum(..) 10 | , SwapRedeemer(..) 11 | , BeaconRedeemer(..) 12 | 13 | -- * Contracts 14 | , swapScript 15 | , swapValidatorHash 16 | , beaconScript 17 | , beaconCurrencySymbol 18 | 19 | -- * Beacon Names 20 | , genPairBeaconName 21 | , genAssetBeaconName 22 | 23 | -- * Datums 24 | , genSwapDatum 25 | 26 | -- * Helpers 27 | , getRequiredSwapDirection 28 | ) where 29 | 30 | import qualified PlutusTx 31 | import qualified PlutusTx.Prelude as PlutusTx 32 | import GHC.Generics (Generic) 33 | import qualified Data.Map as Map 34 | import Data.Aeson 35 | import qualified Plutus.Script.Utils.Scripts as PV2 36 | import qualified PlutusLedgerApi.V2 as PV2 37 | 38 | import CardanoSwaps.Utils 39 | import CardanoSwaps.Blueprints 40 | 41 | ------------------------------------------------- 42 | -- On-Chain Data Types 43 | ------------------------------------------------- 44 | data SwapDatum = SwapDatum 45 | { beaconId :: CurrencySymbol -- ^ `CurrencySymbol` for the `beaconScript`. 46 | , pairBeacon :: TokenName -- ^ The pair beacon's `TokenName` for this trading pair. 47 | , asset1Id :: CurrencySymbol -- ^ The `CurrencySymbol` for asset1. 48 | , asset1Name :: TokenName -- ^ The `TokenName` for asset1. 49 | , asset1Beacon :: TokenName -- ^ The asset beacon's `TokenName` for asset1. 50 | , asset2Id :: CurrencySymbol -- ^ The `CurrencySymbol` for asset2. 51 | , asset2Name :: TokenName -- ^ The `TokenName` for asset2. 52 | , asset2Beacon :: TokenName -- ^ The asset beacon's `TokenName` for asset2. 53 | , asset1Price :: PlutusRational -- ^ The price to take asset1 as a fraction (Asset2/Asset1). 54 | , asset2Price :: PlutusRational -- ^ The price to take asset2 as a fraction (Asset1/Asset2). 55 | , prevInput :: Maybe TxOutRef -- ^ The corresponding swap input's output reference. 56 | } deriving (Generic,Show,Eq) 57 | 58 | instance ToJSON SwapDatum where 59 | toJSON SwapDatum{..} = 60 | object [ "beacon_id" .= show beaconId 61 | , "pair_beacon" .= showTokenName pairBeacon 62 | , "asset1_id" .= show asset1Id 63 | , "asset1_name" .= showTokenName asset1Name 64 | , "asset1_beacon" .= showTokenName asset1Beacon 65 | , "asset2_id" .= show asset2Id 66 | , "asset2_name" .= showTokenName asset2Name 67 | , "asset2_beacon" .= showTokenName asset2Beacon 68 | , "asset1_price" .= asset1Price 69 | , "asset2_price" .= asset2Price 70 | , "prev_input" .= prevInput 71 | ] 72 | 73 | data SwapRedeemer 74 | -- | Spend the swap as the owner using the beacon script as a minting policy. 75 | = SpendWithMint 76 | -- | Spend the swap as the owner using the beacon script as a staking validator. This is only 77 | -- for when no beacons need to be minted or burned in the transaction. 78 | | SpendWithStake 79 | -- | Take asset1 and deposit asset2. 80 | | TakeAsset1 81 | -- | Take asset2 and deposit asset1. 82 | | TakeAsset2 83 | deriving (Generic,Show) 84 | 85 | data BeaconRedeemer 86 | -- | Execute the beacon script as a minting policy. Used anytime beacons must be minted or burned. 87 | = CreateOrCloseSwaps 88 | -- | Execute the beacon script as a staking validtor. Used anytime beacons do not need to be 89 | -- minted or burned. 90 | | UpdateSwaps 91 | deriving (Generic,Show) 92 | 93 | PlutusTx.unstableMakeIsData ''SwapDatum 94 | PlutusTx.unstableMakeIsData ''SwapRedeemer 95 | PlutusTx.unstableMakeIsData ''BeaconRedeemer 96 | 97 | ------------------------------------------------- 98 | -- Contracts 99 | ------------------------------------------------- 100 | swapScript :: SerialisedScript 101 | swapScript = parseScriptFromCBOR $ blueprints Map.! "two_way_swap.swap_script" 102 | 103 | swapValidatorHash :: PV2.ValidatorHash 104 | swapValidatorHash = PV2.ValidatorHash $ PV2.getScriptHash $ scriptHash swapScript 105 | 106 | beaconScript :: SerialisedScript 107 | beaconScript = 108 | applyArguments 109 | (parseScriptFromCBOR $ blueprints Map.! "two_way_swap.beacon_script") 110 | [PlutusTx.toData swapValidatorHash] 111 | 112 | beaconCurrencySymbol :: PV2.CurrencySymbol 113 | beaconCurrencySymbol = PV2.CurrencySymbol $ PV2.getScriptHash $ scriptHash beaconScript 114 | 115 | ------------------------------------------------- 116 | -- Beacon Names 117 | ------------------------------------------------- 118 | -- | Generate the beacon asset name by hashing asset1 ++ asset2. The trading pair is first 119 | -- sorted so that the beacon name is independent of the ordering. The policy id for 120 | -- ADA is set to "00" __after__ sorting. 121 | -- 122 | -- > sha2_256 ( asset1Id ++ asset1Name ++ asset2Id ++ asset2Name ) 123 | genPairBeaconName :: AssetConfig -> AssetConfig -> TokenName 124 | genPairBeaconName assetX assetY = 125 | let ((CurrencySymbol sym1',TokenName name1),(CurrencySymbol sym2',TokenName name2)) = 126 | if assetY < assetX then (assetY,assetX) else (assetX,assetY) 127 | sym1 = 128 | if sym1' == "" 129 | then unsafeToBuiltinByteString "00" 130 | else sym1' 131 | sym2 = 132 | if sym2' == "" 133 | then unsafeToBuiltinByteString "00" 134 | else sym2' 135 | in TokenName $ PlutusTx.sha2_256 $ sym1 <> name1 <> sym2 <> name2 136 | 137 | -- | Generate the beacon asset name by hashing the asset policy id and name. 138 | -- 139 | -- > sha2_256 ( assetId ++ assetName ) 140 | genAssetBeaconName :: AssetConfig -> TokenName 141 | genAssetBeaconName (CurrencySymbol sym,TokenName name) = 142 | TokenName $ PlutusTx.sha2_256 $ sym <> name 143 | 144 | ------------------------------------------------- 145 | -- Datums 146 | ------------------------------------------------- 147 | -- | Create the datum for a swap. The format should be: 148 | -- 149 | -- > genSwapDatum (firstAsset,secondAsset) firstPrice secondPrice mPrev 150 | -- 151 | -- Which asset is first or second does not matter; just make sure the 152 | -- first price corresponds to __taking__ the first asset and the second price 153 | -- corresponds to __taking__ the second asset. 154 | genSwapDatum :: TwoWayPair -> PlutusRational -> PlutusRational -> Maybe TxOutRef -> SwapDatum 155 | genSwapDatum (firstAsset,secondAsset) firstPrice secondPrice mPrev = 156 | let (asset1,asset2) = 157 | if firstAsset < secondAsset 158 | then (firstAsset,secondAsset) 159 | else (secondAsset,firstAsset) 160 | (asset1Price,asset2Price) = 161 | if asset1 == firstAsset 162 | then (firstPrice,secondPrice) 163 | else (secondPrice,firstPrice) 164 | in SwapDatum 165 | { beaconId = beaconCurrencySymbol 166 | , pairBeacon = genPairBeaconName asset1 asset2 167 | , asset1Id = fst asset1 168 | , asset1Name = snd asset1 169 | , asset1Beacon = genAssetBeaconName asset1 170 | , asset2Id = fst asset2 171 | , asset2Name = snd asset2 172 | , asset2Beacon = genAssetBeaconName asset2 173 | , asset1Price = asset1Price 174 | , asset2Price = asset2Price 175 | , prevInput = mPrev 176 | } 177 | 178 | ------------------------------------------------- 179 | -- Helpers 180 | ------------------------------------------------- 181 | -- | Get the required two-way swap redeemer based on the desired swap direction. 182 | getRequiredSwapDirection :: OfferAsset -> AskAsset -> SwapRedeemer 183 | getRequiredSwapDirection (OfferAsset offer) (AskAsset ask) 184 | | offer == min offer ask = TakeAsset1 185 | | otherwise = TakeAsset2 186 | -------------------------------------------------------------------------------- /scripts/remote/one-way/swap-assets.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Variables 4 | tmpDir="/tmp/cardano-swaps/" 5 | 6 | # Make the tmpDir if it doesn't already exist. 7 | mkdir -p $tmpDir 8 | 9 | swapAddr1="addr_test1zqql5djxthlrdcnvy87m7uswf0d0es9cdw6nvl72gcqj743ualkqngnmdz2w9mv60zuucq0sswtn6lq2lwxwez76x0aqv7yg2s" 10 | swapDatumFile1="${tmpDir}swapDatum1.json" 11 | swapRedeemerFile="${tmpDir}oneWaySpendingRedeemer.json" 12 | 13 | # The reference scripts are permanently locked in the swap address without a staking credential! 14 | # You can use the `cardano-swaps query personal-address` command to see them. 15 | spendingScriptPreprodTestnetRef="9fecc1d2cf99088facad02aeccbedb6a4f783965dc6c02bd04dc8b348e9a0858#0" 16 | spendingScriptSize=4842 17 | 18 | # Create the Swap redeemer. 19 | echo "Creating the spending redeemer..." 20 | cardano-swaps spending-redeemers one-way \ 21 | --swap \ 22 | --out-file $swapRedeemerFile 23 | 24 | # Create the swap datum. 25 | echo "Creating the swap datum..." 26 | cardano-swaps datums one-way \ 27 | --ask-asset lovelace \ 28 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31 \ 29 | --offer-price '1000000 / 1' \ 30 | --input-swap-ref 841f95b65531a8bfe076336a544b62466057848e039ea31e519e2c852add4090#0 \ 31 | --out-file $swapDatumFile1 32 | 33 | # Helper beacon variables. 34 | echo "Calculating the beacon names..." 35 | beaconPolicyId1=$(cardano-swaps beacon-info one-way policy-id \ 36 | --stdout) 37 | 38 | pairBeaconName1=$(cardano-swaps beacon-info one-way pair-beacon \ 39 | --ask-asset lovelace \ 40 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31 \ 41 | --stdout) 42 | 43 | offerBeaconName1=$(cardano-swaps beacon-info one-way offer-beacon \ 44 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31 \ 45 | --stdout) 46 | 47 | askBeaconName1=$(cardano-swaps beacon-info one-way ask-beacon \ 48 | --ask-asset lovelace \ 49 | --stdout) 50 | 51 | pairBeacon1="${beaconPolicyId1}.${pairBeaconName1}" 52 | offerBeacon1="${beaconPolicyId1}.${offerBeaconName1}" 53 | askBeacon1="${beaconPolicyId1}.${askBeaconName1}" 54 | 55 | # Create the transaction. 56 | echo "Exporting the current protocol parameters..." 57 | cardano-swaps query protocol-params \ 58 | --testnet \ 59 | --out-file "${tmpDir}protocol.json" 60 | 61 | initial_change=$((8976772040-5000000-3000000)) 62 | 63 | echo "Building the initial transaction..." 64 | cardano-cli conway transaction build-raw \ 65 | --tx-in 07b2177d87a3e1bcd41548bcf2dca24038dbf09865fae80bf0b511229bf7f2df#1 \ 66 | --tx-in 841f95b65531a8bfe076336a544b62466057848e039ea31e519e2c852add4090#0 \ 67 | --spending-tx-in-reference $spendingScriptPreprodTestnetRef \ 68 | --spending-plutus-script-v2 \ 69 | --spending-reference-tx-in-inline-datum-present \ 70 | --spending-reference-tx-in-redeemer-file $swapRedeemerFile \ 71 | --spending-reference-tx-in-execution-units "(0,0)" \ 72 | --tx-out "$(cat $HOME/wallets/02.addr) + 3000000 lovelace + 5 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31" \ 73 | --tx-out "${swapAddr1} + 8000000 lovelace + 1 ${pairBeacon1} + 1 ${offerBeacon1} + 1 ${askBeacon1} + 3 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31" \ 74 | --tx-out-inline-datum-file $swapDatumFile1 \ 75 | --tx-out "$(cat $HOME/wallets/02.addr) + ${initial_change} lovelace" \ 76 | --tx-in-collateral 11ed603b92e6164c6bb0c83e0f4d54a954976db7c39e2a82d3cbf70f098da1e0#0 \ 77 | --tx-total-collateral 21000000 \ 78 | --tx-out-return-collateral "$(cat $HOME/wallets/02.addr) 21000000 lovelace" \ 79 | --protocol-params-file "${tmpDir}protocol.json" \ 80 | --fee 5000000 \ 81 | --out-file "${tmpDir}tx.body" 82 | 83 | echo "Getting the execution units estimations..." 84 | exec_units=$(cardano-swaps evaluate-tx \ 85 | --testnet \ 86 | --tx-file "${tmpDir}tx.body") 87 | 88 | # MAKE SURE THE INDEXES MATCH THE LEXICOGRAPHICAL ORDERING FOR INPUTS AND POLICY IDS. 89 | # You can use `cardano-cli debug transaction view --tx-file "${tmpDir}tx.body` to view the prior 90 | # transaction with everything in the correct order. 91 | spend_0_mem=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="spend" and .validator.index==0) | .budget.memory' ) 92 | spend_0_steps=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="spend" and .validator.index==0) | .budget.cpu' ) 93 | 94 | echo "Rebuilding the transaction with proper execution budgets..." 95 | cardano-cli conway transaction build-raw \ 96 | --tx-in 07b2177d87a3e1bcd41548bcf2dca24038dbf09865fae80bf0b511229bf7f2df#1 \ 97 | --tx-in 841f95b65531a8bfe076336a544b62466057848e039ea31e519e2c852add4090#0 \ 98 | --spending-tx-in-reference $spendingScriptPreprodTestnetRef \ 99 | --spending-plutus-script-v2 \ 100 | --spending-reference-tx-in-inline-datum-present \ 101 | --spending-reference-tx-in-redeemer-file $swapRedeemerFile \ 102 | --spending-reference-tx-in-execution-units "(${spend_0_steps},${spend_0_mem})" \ 103 | --tx-out "$(cat $HOME/wallets/02.addr) + 3000000 lovelace + 5 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31" \ 104 | --tx-out "${swapAddr1} + 8000000 lovelace + 1 ${pairBeacon1} + 1 ${offerBeacon1} + 1 ${askBeacon1} + 3 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31" \ 105 | --tx-out-inline-datum-file $swapDatumFile1 \ 106 | --tx-out "$(cat $HOME/wallets/02.addr) + ${initial_change} lovelace" \ 107 | --tx-in-collateral 11ed603b92e6164c6bb0c83e0f4d54a954976db7c39e2a82d3cbf70f098da1e0#0 \ 108 | --tx-total-collateral 21000000 \ 109 | --tx-out-return-collateral "$(cat $HOME/wallets/02.addr) 21000000 lovelace" \ 110 | --protocol-params-file "${tmpDir}protocol.json" \ 111 | --fee 5000000 \ 112 | --out-file "${tmpDir}tx.body" 113 | 114 | echo "Calculating the required fee..." 115 | calculated_fee=$(cardano-cli conway transaction calculate-min-fee \ 116 | --tx-body-file "${tmpDir}tx.body" \ 117 | --protocol-params-file "${tmpDir}protocol.json" \ 118 | --reference-script-size $((spendingScriptSize)) \ 119 | --witness-count 2 | cut -d' ' -f1) 120 | req_fee=$((calculated_fee+50000)) # Add 0.05 ADA to be safe since the fee must still be updated. 121 | req_collateral=$(printf %.0f $(echo "${req_fee}*1.5" | bc)) 122 | 123 | echo "Rebuilding the transaction with the required fee..." 124 | cardano-cli conway transaction build-raw \ 125 | --tx-in 07b2177d87a3e1bcd41548bcf2dca24038dbf09865fae80bf0b511229bf7f2df#1 \ 126 | --tx-in 841f95b65531a8bfe076336a544b62466057848e039ea31e519e2c852add4090#0 \ 127 | --spending-tx-in-reference $spendingScriptPreprodTestnetRef \ 128 | --spending-plutus-script-v2 \ 129 | --spending-reference-tx-in-inline-datum-present \ 130 | --spending-reference-tx-in-redeemer-file $swapRedeemerFile \ 131 | --spending-reference-tx-in-execution-units "(${spend_0_steps},${spend_0_mem})" \ 132 | --tx-out "$(cat $HOME/wallets/02.addr) + 3000000 lovelace + 5 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31" \ 133 | --tx-out "${swapAddr1} + 8000000 lovelace + 1 ${pairBeacon1} + 1 ${offerBeacon1} + 1 ${askBeacon1} + 3 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31" \ 134 | --tx-out-inline-datum-file $swapDatumFile1 \ 135 | --tx-out "$(cat $HOME/wallets/02.addr) + $((initial_change-req_fee)) lovelace" \ 136 | --tx-in-collateral 11ed603b92e6164c6bb0c83e0f4d54a954976db7c39e2a82d3cbf70f098da1e0#0 \ 137 | --tx-total-collateral $req_collateral \ 138 | --tx-out-return-collateral "$(cat $HOME/wallets/02.addr) $((21000000-$req_collateral)) lovelace" \ 139 | --protocol-params-file "${tmpDir}protocol.json" \ 140 | --fee "$req_fee" \ 141 | --out-file "${tmpDir}tx.body" 142 | 143 | echo "Signing the transaction..." 144 | cardano-cli conway transaction sign \ 145 | --tx-body-file "${tmpDir}tx.body" \ 146 | --signing-key-file $HOME/wallets/02.skey \ 147 | --testnet-magic 1 \ 148 | --out-file "${tmpDir}tx.signed" 149 | 150 | echo "Submitting the transaction..." 151 | cardano-swaps submit \ 152 | --testnet \ 153 | --tx-file "${tmpDir}tx.signed" 154 | 155 | # Add a newline after the submission response. 156 | echo "" 157 | -------------------------------------------------------------------------------- /scripts/remote/one-way/create-swap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Variables 4 | tmpDir="/tmp/cardano-swaps/" 5 | 6 | # Make the tmpDir if it doesn't already exist. 7 | mkdir -p $tmpDir 8 | 9 | swapScriptFile="${tmpDir}oneWaySwap.plutus" # This is used to create the user's swap address. 10 | ownerPubKeyFile="$HOME/wallets/01Stake.vkey" 11 | swapAddrFile="${tmpDir}oneWaySwap.addr" 12 | swapDatumFile="${tmpDir}swapDatum.json" 13 | beaconRedeemerFile="${tmpDir}oneWayBeaconRedeemer.json" 14 | 15 | # The reference scripts are permanently locked in the swap address without a staking credential! 16 | # You can use the `cardano-swaps query personal-address` command to see them. 17 | beaconScriptPreprodTestnetRef="9fecc1d2cf99088facad02aeccbedb6a4f783965dc6c02bd04dc8b348e9a0858#1" 18 | beaconScriptSize=4432 19 | 20 | # Export the swap validator script. 21 | echo "Exporting the swap validator script..." 22 | cardano-swaps scripts one-way swap-script \ 23 | --out-file $swapScriptFile 24 | 25 | # Create the swap address. 26 | echo -n "Creating the swap address... " 27 | cardano-cli conway address build \ 28 | --payment-script-file $swapScriptFile \ 29 | --stake-verification-key-file $ownerPubKeyFile \ 30 | --testnet-magic 1 \ 31 | --out-file $swapAddrFile 32 | 33 | echo "$(cat $swapAddrFile)" 34 | 35 | # Helper beacon variables. 36 | echo "Calculating the beacon names..." 37 | beaconPolicyId=$(cardano-swaps beacon-info one-way policy-id \ 38 | --stdout) 39 | 40 | pairBeaconName=$(cardano-swaps beacon-info one-way pair-beacon \ 41 | --ask-asset lovelace \ 42 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 43 | --stdout) 44 | 45 | offerBeaconName=$(cardano-swaps beacon-info one-way offer-beacon \ 46 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 47 | --stdout) 48 | 49 | askBeaconName=$(cardano-swaps beacon-info one-way ask-beacon \ 50 | --ask-asset lovelace \ 51 | --stdout) 52 | 53 | pairBeacon="${beaconPolicyId}.${pairBeaconName}" 54 | offerBeacon="${beaconPolicyId}.${offerBeaconName}" 55 | askBeacon="${beaconPolicyId}.${askBeaconName}" 56 | 57 | # Get the beacon script redeemer. 58 | echo "Creating the minting redeemer..." 59 | cardano-swaps beacon-redeemers one-way \ 60 | --mint-or-burn \ 61 | --out-file $beaconRedeemerFile 62 | 63 | # Create the swap datum. 64 | echo "Creating the swap datum..." 65 | cardano-swaps datums one-way \ 66 | --ask-asset lovelace \ 67 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 68 | --offer-price '1000000 / 1' \ 69 | --out-file $swapDatumFile 70 | 71 | # Create the transaction. 72 | echo "Exporting the current protocol parameters..." 73 | cardano-swaps query protocol-params \ 74 | --testnet \ 75 | --out-file "${tmpDir}protocol.json" 76 | 77 | initial_change=$((21607098)) 78 | 79 | echo "Building the initial transaction..." 80 | cardano-cli conway transaction build-raw \ 81 | --tx-in e95a73a1e03afdf74b86d10e504b64285f7afdfab7f7021a41054ae4b377ca9f#1 \ 82 | --tx-in ee55fa696e5e7dd29dafef7c47e36e37207e88b0a120a1156a709c429fe08c8f#3 \ 83 | --tx-out "$(cat ${swapAddrFile}) + 3000000 lovelace + 1 ${pairBeacon} + 1 ${offerBeacon} + 1 ${askBeacon} + 3 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a" \ 84 | --tx-out-inline-datum-file $swapDatumFile \ 85 | --tx-out "$(cat $HOME/wallets/01.addr) + ${initial_change} lovelace " \ 86 | --mint "1 ${pairBeacon} + 1 ${offerBeacon} + 1 ${askBeacon}" \ 87 | --mint-tx-in-reference $beaconScriptPreprodTestnetRef \ 88 | --mint-plutus-script-v2 \ 89 | --mint-reference-tx-in-execution-units "(0,0)" \ 90 | --mint-reference-tx-in-redeemer-file $beaconRedeemerFile \ 91 | --policy-id "$beaconPolicyId" \ 92 | --protocol-params-file "${tmpDir}protocol.json" \ 93 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 94 | --tx-total-collateral 21000000 \ 95 | --tx-out-return-collateral "$(cat $HOME/wallets/01.addr) 21000000 lovelace" \ 96 | --fee 5000000 \ 97 | --out-file "${tmpDir}tx.body" 98 | 99 | echo "Getting the execution units estimations..." 100 | exec_units=$(cardano-swaps evaluate-tx \ 101 | --testnet \ 102 | --tx-file "${tmpDir}tx.body") 103 | 104 | # MAKE SURE THE INDEXES MATCH THE LEXICOGRAPHICAL ORDERING FOR INPUTS AND POLICY IDS. 105 | # You can use `cardano-cli debug transaction view --tx-file "${tmpDir}tx.body` to view the prior 106 | # transaction with everything in the correct order. 107 | mint_mem=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="mint" and .validator.index==0) | .budget.memory' ) 108 | mint_steps=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="mint" and .validator.index==0) | .budget.cpu' ) 109 | 110 | echo "Rebuilding the transaction with proper executions budgets..." 111 | cardano-cli conway transaction build-raw \ 112 | --tx-in e95a73a1e03afdf74b86d10e504b64285f7afdfab7f7021a41054ae4b377ca9f#1 \ 113 | --tx-in ee55fa696e5e7dd29dafef7c47e36e37207e88b0a120a1156a709c429fe08c8f#3 \ 114 | --tx-out "$(cat ${swapAddrFile}) + 3000000 lovelace + 1 ${pairBeacon} + 1 ${offerBeacon} + 1 ${askBeacon} + 3 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a" \ 115 | --tx-out-inline-datum-file $swapDatumFile \ 116 | --tx-out "$(cat $HOME/wallets/01.addr) + ${initial_change} lovelace " \ 117 | --mint "1 ${pairBeacon} + 1 ${offerBeacon} + 1 ${askBeacon}" \ 118 | --mint-tx-in-reference $beaconScriptPreprodTestnetRef \ 119 | --mint-plutus-script-v2 \ 120 | --mint-reference-tx-in-execution-units "(${mint_steps},${mint_mem})" \ 121 | --mint-reference-tx-in-redeemer-file $beaconRedeemerFile \ 122 | --policy-id "$beaconPolicyId" \ 123 | --protocol-params-file "${tmpDir}protocol.json" \ 124 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 125 | --tx-total-collateral 21000000 \ 126 | --tx-out-return-collateral "$(cat $HOME/wallets/01.addr) 21000000 lovelace" \ 127 | --fee 5000000 \ 128 | --out-file "${tmpDir}tx.body" 129 | 130 | echo "Calculating the required fee..." 131 | calculated_fee=$(cardano-cli conway transaction calculate-min-fee \ 132 | --tx-body-file "${tmpDir}tx.body" \ 133 | --protocol-params-file "${tmpDir}protocol.json" \ 134 | --reference-script-size $((beaconScriptSize)) \ 135 | --witness-count 1 | cut -d' ' -f1) 136 | req_fee=$((calculated_fee+50000)) # Add 0.05 ADA to be safe since the fee must still be updated. 137 | req_collateral=$(printf %.0f $(echo "${req_fee}*1.5" | bc)) 138 | 139 | echo "Rebuilding the transaction with proper transaction fee..." 140 | cardano-cli conway transaction build-raw \ 141 | --tx-in e95a73a1e03afdf74b86d10e504b64285f7afdfab7f7021a41054ae4b377ca9f#1 \ 142 | --tx-in ee55fa696e5e7dd29dafef7c47e36e37207e88b0a120a1156a709c429fe08c8f#3 \ 143 | --tx-out "$(cat ${swapAddrFile}) + 3000000 lovelace + 1 ${pairBeacon} + 1 ${offerBeacon} + 1 ${askBeacon} + 3 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a" \ 144 | --tx-out-inline-datum-file $swapDatumFile \ 145 | --tx-out "$(cat $HOME/wallets/01.addr) + $((initial_change-req_fee)) lovelace " \ 146 | --mint "1 ${pairBeacon} + 1 ${offerBeacon} + 1 ${askBeacon}" \ 147 | --mint-tx-in-reference $beaconScriptPreprodTestnetRef \ 148 | --mint-plutus-script-v2 \ 149 | --mint-reference-tx-in-execution-units "(${mint_steps},${mint_mem})" \ 150 | --mint-reference-tx-in-redeemer-file $beaconRedeemerFile \ 151 | --policy-id "$beaconPolicyId" \ 152 | --protocol-params-file "${tmpDir}protocol.json" \ 153 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 154 | --tx-total-collateral $req_collateral \ 155 | --tx-out-return-collateral "$(cat $HOME/wallets/01.addr) $((21000000-$req_collateral)) lovelace" \ 156 | --fee "$req_fee" \ 157 | --out-file "${tmpDir}tx.body" 158 | 159 | echo "Signing the transaction..." 160 | cardano-cli conway transaction sign \ 161 | --tx-body-file "${tmpDir}tx.body" \ 162 | --signing-key-file $HOME/wallets/01.skey \ 163 | --testnet-magic 1 \ 164 | --out-file "${tmpDir}tx.signed" 165 | 166 | echo "Submitting the transaction..." 167 | cardano-swaps submit \ 168 | --testnet \ 169 | --tx-file "${tmpDir}tx.signed" 170 | 171 | # Add a newline after the submission response. 172 | echo "" 173 | -------------------------------------------------------------------------------- /scripts/remote/two-way/swap-assets.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Variables 4 | tmpDir="/tmp/cardano-swaps/" 5 | 6 | # Make the tmpDir if it doesn't already exist. 7 | mkdir -p $tmpDir 8 | 9 | swapAddr1="addr_test1zzrns8ct7stw9kh8f97nlnvqsl8kw7eukje2aw3kak8c77fualkqngnmdz2w9mv60zuucq0sswtn6lq2lwxwez76x0aq3y05nq" 10 | swapDatumFile1="${tmpDir}swapDatum1.json" 11 | swapRedeemerFile="${tmpDir}twoWaySpendingRedeemer.json" 12 | 13 | # The reference scripts are permanently locked in the swap address without a staking credential! 14 | # You can use the `cardano-swaps query personal-address` command to see them. 15 | spendingScriptPreprodTestnetRef="115c9ebb9928b8ec6e0c9d1420c43421cfb323639dd9fdcf1e7155e73bec13c5#0" 16 | spendingScriptSize=5343 17 | 18 | # Create the Swap redeemer. 19 | echo "Creating the spending redeemer..." 20 | cardano-swaps spending-redeemers two-way \ 21 | --ask-asset lovelace \ 22 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31 \ 23 | --out-file $swapRedeemerFile 24 | 25 | # Create the swap datum. 26 | echo "Creating the swap datum..." 27 | cardano-swaps datums two-way \ 28 | --first-asset lovelace \ 29 | --second-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31 \ 30 | --first-price '1 / 1000000' \ 31 | --second-price 3000000 \ 32 | --input-swap-ref 1f4b5eaf864f57ad3ee4e58edd5bc955fa1315752b663f80719a67a5900f1b99#0 \ 33 | --out-file $swapDatumFile1 34 | 35 | # Helper beacon variables. 36 | echo "Calculating the beacon names..." 37 | beaconPolicyId1=$(cardano-swaps beacon-info two-way policy-id \ 38 | --stdout) 39 | 40 | pairBeaconName1=$(cardano-swaps beacon-info two-way pair-beacon \ 41 | --first-asset lovelace \ 42 | --second-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31 \ 43 | --stdout) 44 | 45 | asset1BeaconName1=$(cardano-swaps beacon-info two-way asset-beacon \ 46 | --first-asset lovelace \ 47 | --stdout) 48 | 49 | asset2BeaconName1=$(cardano-swaps beacon-info two-way asset-beacon \ 50 | --second-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31 \ 51 | --stdout) 52 | 53 | pairBeacon1="${beaconPolicyId1}.${pairBeaconName1}" 54 | asset1Beacon1="${beaconPolicyId1}.${asset1BeaconName1}" 55 | asset2Beacon1="${beaconPolicyId1}.${asset2BeaconName1}" 56 | 57 | # Create the transaction. 58 | echo "Exporting the current protocol parameters..." 59 | cardano-swaps query protocol-params \ 60 | --testnet \ 61 | --out-file "${tmpDir}protocol.json" 62 | 63 | initial_change=$((13079241-6000000-3000000)) 64 | 65 | echo "Building the initial transaction..." 66 | cardano-cli conway transaction build-raw \ 67 | --tx-in 0e8ade7c8cc42b1ab2c64ac5b2fa578adef42d46ba3ee3e0c52a3fd33af4bc65#0 \ 68 | --tx-in 1f4b5eaf864f57ad3ee4e58edd5bc955fa1315752b663f80719a67a5900f1b99#0 \ 69 | --spending-tx-in-reference $spendingScriptPreprodTestnetRef \ 70 | --spending-plutus-script-v2 \ 71 | --spending-reference-tx-in-inline-datum-present \ 72 | --spending-reference-tx-in-redeemer-file $swapRedeemerFile \ 73 | --spending-reference-tx-in-execution-units "(0,0)" \ 74 | --tx-out "$(cat $HOME/wallets/02.addr) + 3000000 lovelace + 2 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31" \ 75 | --tx-out "${swapAddr1} + 9000000 lovelace + 1 ${pairBeacon1} + 1 ${asset1Beacon1} + 1 ${asset2Beacon1} + 9 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31" \ 76 | --tx-out-inline-datum-file $swapDatumFile1 \ 77 | --tx-out "$(cat $HOME/wallets/02.addr) + ${initial_change} lovelace" \ 78 | --tx-in-collateral 11ed603b92e6164c6bb0c83e0f4d54a954976db7c39e2a82d3cbf70f098da1e0#0 \ 79 | --tx-total-collateral 21000000 \ 80 | --tx-out-return-collateral "$(cat $HOME/wallets/02.addr) 21000000 lovelace" \ 81 | --protocol-params-file "${tmpDir}protocol.json" \ 82 | --fee 5000000 \ 83 | --out-file "${tmpDir}tx.body" 84 | 85 | echo "Getting the execution units estimations..." 86 | exec_units=$(cardano-swaps evaluate-tx \ 87 | --testnet \ 88 | --tx-file "${tmpDir}tx.body") 89 | 90 | # MAKE SURE THE INDEXES MATCH THE LEXICOGRAPHICAL ORDERING FOR INPUTS AND POLICY IDS. 91 | # You can use `cardano-cli debug transaction view --tx-file "${tmpDir}tx.body` to view the prior 92 | # transaction with everything in the correct order. 93 | spend_0_mem=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="spend" and .validator.index==0) | .budget.memory' ) 94 | spend_0_steps=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="spend" and .validator.index==0) | .budget.cpu' ) 95 | 96 | echo "Rebuilding the transaction with proper execution budgets..." 97 | cardano-cli conway transaction build-raw \ 98 | --tx-in 0e8ade7c8cc42b1ab2c64ac5b2fa578adef42d46ba3ee3e0c52a3fd33af4bc65#0 \ 99 | --tx-in 1f4b5eaf864f57ad3ee4e58edd5bc955fa1315752b663f80719a67a5900f1b99#0 \ 100 | --spending-tx-in-reference $spendingScriptPreprodTestnetRef \ 101 | --spending-plutus-script-v2 \ 102 | --spending-reference-tx-in-inline-datum-present \ 103 | --spending-reference-tx-in-redeemer-file $swapRedeemerFile \ 104 | --spending-reference-tx-in-execution-units "(${spend_0_steps},${spend_0_mem})" \ 105 | --tx-out "$(cat $HOME/wallets/02.addr) + 3000000 lovelace + 2 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31" \ 106 | --tx-out "${swapAddr1} + 9000000 lovelace + 1 ${pairBeacon1} + 1 ${asset1Beacon1} + 1 ${asset2Beacon1} + 9 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31" \ 107 | --tx-out-inline-datum-file $swapDatumFile1 \ 108 | --tx-out "$(cat $HOME/wallets/02.addr) + ${initial_change} lovelace" \ 109 | --tx-in-collateral 11ed603b92e6164c6bb0c83e0f4d54a954976db7c39e2a82d3cbf70f098da1e0#0 \ 110 | --tx-total-collateral 21000000 \ 111 | --tx-out-return-collateral "$(cat $HOME/wallets/02.addr) 21000000 lovelace" \ 112 | --protocol-params-file "${tmpDir}protocol.json" \ 113 | --fee 5000000 \ 114 | --out-file "${tmpDir}tx.body" 115 | 116 | echo "Calculating the required fee..." 117 | calculated_fee=$(cardano-cli conway transaction calculate-min-fee \ 118 | --tx-body-file "${tmpDir}tx.body" \ 119 | --protocol-params-file "${tmpDir}protocol.json" \ 120 | --reference-script-size $((spendingScriptSize)) \ 121 | --witness-count 2 | cut -d' ' -f1) 122 | req_fee=$((calculated_fee+50000)) # Add 0.05 ADA to be safe since the fee must still be updated. 123 | req_collateral=$(printf %.0f $(echo "${req_fee}*1.5" | bc)) 124 | 125 | echo "Rebuilding the transaction with the required fee..." 126 | cardano-cli conway transaction build-raw \ 127 | --tx-in 0e8ade7c8cc42b1ab2c64ac5b2fa578adef42d46ba3ee3e0c52a3fd33af4bc65#0 \ 128 | --tx-in 1f4b5eaf864f57ad3ee4e58edd5bc955fa1315752b663f80719a67a5900f1b99#0 \ 129 | --spending-tx-in-reference $spendingScriptPreprodTestnetRef \ 130 | --spending-plutus-script-v2 \ 131 | --spending-reference-tx-in-inline-datum-present \ 132 | --spending-reference-tx-in-redeemer-file $swapRedeemerFile \ 133 | --spending-reference-tx-in-execution-units "(${spend_0_steps},${spend_0_mem})" \ 134 | --tx-out "$(cat $HOME/wallets/02.addr) + 3000000 lovelace + 2 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31" \ 135 | --tx-out "${swapAddr1} + 9000000 lovelace + 1 ${pairBeacon1} + 1 ${asset1Beacon1} + 1 ${asset2Beacon1} + 9 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31" \ 136 | --tx-out-inline-datum-file $swapDatumFile1 \ 137 | --tx-out "$(cat $HOME/wallets/02.addr) + $((initial_change-req_fee)) lovelace" \ 138 | --tx-in-collateral 11ed603b92e6164c6bb0c83e0f4d54a954976db7c39e2a82d3cbf70f098da1e0#0 \ 139 | --tx-total-collateral $req_collateral \ 140 | --tx-out-return-collateral "$(cat $HOME/wallets/02.addr) $((21000000-$req_collateral)) lovelace" \ 141 | --protocol-params-file "${tmpDir}protocol.json" \ 142 | --fee "$req_fee" \ 143 | --out-file "${tmpDir}tx.body" 144 | 145 | echo "Signing the transaction..." 146 | cardano-cli conway transaction sign \ 147 | --tx-body-file "${tmpDir}tx.body" \ 148 | --signing-key-file $HOME/wallets/02.skey \ 149 | --testnet-magic 1 \ 150 | --out-file "${tmpDir}tx.signed" 151 | 152 | echo "Submitting the transaction..." 153 | cardano-swaps submit \ 154 | --testnet \ 155 | --tx-file "${tmpDir}tx.signed" 156 | 157 | # Add a newline after the submission response. 158 | echo "" 159 | -------------------------------------------------------------------------------- /scripts/remote/two-way/create-swap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Variables 4 | tmpDir="/tmp/cardano-swaps/" 5 | 6 | # Make the tmpDir if it doesn't already exist. 7 | mkdir -p $tmpDir 8 | 9 | swapScriptFile="${tmpDir}twoWaySwap.plutus" # This is used to create the swap address. 10 | ownerPubKeyFile="$HOME/wallets/01Stake.vkey" 11 | swapAddrFile="${tmpDir}twoWaySwap.addr" 12 | swapDatumFile="${tmpDir}swapDatum.json" 13 | beaconRedeemerFile="${tmpDir}twoWayBeaconRedeemer.json" 14 | 15 | # The reference scripts are permanently locked in the swap address without a staking credential! 16 | # You can use the `cardano-swaps query personal-address` command to see them. 17 | beaconScriptPreprodTestnetRef="115c9ebb9928b8ec6e0c9d1420c43421cfb323639dd9fdcf1e7155e73bec13c5#1" 18 | beaconScriptSize=4707 19 | 20 | # Export the swap validator script. 21 | echo "Exporting the swap validator script..." 22 | cardano-swaps scripts two-way swap-script \ 23 | --out-file $swapScriptFile 24 | 25 | # Create the swap address. 26 | echo -n "Creating the swap address... " 27 | cardano-cli conway address build \ 28 | --payment-script-file $swapScriptFile \ 29 | --stake-verification-key-file $ownerPubKeyFile \ 30 | --testnet-magic 1 \ 31 | --out-file $swapAddrFile 32 | 33 | echo "$(cat $swapAddrFile)" 34 | 35 | # Helper beacon variables. 36 | echo "Calculating the beacon names..." 37 | beaconPolicyId=$(cardano-swaps beacon-info two-way policy-id \ 38 | --stdout) 39 | 40 | pairBeaconName=$(cardano-swaps beacon-info two-way pair-beacon \ 41 | --first-asset lovelace \ 42 | --second-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 43 | --stdout) 44 | 45 | asset1BeaconName=$(cardano-swaps beacon-info two-way asset-beacon \ 46 | --first-asset lovelace \ 47 | --stdout) 48 | 49 | asset2BeaconName=$(cardano-swaps beacon-info two-way asset-beacon \ 50 | --second-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 51 | --stdout) 52 | 53 | pairBeacon="${beaconPolicyId}.${pairBeaconName}" 54 | asset1Beacon="${beaconPolicyId}.${asset1BeaconName}" 55 | asset2Beacon="${beaconPolicyId}.${asset2BeaconName}" 56 | 57 | # Get the mint beacon redeemer. 58 | echo "Creating the minting redeemer..." 59 | cardano-swaps beacon-redeemers two-way \ 60 | --mint-or-burn \ 61 | --out-file $beaconRedeemerFile 62 | 63 | # Create the swap datum. 64 | echo "Creating the swap datum..." 65 | cardano-swaps datums two-way \ 66 | --first-asset lovelace \ 67 | --second-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 68 | --first-price '1 / 1000000' \ 69 | --second-price 2000000 \ 70 | --out-file $swapDatumFile 71 | 72 | # Create the transaction. 73 | echo "Exporting the current protocol parameters..." 74 | cardano-swaps query protocol-params \ 75 | --testnet \ 76 | --out-file "${tmpDir}protocol.json" 77 | 78 | initial_change=$((8179724933)) 79 | 80 | echo "Building the initial transaction..." 81 | cardano-cli conway transaction build-raw \ 82 | --tx-in ec243b6e5c3a1f7de6a0b0d75bf29247009e92596ac13f67b9176a70dcf96915#2 \ 83 | --tx-in d60f1f75bbfc267e47a04282da77821f99d343f8555afe18e70d151733c3ab36#1 \ 84 | --tx-out "$(cat ${swapAddrFile}) + 3000000 lovelace + 1 ${pairBeacon} + 1 ${asset1Beacon} + 1 ${asset2Beacon} + 20 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a" \ 85 | --tx-out-inline-datum-file $swapDatumFile \ 86 | --tx-out "$(cat $HOME/wallets/01.addr) + ${initial_change} lovelace " \ 87 | --mint "1 ${pairBeacon} + 1 ${asset1Beacon} + 1 ${asset2Beacon}" \ 88 | --mint-tx-in-reference $beaconScriptPreprodTestnetRef \ 89 | --mint-plutus-script-v2 \ 90 | --mint-reference-tx-in-execution-units "(0,0)" \ 91 | --mint-reference-tx-in-redeemer-file $beaconRedeemerFile \ 92 | --policy-id "$beaconPolicyId" \ 93 | --protocol-params-file "${tmpDir}protocol.json" \ 94 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 95 | --tx-total-collateral 21000000 \ 96 | --tx-out-return-collateral "$(cat $HOME/wallets/01.addr) 21000000 lovelace" \ 97 | --fee 5000000 \ 98 | --out-file "${tmpDir}tx.body" 99 | 100 | echo "Getting the execution units estimations..." 101 | exec_units=$(cardano-swaps evaluate-tx \ 102 | --testnet \ 103 | --tx-file "${tmpDir}tx.body") 104 | 105 | # MAKE SURE THE INDEXES MATCH THE LEXICOGRAPHICAL ORDERING FOR INPUTS AND POLICY IDS. 106 | # You can use `cardano-cli debug transaction view --tx-file "${tmpDir}tx.body` to view the prior 107 | # transaction with everything in the correct order. 108 | mint_mem=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="mint" and .validator.index==0) | .budget.memory' ) 109 | mint_steps=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="mint" and .validator.index==0) | .budget.cpu' ) 110 | 111 | echo "Rebuilding the transaction with proper executions budgets..." 112 | cardano-cli conway transaction build-raw \ 113 | --tx-in ec243b6e5c3a1f7de6a0b0d75bf29247009e92596ac13f67b9176a70dcf96915#2 \ 114 | --tx-in d60f1f75bbfc267e47a04282da77821f99d343f8555afe18e70d151733c3ab36#1 \ 115 | --tx-out "$(cat ${swapAddrFile}) + 3000000 lovelace + 1 ${pairBeacon} + 1 ${asset1Beacon} + 1 ${asset2Beacon} + 20 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a" \ 116 | --tx-out-inline-datum-file $swapDatumFile \ 117 | --tx-out "$(cat $HOME/wallets/01.addr) + ${initial_change} lovelace " \ 118 | --mint "1 ${pairBeacon} + 1 ${asset1Beacon} + 1 ${asset2Beacon}" \ 119 | --mint-tx-in-reference $beaconScriptPreprodTestnetRef \ 120 | --mint-plutus-script-v2 \ 121 | --mint-reference-tx-in-execution-units "(${mint_steps},${mint_mem})" \ 122 | --mint-reference-tx-in-redeemer-file $beaconRedeemerFile \ 123 | --policy-id "$beaconPolicyId" \ 124 | --protocol-params-file "${tmpDir}protocol.json" \ 125 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 126 | --tx-total-collateral 21000000 \ 127 | --tx-out-return-collateral "$(cat $HOME/wallets/01.addr) 21000000 lovelace" \ 128 | --fee 5000000 \ 129 | --out-file "${tmpDir}tx.body" 130 | 131 | echo "Calculating the required fee..." 132 | calculated_fee=$(cardano-cli conway transaction calculate-min-fee \ 133 | --tx-body-file "${tmpDir}tx.body" \ 134 | --protocol-params-file "${tmpDir}protocol.json" \ 135 | --reference-script-size $((beaconScriptSize)) \ 136 | --witness-count 1 | cut -d' ' -f1) 137 | req_fee=$((calculated_fee+50000)) # Add 0.05 ADA to be safe since the fee must still be updated. 138 | req_collateral=$(printf %.0f $(echo "${req_fee}*1.5" | bc)) 139 | 140 | echo "Rebuilding the transaction with proper transaction fee..." 141 | cardano-cli conway transaction build-raw \ 142 | --tx-in ec243b6e5c3a1f7de6a0b0d75bf29247009e92596ac13f67b9176a70dcf96915#2 \ 143 | --tx-in d60f1f75bbfc267e47a04282da77821f99d343f8555afe18e70d151733c3ab36#1 \ 144 | --tx-out "$(cat ${swapAddrFile}) + 3000000 lovelace + 1 ${pairBeacon} + 1 ${asset1Beacon} + 1 ${asset2Beacon} + 20 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a" \ 145 | --tx-out-inline-datum-file $swapDatumFile \ 146 | --tx-out "$(cat $HOME/wallets/01.addr) + $((initial_change-req_fee)) lovelace " \ 147 | --mint "1 ${pairBeacon} + 1 ${asset1Beacon} + 1 ${asset2Beacon}" \ 148 | --mint-tx-in-reference $beaconScriptPreprodTestnetRef \ 149 | --mint-plutus-script-v2 \ 150 | --mint-reference-tx-in-execution-units "(${mint_steps},${mint_mem})" \ 151 | --mint-reference-tx-in-redeemer-file $beaconRedeemerFile \ 152 | --policy-id "$beaconPolicyId" \ 153 | --protocol-params-file "${tmpDir}protocol.json" \ 154 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 155 | --tx-total-collateral $req_collateral \ 156 | --tx-out-return-collateral "$(cat $HOME/wallets/01.addr) $((21000000-$req_collateral)) lovelace" \ 157 | --fee "$req_fee" \ 158 | --out-file "${tmpDir}tx.body" 159 | 160 | echo "Signing the transaction..." 161 | cardano-cli conway transaction sign \ 162 | --tx-body-file "${tmpDir}tx.body" \ 163 | --signing-key-file $HOME/wallets/01.skey \ 164 | --testnet-magic 1 \ 165 | --out-file "${tmpDir}tx.signed" 166 | 167 | echo "Submitting the transaction..." 168 | cardano-swaps submit \ 169 | --testnet \ 170 | --tx-file "${tmpDir}tx.signed" 171 | 172 | # Add a newline after the submission response. 173 | echo "" 174 | -------------------------------------------------------------------------------- /scripts/remote/one-way/close-swap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Variables 4 | tmpDir="/tmp/cardano-swaps/" 5 | 6 | # Make the tmpDir if it doesn't already exist. 7 | mkdir -p $tmpDir 8 | 9 | ownerPubKeyFile="$HOME/wallets/01Stake.vkey" 10 | swapRedeemerFile="${tmpDir}oneWaySpendingRedeemer.json" 11 | beaconRedeemerFile="${tmpDir}oneWayBeaconRedeemer.json" 12 | 13 | # The reference scripts are permanently locked in the swap address without a staking credential! 14 | # You can use the `cardano-swaps query personal-address` command to see them. 15 | beaconScriptPreprodTestnetRef="9fecc1d2cf99088facad02aeccbedb6a4f783965dc6c02bd04dc8b348e9a0858#1" 16 | beaconScriptSize=4432 17 | 18 | spendingScriptPreprodTestnetRef="9fecc1d2cf99088facad02aeccbedb6a4f783965dc6c02bd04dc8b348e9a0858#0" 19 | spendingScriptSize=4842 20 | 21 | # Generate the hash for the staking verification key. 22 | echo "Calculating the staking pubkey hash for the borrower..." 23 | ownerPubKeyHash=$(cardano-cli conway stake-address key-hash \ 24 | --stake-verification-key-file $ownerPubKeyFile) 25 | 26 | # Create the spending redeemer. 27 | echo "Creating the spending redeemer..." 28 | cardano-swaps spending-redeemers one-way \ 29 | --close \ 30 | --out-file $swapRedeemerFile 31 | 32 | # Helper beacon variables. 33 | echo "Calculating the beacon names..." 34 | beaconPolicyId=$(cardano-swaps beacon-info one-way policy-id \ 35 | --stdout) 36 | 37 | pairBeaconName=$(cardano-swaps beacon-info one-way pair-beacon \ 38 | --ask-asset lovelace \ 39 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 40 | --stdout) 41 | 42 | offerBeaconName=$(cardano-swaps beacon-info one-way offer-beacon \ 43 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 44 | --stdout) 45 | 46 | askBeaconName=$(cardano-swaps beacon-info one-way ask-beacon \ 47 | --ask-asset lovelace \ 48 | --stdout) 49 | 50 | pairBeacon="${beaconPolicyId}.${pairBeaconName}" 51 | offerBeacon="${beaconPolicyId}.${offerBeaconName}" 52 | askBeacon="${beaconPolicyId}.${askBeaconName}" 53 | 54 | # Creating the beacon policy redeemer. 55 | echo "Creating the beacon policy redeemer..." 56 | cardano-swaps beacon-redeemers one-way \ 57 | --mint-or-burn \ 58 | --out-file $beaconRedeemerFile 59 | 60 | # Create the transaction. 61 | echo "Exporting the current protocol parameters..." 62 | cardano-swaps query protocol-params \ 63 | --testnet \ 64 | --out-file "${tmpDir}protocol.json" 65 | 66 | initial_change=$((21267609)) 67 | 68 | echo "Building the initial transaction..." 69 | cardano-cli conway transaction build-raw \ 70 | --tx-in e385b11dedde56156e1f206e38a1cdd61b39626dac9c796c64b7014de6171bc0#1 \ 71 | --tx-in e385b11dedde56156e1f206e38a1cdd61b39626dac9c796c64b7014de6171bc0#0 \ 72 | --spending-tx-in-reference $spendingScriptPreprodTestnetRef \ 73 | --spending-plutus-script-v2 \ 74 | --spending-reference-tx-in-inline-datum-present \ 75 | --spending-reference-tx-in-execution-units "(0,0)" \ 76 | --spending-reference-tx-in-redeemer-file $swapRedeemerFile \ 77 | --tx-out "$(cat $HOME/wallets/01.addr) + 3000000 lovelace + 3 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a" \ 78 | --tx-out "$(cat $HOME/wallets/01.addr) + ${initial_change} lovelace" \ 79 | --mint "-1 ${pairBeacon} + -1 ${offerBeacon} + -1 ${askBeacon}" \ 80 | --mint-tx-in-reference $beaconScriptPreprodTestnetRef \ 81 | --mint-plutus-script-v2 \ 82 | --mint-reference-tx-in-execution-units "(0,0)" \ 83 | --mint-reference-tx-in-redeemer-file $beaconRedeemerFile \ 84 | --policy-id "$beaconPolicyId" \ 85 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 86 | --tx-total-collateral 21000000 \ 87 | --tx-out-return-collateral "$(cat $HOME/wallets/01.addr) 21000000 lovelace" \ 88 | --required-signer-hash "$ownerPubKeyHash" \ 89 | --protocol-params-file "${tmpDir}protocol.json" \ 90 | --fee 5000000 \ 91 | --out-file "${tmpDir}tx.body" 92 | 93 | echo "Getting the execution units estimations..." 94 | exec_units=$(cardano-swaps evaluate-tx \ 95 | --testnet \ 96 | --tx-file "${tmpDir}tx.body") 97 | 98 | # MAKE SURE THE INDEXES MATCH THE LEXICOGRAPHICAL ORDERING FOR INPUTS AND POLICY IDS. 99 | # You can use `cardano-cli debug transaction view --tx-file "${tmpDir}tx.body` to view the prior 100 | # transaction with everything in the correct order. 101 | mint_mem=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="mint" and .validator.index==0) | .budget.memory' ) 102 | mint_steps=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="mint" and .validator.index==0) | .budget.cpu' ) 103 | spend_0_mem=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="spend" and .validator.index==0) | .budget.memory' ) 104 | spend_0_steps=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="spend" and .validator.index==0) | .budget.cpu' ) 105 | 106 | echo "Rebuilding the transaction with proper execution budgets..." 107 | cardano-cli conway transaction build-raw \ 108 | --tx-in e385b11dedde56156e1f206e38a1cdd61b39626dac9c796c64b7014de6171bc0#1 \ 109 | --tx-in e385b11dedde56156e1f206e38a1cdd61b39626dac9c796c64b7014de6171bc0#0 \ 110 | --spending-tx-in-reference $spendingScriptPreprodTestnetRef \ 111 | --spending-plutus-script-v2 \ 112 | --spending-reference-tx-in-inline-datum-present \ 113 | --spending-reference-tx-in-execution-units "(${spend_0_steps},${spend_0_mem})" \ 114 | --spending-reference-tx-in-redeemer-file $swapRedeemerFile \ 115 | --tx-out "$(cat $HOME/wallets/01.addr) + 3000000 lovelace + 3 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a" \ 116 | --tx-out "$(cat $HOME/wallets/01.addr) + ${initial_change} lovelace" \ 117 | --mint "-1 ${pairBeacon} + -1 ${offerBeacon} + -1 ${askBeacon}" \ 118 | --mint-tx-in-reference $beaconScriptPreprodTestnetRef \ 119 | --mint-plutus-script-v2 \ 120 | --mint-reference-tx-in-execution-units "(${mint_steps},${mint_mem})" \ 121 | --mint-reference-tx-in-redeemer-file $beaconRedeemerFile \ 122 | --policy-id "$beaconPolicyId" \ 123 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 124 | --tx-total-collateral 21000000 \ 125 | --tx-out-return-collateral "$(cat $HOME/wallets/01.addr) 21000000 lovelace" \ 126 | --required-signer-hash "$ownerPubKeyHash" \ 127 | --protocol-params-file "${tmpDir}protocol.json" \ 128 | --fee 5000000 \ 129 | --out-file "${tmpDir}tx.body" 130 | 131 | echo "Calculating the required fee..." 132 | calculated_fee=$(cardano-cli conway transaction calculate-min-fee \ 133 | --tx-body-file "${tmpDir}tx.body" \ 134 | --protocol-params-file "${tmpDir}protocol.json" \ 135 | --reference-script-size $((beaconScriptSize+spendingScriptSize)) \ 136 | --witness-count 2 | cut -d' ' -f1) 137 | req_fee=$((calculated_fee+50000)) # Add 0.05 ADA to be safe since the fee must still be updated. 138 | req_collateral=$(printf %.0f $(echo "${req_fee}*1.5" | bc)) 139 | 140 | echo "Rebuilding the transaction with the required fee..." 141 | cardano-cli conway transaction build-raw \ 142 | --tx-in e385b11dedde56156e1f206e38a1cdd61b39626dac9c796c64b7014de6171bc0#1 \ 143 | --tx-in e385b11dedde56156e1f206e38a1cdd61b39626dac9c796c64b7014de6171bc0#0 \ 144 | --spending-tx-in-reference $spendingScriptPreprodTestnetRef \ 145 | --spending-plutus-script-v2 \ 146 | --spending-reference-tx-in-inline-datum-present \ 147 | --spending-reference-tx-in-execution-units "(${spend_0_steps},${spend_0_mem})" \ 148 | --spending-reference-tx-in-redeemer-file $swapRedeemerFile \ 149 | --tx-out "$(cat $HOME/wallets/01.addr) + 3000000 lovelace + 3 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a" \ 150 | --tx-out "$(cat $HOME/wallets/01.addr) + $((initial_change-req_fee)) lovelace " \ 151 | --mint "-1 ${pairBeacon} + -1 ${offerBeacon} + -1 ${askBeacon}" \ 152 | --mint-tx-in-reference $beaconScriptPreprodTestnetRef \ 153 | --mint-plutus-script-v2 \ 154 | --mint-reference-tx-in-execution-units "(${mint_steps},${mint_mem})" \ 155 | --mint-reference-tx-in-redeemer-file $beaconRedeemerFile \ 156 | --policy-id "$beaconPolicyId" \ 157 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 158 | --tx-total-collateral $req_collateral \ 159 | --tx-out-return-collateral "$(cat $HOME/wallets/01.addr) $((21000000-$req_collateral)) lovelace" \ 160 | --required-signer-hash "$ownerPubKeyHash" \ 161 | --protocol-params-file "${tmpDir}protocol.json" \ 162 | --fee "$req_fee" \ 163 | --out-file "${tmpDir}tx.body" 164 | 165 | echo "Signing the transaction..." 166 | cardano-cli conway transaction sign \ 167 | --tx-body-file "${tmpDir}tx.body" \ 168 | --signing-key-file $HOME/wallets/01.skey \ 169 | --signing-key-file $HOME/wallets/01Stake.skey \ 170 | --testnet-magic 1 \ 171 | --out-file "${tmpDir}tx.signed" 172 | 173 | echo "Submitting the transaction..." 174 | cardano-swaps submit \ 175 | --testnet \ 176 | --tx-file "${tmpDir}tx.signed" 177 | 178 | # Add a newline after the submission response. 179 | echo "" 180 | -------------------------------------------------------------------------------- /scripts/remote/two-way/close-swap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Variables 4 | tmpDir="/tmp/cardano-swaps/" 5 | 6 | # Make the tmpDir if it doesn't already exist. 7 | mkdir -p $tmpDir 8 | 9 | ownerPubKeyFile="$HOME/wallets/01Stake.vkey" 10 | swapRedeemerFile="${tmpDir}twoWaySpendingRedeemer.json" 11 | beaconRedeemerFile="${tmpDir}twoWayBeaconRedeemer.json" 12 | 13 | # The reference scripts are permanently locked in the swap address without a staking credential! 14 | # You can use the `cardano-swaps query personal-address` command to see them. 15 | beaconScriptPreprodTestnetRef="115c9ebb9928b8ec6e0c9d1420c43421cfb323639dd9fdcf1e7155e73bec13c5#1" 16 | beaconScriptSize=4707 17 | 18 | spendingScriptPreprodTestnetRef="115c9ebb9928b8ec6e0c9d1420c43421cfb323639dd9fdcf1e7155e73bec13c5#0" 19 | spendingScriptSize=5343 20 | 21 | # Generate the hash for the staking verification key. 22 | echo "Calculating the staking pubkey hash for the borrower..." 23 | ownerPubKeyHash=$(cardano-cli conway stake-address key-hash \ 24 | --stake-verification-key-file $ownerPubKeyFile) 25 | 26 | # Create the spending redeemer. 27 | echo "Creating the spending redeemer..." 28 | cardano-swaps spending-redeemers two-way \ 29 | --close \ 30 | --out-file $swapRedeemerFile 31 | 32 | # Helper beacon variables. 33 | echo "Calculating the beacon names..." 34 | beaconPolicyId=$(cardano-swaps beacon-info two-way policy-id \ 35 | --stdout) 36 | 37 | pairBeaconName=$(cardano-swaps beacon-info two-way pair-beacon \ 38 | --first-asset lovelace \ 39 | --second-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31 \ 40 | --stdout) 41 | 42 | asset1BeaconName=$(cardano-swaps beacon-info two-way asset-beacon \ 43 | --first-asset lovelace \ 44 | --stdout) 45 | 46 | asset2BeaconName=$(cardano-swaps beacon-info two-way asset-beacon \ 47 | --second-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31 \ 48 | --stdout) 49 | 50 | pairBeacon="${beaconPolicyId}.${pairBeaconName}" 51 | asset1Beacon="${beaconPolicyId}.${asset1BeaconName}" 52 | asset2Beacon="${beaconPolicyId}.${asset2BeaconName}" 53 | 54 | # Creating the beacon policy redeemer. 55 | echo "Creating the beacon policy redeemer..." 56 | cardano-swaps beacon-redeemers two-way \ 57 | --mint-or-burn \ 58 | --out-file $beaconRedeemerFile 59 | 60 | # Create the transaction. 61 | echo "Exporting the current protocol parameters..." 62 | cardano-swaps query protocol-params \ 63 | --testnet \ 64 | --out-file "${tmpDir}protocol.json" 65 | 66 | initial_change=$((8179202411)) 67 | 68 | echo "Building the initial transaction..." 69 | cardano-cli conway transaction build-raw \ 70 | --tx-in 84e649f06340eb887663dd5211259367b27638f842778b14382359983130bfb2#1 \ 71 | --tx-in f3f408e7eb7ba2813ec6e13cc1c7bbe2448cab082e68b8fecd25de0b2e481be6#1 \ 72 | --spending-tx-in-reference $spendingScriptPreprodTestnetRef \ 73 | --spending-plutus-script-v2 \ 74 | --spending-reference-tx-in-inline-datum-present \ 75 | --spending-reference-tx-in-execution-units "(0,0)" \ 76 | --spending-reference-tx-in-redeemer-file $swapRedeemerFile \ 77 | --tx-out "$(cat $HOME/wallets/01.addr) + 9000000 lovelace + 9 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31" \ 78 | --tx-out "$(cat $HOME/wallets/01.addr) + ${initial_change} lovelace" \ 79 | --mint "-1 ${pairBeacon} + -1 ${asset1Beacon} + -1 ${asset2Beacon}" \ 80 | --mint-tx-in-reference $beaconScriptPreprodTestnetRef \ 81 | --mint-plutus-script-v2 \ 82 | --mint-reference-tx-in-execution-units "(0,0)" \ 83 | --mint-reference-tx-in-redeemer-file $beaconRedeemerFile \ 84 | --policy-id "$beaconPolicyId" \ 85 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 86 | --tx-total-collateral 21000000 \ 87 | --tx-out-return-collateral "$(cat $HOME/wallets/01.addr) 21000000 lovelace" \ 88 | --required-signer-hash "$ownerPubKeyHash" \ 89 | --protocol-params-file "${tmpDir}protocol.json" \ 90 | --fee 5000000 \ 91 | --out-file "${tmpDir}tx.body" 92 | 93 | echo "Getting the execution units estimations..." 94 | exec_units=$(cardano-swaps evaluate-tx \ 95 | --testnet \ 96 | --tx-file "${tmpDir}tx.body") 97 | 98 | # MAKE SURE THE INDEXES MATCH THE LEXICOGRAPHICAL ORDERING FOR INPUTS AND POLICY IDS. 99 | # You can use `cardano-cli debug transaction view --tx-file "${tmpDir}tx.body` to view the prior 100 | # transaction with everything in the correct order. 101 | mint_mem=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="mint" and .validator.index==0) | .budget.memory' ) 102 | mint_steps=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="mint" and .validator.index==0) | .budget.cpu' ) 103 | spend_0_mem=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="spend" and .validator.index==0) | .budget.memory' ) 104 | spend_0_steps=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="spend" and .validator.index==0) | .budget.cpu' ) 105 | 106 | echo "Rebuilding the transaction with proper execution budgets..." 107 | cardano-cli conway transaction build-raw \ 108 | --tx-in 84e649f06340eb887663dd5211259367b27638f842778b14382359983130bfb2#1 \ 109 | --tx-in f3f408e7eb7ba2813ec6e13cc1c7bbe2448cab082e68b8fecd25de0b2e481be6#1 \ 110 | --spending-tx-in-reference $spendingScriptPreprodTestnetRef \ 111 | --spending-plutus-script-v2 \ 112 | --spending-reference-tx-in-inline-datum-present \ 113 | --spending-reference-tx-in-execution-units "(${spend_0_steps},${spend_0_mem})" \ 114 | --spending-reference-tx-in-redeemer-file $swapRedeemerFile \ 115 | --tx-out "$(cat $HOME/wallets/01.addr) + 9000000 lovelace + 9 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31" \ 116 | --tx-out "$(cat $HOME/wallets/01.addr) + ${initial_change} lovelace" \ 117 | --mint "-1 ${pairBeacon} + -1 ${asset1Beacon} + -1 ${asset2Beacon}" \ 118 | --mint-tx-in-reference $beaconScriptPreprodTestnetRef \ 119 | --mint-plutus-script-v2 \ 120 | --mint-reference-tx-in-execution-units "(${mint_steps},${mint_mem})" \ 121 | --mint-reference-tx-in-redeemer-file $beaconRedeemerFile \ 122 | --policy-id "$beaconPolicyId" \ 123 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 124 | --tx-total-collateral 21000000 \ 125 | --tx-out-return-collateral "$(cat $HOME/wallets/01.addr) 21000000 lovelace" \ 126 | --required-signer-hash "$ownerPubKeyHash" \ 127 | --protocol-params-file "${tmpDir}protocol.json" \ 128 | --fee 5000000 \ 129 | --out-file "${tmpDir}tx.body" 130 | 131 | echo "Calculating the required fee..." 132 | calculated_fee=$(cardano-cli conway transaction calculate-min-fee \ 133 | --tx-body-file "${tmpDir}tx.body" \ 134 | --protocol-params-file "${tmpDir}protocol.json" \ 135 | --reference-script-size $((beaconScriptSize+spendingScriptSize)) \ 136 | --witness-count 2 | cut -d' ' -f1) 137 | req_fee=$((calculated_fee+50000)) # Add 0.05 ADA to be safe since the fee must still be updated. 138 | req_collateral=$(printf %.0f $(echo "${req_fee}*1.5" | bc)) 139 | 140 | echo "Rebuilding the transaction with the required fee..." 141 | cardano-cli conway transaction build-raw \ 142 | --tx-in 84e649f06340eb887663dd5211259367b27638f842778b14382359983130bfb2#1 \ 143 | --tx-in f3f408e7eb7ba2813ec6e13cc1c7bbe2448cab082e68b8fecd25de0b2e481be6#1 \ 144 | --spending-tx-in-reference $spendingScriptPreprodTestnetRef \ 145 | --spending-plutus-script-v2 \ 146 | --spending-reference-tx-in-inline-datum-present \ 147 | --spending-reference-tx-in-execution-units "(${spend_0_steps},${spend_0_mem})" \ 148 | --spending-reference-tx-in-redeemer-file $swapRedeemerFile \ 149 | --tx-out "$(cat $HOME/wallets/01.addr) + 9000000 lovelace + 9 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.54657374546f6b656e31" \ 150 | --tx-out "$(cat $HOME/wallets/01.addr) + $((initial_change-req_fee)) lovelace " \ 151 | --mint "-1 ${pairBeacon} + -1 ${asset1Beacon} + -1 ${asset2Beacon}" \ 152 | --mint-tx-in-reference $beaconScriptPreprodTestnetRef \ 153 | --mint-plutus-script-v2 \ 154 | --mint-reference-tx-in-execution-units "(${mint_steps},${mint_mem})" \ 155 | --mint-reference-tx-in-redeemer-file $beaconRedeemerFile \ 156 | --policy-id "$beaconPolicyId" \ 157 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 158 | --tx-total-collateral $req_collateral \ 159 | --tx-out-return-collateral "$(cat $HOME/wallets/01.addr) $((21000000-$req_collateral)) lovelace" \ 160 | --required-signer-hash "$ownerPubKeyHash" \ 161 | --protocol-params-file "${tmpDir}protocol.json" \ 162 | --fee "$req_fee" \ 163 | --out-file "${tmpDir}tx.body" 164 | 165 | echo "Signing the transaction..." 166 | cardano-cli conway transaction sign \ 167 | --tx-body-file "${tmpDir}tx.body" \ 168 | --signing-key-file $HOME/wallets/01.skey \ 169 | --signing-key-file $HOME/wallets/01Stake.skey \ 170 | --testnet-magic 1 \ 171 | --out-file "${tmpDir}tx.signed" 172 | 173 | echo "Submitting the transaction..." 174 | cardano-swaps submit \ 175 | --testnet \ 176 | --tx-file "${tmpDir}tx.signed" 177 | 178 | # Add a newline after the submission response. 179 | echo "" 180 | -------------------------------------------------------------------------------- /src/CardanoSwaps/Utils.hs: -------------------------------------------------------------------------------- 1 | {-# OPTIONS_GHC -Wno-orphans #-} 2 | 3 | {-# LANGUAGE StrictData #-} 4 | {-# LANGUAGE OverloadedStrings #-} 5 | 6 | module CardanoSwaps.Utils 7 | ( 8 | -- * On-Chain Data Types 9 | PlutusRational 10 | , AssetConfig 11 | , OfferAsset(..) 12 | , AskAsset(..) 13 | , TwoWayPair 14 | 15 | -- * Serialization 16 | , writeData 17 | , writeScript 18 | , decodeDatum 19 | , dataFromCBOR 20 | , decodeHex 21 | , toCBOR 22 | , parseScriptFromCBOR 23 | 24 | -- * Parsing User Inputs 25 | -- This is just so that certain things do not need to be re-exported. 26 | , readAssetConfig 27 | , readTokenName 28 | , readCurrencySymbol 29 | , readTxId 30 | , readTxOutRef 31 | , readPlutusRational 32 | 33 | -- * Misc 34 | , unsafeFromRight 35 | , showTokenName 36 | , unsafeToBuiltinByteString 37 | , scriptHash 38 | , datumHash 39 | , toLedgerScript 40 | , toVersionedLedgerScript 41 | , wrapVersionedLedgerScript 42 | , toCardanoApiScript 43 | 44 | -- * Re-exports 45 | , applyArguments 46 | , PV2.CurrencySymbol(..) 47 | , PV2.TokenName(..) 48 | , unsafeRatio 49 | , PV2.adaSymbol 50 | , PV2.adaToken 51 | , numerator 52 | , denominator 53 | , PV2.TxOutRef(..) 54 | , PV2.TxId(..) 55 | , PV2.SerialisedScript 56 | ) where 57 | 58 | import qualified Data.Aeson as Aeson 59 | import Lens.Micro (over) 60 | import qualified Codec.Serialise as Serial 61 | import Data.ByteString.Lazy (fromStrict,toStrict) 62 | import Data.Text (Text,unpack,pack,replace) 63 | import qualified Data.ByteString.Lazy as LBS 64 | import Data.String (fromString) 65 | import Text.Read (readMaybe) 66 | import Control.Applicative ((<|>)) 67 | import qualified Data.ByteString.Base16 as Base16 68 | import Relude (toShort,encodeUtf8) 69 | 70 | import qualified PlutusTx.Prelude as PlutusTx 71 | import qualified PlutusCore.MkPlc as PLC 72 | import qualified UntypedPlutusCore as UPLC 73 | import qualified Cardano.Api as Api 74 | import Cardano.Api.Shelley (fromPlutusData,PlutusScript(..)) 75 | import PlutusLedgerApi.V1.Bytes (fromHex,bytes,encodeByteString,LedgerBytesError) 76 | import Ledger.Tx.CardanoAPI.Internal (fromCardanoScriptData) 77 | import qualified Ledger as L 78 | import PlutusTx.Ratio (fromGHC,unsafeRatio,numerator,denominator) 79 | import qualified PlutusTx.Builtins as Builtins 80 | import qualified Plutus.Script.Utils.Scripts as PV2 81 | import qualified PlutusLedgerApi.V2 as PV2 82 | 83 | ------------------------------------------------- 84 | -- On-Chain Data Types 85 | ------------------------------------------------- 86 | type PlutusRational = PlutusTx.Rational 87 | type AssetConfig = (PV2.CurrencySymbol,PV2.TokenName) 88 | 89 | ------------------------------------------------- 90 | -- Off-Chain Data Types 91 | ------------------------------------------------- 92 | newtype OfferAsset = OfferAsset { unOfferAsset :: AssetConfig } 93 | newtype AskAsset = AskAsset { unAskAsset :: AssetConfig } 94 | type TwoWayPair = (AssetConfig,AssetConfig) 95 | 96 | ------------------------------------------------- 97 | -- Serialization 98 | ------------------------------------------------- 99 | toJSONValue :: PV2.ToData a => a -> Aeson.Value 100 | toJSONValue = Api.scriptDataToJson Api.ScriptDataJsonDetailedSchema 101 | . Api.unsafeHashableScriptData 102 | . fromPlutusData 103 | . PV2.toData 104 | 105 | writeScript :: FilePath -> PV2.SerialisedScript -> IO (Either (Api.FileError ()) ()) 106 | writeScript file script = 107 | Api.writeFileTextEnvelope @(Api.PlutusScript Api.PlutusScriptV2) (Api.File file) Nothing $ 108 | PlutusScriptSerialised script 109 | 110 | writeData :: PV2.ToData a => FilePath -> a -> IO () 111 | writeData file = LBS.writeFile file . Aeson.encode . toJSONValue 112 | 113 | decodeDatum :: (PV2.FromData a) => Aeson.Value -> Maybe a 114 | decodeDatum = either (const Nothing) (PV2.fromBuiltinData . fromCardanoScriptData) 115 | . Api.scriptDataFromJson Api.ScriptDataJsonDetailedSchema 116 | 117 | parseScriptFromCBOR :: String -> PV2.SerialisedScript 118 | parseScriptFromCBOR script = 119 | case Base16.decode base16Bytes of 120 | Left e -> error $ "Failed to decode validator: " <> show e 121 | Right bytes' -> toShort bytes' 122 | where 123 | base16Bytes = encodeUtf8 script 124 | 125 | dataFromCBOR :: String -> Either LedgerBytesError PV2.Data 126 | dataFromCBOR = fmap Serial.deserialise . decodeHex 127 | 128 | decodeHex :: String -> Either LedgerBytesError LBS.ByteString 129 | decodeHex = fmap (fromStrict . bytes) . fromHex . fromString 130 | 131 | toCBOR :: Serial.Serialise a => a -> Text 132 | toCBOR = encodeByteString . toStrict . Serial.serialise 133 | 134 | ------------------------------------------------- 135 | -- Functions for parsing user input. 136 | ------------------------------------------------- 137 | -- | Parse `AssetConfig` from user supplied `String`. The input is expected to either be 138 | -- "lovelace" or of the form "policy_id.asset_name". 139 | readAssetConfig :: String -> Either String AssetConfig 140 | readAssetConfig s = 141 | if s == "lovelace" then Right (PV2.adaSymbol,PV2.adaToken) 142 | else (,) <$> readCurrencySymbol policy <*> readTokenName (drop 1 name) 143 | where 144 | (policy,name) = span (/='.') s 145 | 146 | -- | Parse `CurrencySymbol` from user supplied `String`. 147 | readCurrencySymbol :: String -> Either String PV2.CurrencySymbol 148 | readCurrencySymbol s = case fromHex $ fromString s of 149 | Right (PV2.LedgerBytes bytes') -> Right $ PV2.CurrencySymbol bytes' 150 | Left msg -> Left $ show msg 151 | 152 | -- | Parse `TokenName` from user supplied `String`. 153 | readTokenName :: String -> Either String PV2.TokenName 154 | readTokenName s = case fromHex $ fromString s of 155 | Right (PV2.LedgerBytes bytes') -> Right $ PV2.TokenName bytes' 156 | Left msg -> Left $ show msg 157 | 158 | -- | Parse `TxId` from user supplied `String`. 159 | readTxId :: String -> Either String PV2.TxId 160 | readTxId s = case fromHex $ fromString s of 161 | Right (PV2.LedgerBytes bytes') -> Right $ PV2.TxId bytes' 162 | Left msg -> Left $ show msg 163 | 164 | readTxOutRef :: String -> Either String PV2.TxOutRef 165 | readTxOutRef s = PV2.TxOutRef <$> readTxId txHash <*> readIndex (drop 1 index) 166 | where 167 | (txHash,index) = span (/='#') s 168 | 169 | readIndex :: String -> Either String Integer 170 | readIndex i = case readMaybe i of 171 | Nothing -> Left $ "could not convert: " <> i 172 | Just i' -> Right i' 173 | 174 | -- | Parse `PlutusRational` from user supplied `String` of either a decimal or a fraction. 175 | readPlutusRational :: String -> Either String PlutusRational 176 | readPlutusRational s = case fromGHC <$> (readMaybeRatio sample <|> readMaybeDouble sample) of 177 | Nothing -> Left $ "could not convert: " <> s 178 | Just r -> Right r 179 | where 180 | -- Replace / with % since Haskell fractions use % while humans use /. 181 | sample :: String 182 | sample = unpack $ replace "/" "%" $ pack s 183 | 184 | readMaybeRatio :: String -> Maybe Rational 185 | readMaybeRatio = readMaybe 186 | 187 | readMaybeDouble :: String -> Maybe Rational 188 | readMaybeDouble = fmap toRational . readMaybe @Double 189 | 190 | ------------------------------------------------- 191 | -- Misc 192 | ------------------------------------------------- 193 | toCardanoApiScript :: PV2.SerialisedScript -> Api.Script Api.PlutusScriptV2 194 | toCardanoApiScript = Api.PlutusScript Api.PlutusScriptV2 . PlutusScriptSerialised 195 | 196 | toLedgerScript :: PV2.SerialisedScript -> PV2.Script 197 | toLedgerScript = PV2.Script 198 | 199 | toVersionedLedgerScript :: PV2.SerialisedScript -> PV2.Versioned PV2.Script 200 | toVersionedLedgerScript script = PV2.Versioned (toLedgerScript script) PV2.PlutusV2 201 | 202 | wrapVersionedLedgerScript :: (PV2.Script -> a) -> PV2.Versioned PV2.Script -> PV2.Versioned a 203 | wrapVersionedLedgerScript wrapper v@PV2.Versioned{PV2.unversioned} = 204 | v{PV2.unversioned = wrapper unversioned} 205 | 206 | scriptHash :: PV2.SerialisedScript -> PV2.ScriptHash 207 | scriptHash = 208 | PV2.ScriptHash 209 | . Builtins.toBuiltin 210 | . Api.serialiseToRawBytes 211 | . Api.hashScript 212 | . toCardanoApiScript 213 | 214 | datumHash :: (PV2.ToData a) => a -> PV2.DatumHash 215 | datumHash = L.datumHash . L.Datum . PV2.dataToBuiltinData . PV2.toData 216 | 217 | applyArguments :: PV2.SerialisedScript -> [PV2.Data] -> PV2.SerialisedScript 218 | applyArguments p args = 219 | let termArgs = fmap (PLC.mkConstant ()) args 220 | applied t = PLC.mkIterAppNoAnn t termArgs 221 | in PV2.serialiseUPLC $ over UPLC.progTerm applied $ PV2.uncheckedDeserialiseUPLC p 222 | 223 | unsafeFromRight :: Either a b -> b 224 | unsafeFromRight (Right x) = x 225 | unsafeFromRight _ = error "unsafeFromRight used on Left" 226 | 227 | -- | Show the token name in hexidecimal. 228 | showTokenName :: PV2.TokenName -> String 229 | showTokenName (PV2.TokenName name) = show $ PV2.PubKeyHash name 230 | 231 | unsafeToBuiltinByteString :: String -> Builtins.BuiltinByteString 232 | unsafeToBuiltinByteString = (\(PV2.LedgerBytes bytes') -> bytes') 233 | . unsafeFromRight 234 | . fromHex 235 | . fromString 236 | -------------------------------------------------------------------------------- /scripts/remote/one-way/update-price.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Variables 4 | tmpDir="/tmp/cardano-swaps/" 5 | 6 | # Make the tmpDir if it doesn't already exist. 7 | mkdir -p $tmpDir 8 | 9 | ownerPubKeyFile="$HOME/wallets/01Stake.vkey" 10 | beaconScriptFile="${tmpDir}oneWayBeacons.plutus" 11 | beaconAddrFile="${tmpDir}oneWayBeaconStake.addr" 12 | swapAddrFile="${tmpDir}oneWaySwap.addr" 13 | swapDatumFile="${tmpDir}swapDatum.json" 14 | swapRedeemerFile="${tmpDir}oneWaySpendingRedeemer.json" 15 | beaconRedeemerFile="${tmpDir}oneWayBeaconRedeemer.json" 16 | 17 | # The reference scripts are permanently locked in the swap address without a staking credential! 18 | # You can use the `cardano-swaps query personal-address` command to see them. 19 | beaconScriptPreprodTestnetRef="9fecc1d2cf99088facad02aeccbedb6a4f783965dc6c02bd04dc8b348e9a0858#1" 20 | beaconScriptSize=4432 21 | 22 | spendingScriptPreprodTestnetRef="9fecc1d2cf99088facad02aeccbedb6a4f783965dc6c02bd04dc8b348e9a0858#0" 23 | spendingScriptSize=4842 24 | 25 | # Generate the hash for the staking verification key. 26 | echo "Calculating the staking pubkey hash for the borrower..." 27 | ownerPubKeyHash=$(cardano-cli conway stake-address key-hash \ 28 | --stake-verification-key-file $ownerPubKeyFile) 29 | 30 | # Export the beacon script. 31 | echo "Exporting the beacon script..." 32 | cardano-swaps scripts one-way beacon-script \ 33 | --out-file $beaconScriptFile 34 | 35 | # Create the beacon stake address. 36 | echo "Creating the beacon reward address..." 37 | cardano-cli conway stake-address build \ 38 | --stake-script-file $beaconScriptFile \ 39 | --testnet-magic 1 \ 40 | --out-file $beaconAddrFile 41 | 42 | # Create the spending redeemer. 43 | echo "Creating the spending redeemer..." 44 | cardano-swaps spending-redeemers one-way \ 45 | --update-with-stake \ 46 | --out-file $swapRedeemerFile 47 | 48 | # Create the beacon script redeemer. 49 | echo "Creating the beacon redeemer..." 50 | cardano-swaps beacon-redeemers one-way \ 51 | --update-only \ 52 | --out-file $beaconRedeemerFile 53 | 54 | # Create the new swap datum. 55 | echo "Creating the new swap datum..." 56 | cardano-swaps datums one-way \ 57 | --ask-asset lovelace \ 58 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 59 | --offer-price 2000000 \ 60 | --out-file $swapDatumFile 61 | 62 | # Helper beacon variables. 63 | echo "Calculating the beacon names..." 64 | beaconPolicyId=$(cardano-swaps beacon-info one-way policy-id \ 65 | --stdout) 66 | 67 | pairBeaconName=$(cardano-swaps beacon-info one-way pair-beacon \ 68 | --ask-asset lovelace \ 69 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 70 | --stdout) 71 | 72 | offerBeaconName=$(cardano-swaps beacon-info one-way offer-beacon \ 73 | --offer-asset c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a \ 74 | --stdout) 75 | 76 | askBeaconName=$(cardano-swaps beacon-info one-way ask-beacon \ 77 | --ask-asset lovelace \ 78 | --stdout) 79 | 80 | pairBeacon="${beaconPolicyId}.${pairBeaconName}" 81 | offerBeacon="${beaconPolicyId}.${offerBeaconName}" 82 | askBeacon="${beaconPolicyId}.${askBeaconName}" 83 | 84 | # Create the transaction. 85 | echo "Exporting the current protocol parameters..." 86 | cardano-swaps query protocol-params \ 87 | --testnet \ 88 | --out-file "${tmpDir}protocol.json" 89 | 90 | initial_change=$((316605149)) 91 | 92 | echo "Building the initial transaction..." 93 | cardano-cli conway transaction build-raw \ 94 | --tx-in 5befc3f68d6ff1f8f7842bf27163a415cefd7f3dfca1c1f47b7668937307cca1#1 \ 95 | --tx-in a0253efa191f62d2eae47230e9deacfa16923faf6d13074d460f57a934f2ca0e#0 \ 96 | --spending-tx-in-reference $spendingScriptPreprodTestnetRef \ 97 | --spending-plutus-script-v2 \ 98 | --spending-reference-tx-in-inline-datum-present \ 99 | --spending-reference-tx-in-execution-units "(0,0)" \ 100 | --spending-reference-tx-in-redeemer-file $swapRedeemerFile \ 101 | --withdrawal "$(cat ${beaconAddrFile})+0" \ 102 | --withdrawal-tx-in-reference $beaconScriptPreprodTestnetRef \ 103 | --withdrawal-plutus-script-v2 \ 104 | --withdrawal-reference-tx-in-execution-units "(0,0)" \ 105 | --withdrawal-reference-tx-in-redeemer-file $beaconRedeemerFile \ 106 | --tx-out "$(cat ${swapAddrFile}) + 3000000 lovelace + 1 ${pairBeacon} + 1 ${offerBeacon} + 1 ${askBeacon} + 10 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a" \ 107 | --tx-out-inline-datum-file $swapDatumFile \ 108 | --tx-out "$(cat $HOME/wallets/01.addr) + ${initial_change} lovelace" \ 109 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 110 | --tx-total-collateral 21000000 \ 111 | --tx-out-return-collateral "$(cat $HOME/wallets/01.addr) 21000000 lovelace" \ 112 | --required-signer-hash "$ownerPubKeyHash" \ 113 | --protocol-params-file "${tmpDir}protocol.json" \ 114 | --fee 5000000 \ 115 | --out-file "${tmpDir}tx.body" 116 | 117 | echo "Getting the execution units estimations..." 118 | exec_units=$(cardano-swaps evaluate-tx \ 119 | --testnet \ 120 | --tx-file "${tmpDir}tx.body") 121 | 122 | # MAKE SURE THE INDEXES MATCH THE LEXICOGRAPHICAL ORDERING FOR INPUTS AND POLICY IDS. 123 | # You can use `cardano-cli debug transaction view --tx-file "${tmpDir}tx.body` to view the prior 124 | # transaction with everything in the correct order. 125 | stake_mem=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="withrdrawal" and .validator.index==0) | .budget.memory' ) 126 | stake_steps=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="withrdrawal" and .validator.index==0) | .budget.cpu' ) 127 | spend_0_mem=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="spend" and .validator.index==0) | .budget.memory' ) 128 | spend_0_steps=$(echo $exec_units | jq '.result | .[] | select(.validator.purpose=="spend" and .validator.index==0) | .budget.cpu' ) 129 | 130 | echo "Rebuilding the transaction with proper execution budgets..." 131 | cardano-cli conway transaction build-raw \ 132 | --tx-in 5befc3f68d6ff1f8f7842bf27163a415cefd7f3dfca1c1f47b7668937307cca1#1 \ 133 | --tx-in a0253efa191f62d2eae47230e9deacfa16923faf6d13074d460f57a934f2ca0e#0 \ 134 | --spending-tx-in-reference $spendingScriptPreprodTestnetRef \ 135 | --spending-plutus-script-v2 \ 136 | --spending-reference-tx-in-inline-datum-present \ 137 | --spending-reference-tx-in-execution-units "(${spend_0_steps},${spend_0_mem})" \ 138 | --spending-reference-tx-in-redeemer-file $swapRedeemerFile \ 139 | --withdrawal "$(cat ${beaconAddrFile})+0" \ 140 | --withdrawal-tx-in-reference $beaconScriptPreprodTestnetRef \ 141 | --withdrawal-plutus-script-v2 \ 142 | --withdrawal-reference-tx-in-execution-units "(${stake_steps},${stake_mem})" \ 143 | --withdrawal-reference-tx-in-redeemer-file $beaconRedeemerFile \ 144 | --tx-out "$(cat ${swapAddrFile}) + 3000000 lovelace + 1 ${pairBeacon} + 1 ${offerBeacon} + 1 ${askBeacon} + 10 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a" \ 145 | --tx-out-inline-datum-file $swapDatumFile \ 146 | --tx-out "$(cat $HOME/wallets/01.addr) + ${initial_change} lovelace" \ 147 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 148 | --tx-total-collateral 21000000 \ 149 | --tx-out-return-collateral "$(cat $HOME/wallets/01.addr) 21000000 lovelace" \ 150 | --required-signer-hash "$ownerPubKeyHash" \ 151 | --protocol-params-file "${tmpDir}protocol.json" \ 152 | --fee 5000000 \ 153 | --out-file "${tmpDir}tx.body" 154 | 155 | echo "Calculating the required fee..." 156 | calculated_fee=$(cardano-cli conway transaction calculate-min-fee \ 157 | --tx-body-file "${tmpDir}tx.body" \ 158 | --protocol-params-file "${tmpDir}protocol.json" \ 159 | --reference-script-size $((beaconScriptSize+spendingScriptSize)) \ 160 | --witness-count 2 | cut -d' ' -f1) 161 | req_fee=$((calculated_fee+50000)) # Add 0.05 ADA to be safe since the fee must still be updated. 162 | req_collateral=$(printf %.0f $(echo "${req_fee}*1.5" | bc)) 163 | 164 | echo "Rebuilding the transaction with the required fee..." 165 | cardano-cli conway transaction build-raw \ 166 | --tx-in 5befc3f68d6ff1f8f7842bf27163a415cefd7f3dfca1c1f47b7668937307cca1#1 \ 167 | --tx-in a0253efa191f62d2eae47230e9deacfa16923faf6d13074d460f57a934f2ca0e#0 \ 168 | --spending-tx-in-reference $spendingScriptPreprodTestnetRef \ 169 | --spending-plutus-script-v2 \ 170 | --spending-reference-tx-in-inline-datum-present \ 171 | --spending-reference-tx-in-execution-units "(${spend_0_steps},${spend_0_mem})" \ 172 | --spending-reference-tx-in-redeemer-file $swapRedeemerFile \ 173 | --withdrawal "$(cat ${beaconAddrFile})+0" \ 174 | --withdrawal-tx-in-reference $beaconScriptPreprodTestnetRef \ 175 | --withdrawal-plutus-script-v2 \ 176 | --withdrawal-reference-tx-in-execution-units "(${stake_steps},${stake_mem})" \ 177 | --withdrawal-reference-tx-in-redeemer-file $beaconRedeemerFile \ 178 | --tx-out "$(cat ${swapAddrFile}) + 3000000 lovelace + 1 ${pairBeacon} + 1 ${offerBeacon} + 1 ${askBeacon} + 10 c0f8644a01a6bf5db02f4afe30d604975e63dd274f1098a1738e561d.4f74686572546f6b656e0a" \ 179 | --tx-out-inline-datum-file $swapDatumFile \ 180 | --tx-out "$(cat $HOME/wallets/01.addr) + $((initial_change-req_fee)) lovelace " \ 181 | --tx-in-collateral 4cc5755712fee56feabad637acf741bc8c36dda5f3d6695ac6487a77c4a92d76#0 \ 182 | --tx-total-collateral $req_collateral \ 183 | --tx-out-return-collateral "$(cat $HOME/wallets/01.addr) $((21000000-$req_collateral)) lovelace" \ 184 | --required-signer-hash "$ownerPubKeyHash" \ 185 | --protocol-params-file "${tmpDir}protocol.json" \ 186 | --fee "$req_fee" \ 187 | --out-file "${tmpDir}tx.body" 188 | 189 | echo "Signing the transaction..." 190 | cardano-cli conway transaction sign \ 191 | --tx-body-file "${tmpDir}tx.body" \ 192 | --signing-key-file $HOME/wallets/01.skey \ 193 | --signing-key-file $HOME/wallets/01Stake.skey \ 194 | --testnet-magic 1 \ 195 | --out-file "${tmpDir}tx.signed" 196 | 197 | echo "Submitting the transaction..." 198 | cardano-swaps submit \ 199 | --testnet \ 200 | --tx-file "${tmpDir}tx.signed" 201 | 202 | # Add a newline after the submission response. 203 | echo "" 204 | --------------------------------------------------------------------------------