github.com/gravity-devs/liquidity@v1.5.3/x/liquidity/client/cli/tx.go (about) 1 package cli 2 3 // DONTCOVER 4 // client is excluded from test coverage in the poc phase milestone 1 and will be included in milestone 2 with completeness 5 6 import ( 7 "fmt" 8 "strconv" 9 "strings" 10 11 "github.com/cosmos/cosmos-sdk/client" 12 "github.com/cosmos/cosmos-sdk/client/flags" 13 "github.com/cosmos/cosmos-sdk/client/tx" 14 sdk "github.com/cosmos/cosmos-sdk/types" 15 "github.com/cosmos/cosmos-sdk/version" 16 "github.com/spf13/cobra" 17 18 "github.com/gravity-devs/liquidity/x/liquidity/types" 19 ) 20 21 // GetTxCmd returns a root CLI command handler for all x/liquidity transaction commands. 22 func GetTxCmd() *cobra.Command { 23 liquidityTxCmd := &cobra.Command{ 24 Use: types.ModuleName, 25 Short: "Liquidity transaction subcommands", 26 DisableFlagParsing: true, 27 SuggestionsMinimumDistance: 2, 28 RunE: client.ValidateCmd, 29 } 30 31 liquidityTxCmd.AddCommand( 32 NewCreatePoolCmd(), 33 NewDepositWithinBatchCmd(), 34 NewWithdrawWithinBatchCmd(), 35 NewSwapWithinBatchCmd(), 36 ) 37 38 return liquidityTxCmd 39 } 40 41 // Create new liquidity pool with the specified pool type and deposit coins. 42 func NewCreatePoolCmd() *cobra.Command { 43 cmd := &cobra.Command{ 44 Use: "create-pool [pool-type] [deposit-coins]", 45 Args: cobra.ExactArgs(2), 46 Short: "Create liquidity pool and deposit coins", 47 Long: strings.TrimSpace( 48 fmt.Sprintf(`Create liquidity pool and deposit coins. 49 50 Example: 51 $ %s tx %s create-pool 1 1000000000uatom,50000000000uusd --from mykey 52 53 This example creates a liquidity pool of pool-type 1 (two coins) and deposits 1000000000uatom and 50000000000uusd. 54 New liquidity pools can be created only for coin combinations that do not already exist in the network. 55 56 [pool-type]: The id of the liquidity pool-type. The only supported pool type is 1 57 [deposit-coins]: The amount of coins to deposit to the liquidity pool. The number of deposit coins must be 2 in pool type 1. 58 `, 59 version.AppName, types.ModuleName, 60 ), 61 ), 62 RunE: func(cmd *cobra.Command, args []string) error { 63 clientCtx, err := client.GetClientTxContext(cmd) 64 if err != nil { 65 return err 66 } 67 poolCreator := clientCtx.GetFromAddress() 68 69 // Get pool type index 70 poolTypeID, err := strconv.ParseUint(args[0], 10, 32) 71 if err != nil { 72 return fmt.Errorf("pool-type %s not a valid uint, input a valid unsigned 32-bit integer for pool-type", args[0]) 73 } 74 75 // Get deposit coins 76 depositCoins, err := sdk.ParseCoinsNormalized(args[1]) 77 if err != nil { 78 return err 79 } 80 81 err = depositCoins.Validate() 82 if err != nil { 83 return err 84 } 85 86 if poolTypeID != 1 { 87 return types.ErrPoolTypeNotExists 88 } 89 90 if depositCoins.Len() != 2 { 91 return fmt.Errorf("the number of deposit coins must be two in pool-type 1") 92 } 93 94 msg := types.NewMsgCreatePool(poolCreator, uint32(poolTypeID), depositCoins) 95 if err := msg.ValidateBasic(); err != nil { 96 return err 97 } 98 99 return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) 100 }, 101 } 102 103 flags.AddTxFlagsToCmd(cmd) 104 105 return cmd 106 } 107 108 // Deposit coins to the specified liquidity pool. 109 func NewDepositWithinBatchCmd() *cobra.Command { 110 cmd := &cobra.Command{ 111 Use: "deposit [pool-id] [deposit-coins]", 112 Args: cobra.ExactArgs(2), 113 Short: "Deposit coins to a liquidity pool", 114 Long: strings.TrimSpace( 115 fmt.Sprintf(`Deposit coins a liquidity pool. 116 117 This deposit request is not processed immediately since it is accumulated in the liquidity pool batch. 118 All requests in a batch are treated equally and executed at the same swap price. 119 120 Example: 121 $ %s tx %s deposit 1 100000000uatom,5000000000uusd --from mykey 122 123 This example request deposits 100000000uatom and 5000000000uusd to pool-id 1. 124 Deposits must be the same coin denoms as the reserve coins. 125 126 [pool-id]: The pool id of the liquidity pool 127 [deposit-coins]: The amount of coins to deposit to the liquidity pool 128 `, 129 version.AppName, types.ModuleName, 130 ), 131 ), 132 RunE: func(cmd *cobra.Command, args []string) error { 133 clientCtx, err := client.GetClientTxContext(cmd) 134 if err != nil { 135 return err 136 } 137 depositor := clientCtx.GetFromAddress() 138 139 // Get pool type index 140 poolID, err := strconv.ParseUint(args[0], 10, 64) 141 if err != nil { 142 return fmt.Errorf("pool-id %s not a valid uint, input a valid unsigned 32-bit integer for pool-id", args[0]) 143 } 144 145 // Get deposit coins 146 depositCoins, err := sdk.ParseCoinsNormalized(args[1]) 147 if err != nil { 148 return err 149 } 150 151 err = depositCoins.Validate() 152 if err != nil { 153 return err 154 } 155 156 if depositCoins.Len() != 2 { 157 return fmt.Errorf("the number of deposit coins must be two in the pool-type 1") 158 } 159 160 msg := types.NewMsgDepositWithinBatch(depositor, poolID, depositCoins) 161 if err := msg.ValidateBasic(); err != nil { 162 return err 163 } 164 165 return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) 166 }, 167 } 168 169 flags.AddTxFlagsToCmd(cmd) 170 171 return cmd 172 } 173 174 // Withdraw pool coin from the specified liquidity pool. 175 func NewWithdrawWithinBatchCmd() *cobra.Command { 176 cmd := &cobra.Command{ 177 Use: "withdraw [pool-id] [pool-coin]", 178 Args: cobra.ExactArgs(2), 179 Short: "Withdraw pool coin from the specified liquidity pool", 180 Long: strings.TrimSpace( 181 fmt.Sprintf(`Withdraw pool coin from the specified liquidity pool. 182 183 This swap request is not processed immediately since it is accumulated in the liquidity pool batch. 184 All requests in a batch are treated equally and executed at the same swap price. 185 186 Example: 187 $ %s tx %s withdraw 1 10000pool96EF6EA6E5AC828ED87E8D07E7AE2A8180570ADD212117B2DA6F0B75D17A6295 --from mykey 188 189 This example request withdraws 10000 pool coin from the specified liquidity pool. 190 The appropriate pool coin must be requested from the specified pool. 191 192 [pool-id]: The pool id of the liquidity pool 193 [pool-coin]: The amount of pool coin to withdraw from the liquidity pool 194 `, 195 version.AppName, types.ModuleName, 196 ), 197 ), 198 RunE: func(cmd *cobra.Command, args []string) error { 199 clientCtx, err := client.GetClientTxContext(cmd) 200 if err != nil { 201 return err 202 } 203 withdrawer := clientCtx.GetFromAddress() 204 205 // Get pool type index 206 poolID, err := strconv.ParseUint(args[0], 10, 64) 207 if err != nil { 208 return fmt.Errorf("pool-id %s not a valid uint, input a valid unsigned 32-bit integer for pool-id", args[0]) 209 } 210 211 // Get pool coin of the target pool 212 poolCoin, err := sdk.ParseCoinNormalized(args[1]) 213 if err != nil { 214 return err 215 } 216 217 err = poolCoin.Validate() 218 if err != nil { 219 return err 220 } 221 222 msg := types.NewMsgWithdrawWithinBatch(withdrawer, poolID, poolCoin) 223 if err := msg.ValidateBasic(); err != nil { 224 return err 225 } 226 227 return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) 228 }, 229 } 230 231 flags.AddTxFlagsToCmd(cmd) 232 233 return cmd 234 } 235 236 // Swap offer coin with demand coin from the specified liquidity pool with the given order price. 237 func NewSwapWithinBatchCmd() *cobra.Command { 238 cmd := &cobra.Command{ 239 Use: "swap [pool-id] [swap-type] [offer-coin] [demand-coin-denom] [order-price] [swap-fee-rate]", 240 Args: cobra.ExactArgs(6), 241 Short: "Swap offer coin with demand coin from the liquidity pool with the given order price", 242 Long: strings.TrimSpace( 243 fmt.Sprintf(`Swap offer coin with demand coin from the liquidity pool with the given order price. 244 245 This swap request is not processed immediately since it is accumulated in the liquidity pool batch. 246 All requests in a batch are treated equally and executed at the same swap price. 247 The order of swap requests is ignored since the universal swap price is calculated in every batch to prevent front running. 248 249 The requested swap is executed with a swap price that is calculated from the given swap price function of the pool, the other swap requests, and the liquidity pool coin reserve status. 250 Swap orders are executed only when the execution swap price is equal to or greater than the submitted order price of the swap order. 251 252 Example: 253 $ %s tx %s swap 1 1 50000000uusd uatom 0.019 0.003 --from mykey 254 255 For this example, imagine that an existing liquidity pool has with 1000000000uatom and 50000000000uusd. 256 This example request swaps 50000000uusd for at least 950000uatom with the order price of 0.019 and swap fee rate of 0.003. 257 A sufficient balance of half of the swap-fee-rate of the offer coin is required to reserve the offer coin fee. 258 259 The order price is the exchange ratio of X/Y, where X is the amount of the first coin and Y is the amount of the second coin when their denoms are sorted alphabetically. 260 Increasing order price reduces the possibility for your request to be processed and results in buying uatom at a lower price than the pool price. 261 262 For explicit calculations, The swap fee rate must be the value that set as liquidity parameter in the current network. 263 The only supported swap-type is 1. For the detailed swap algorithm, see https://github.com/gravity-devs/liquidity 264 265 [pool-id]: The pool id of the liquidity pool 266 [swap-type]: The swap type of the swap message. The only supported swap type is 1 (instant swap). 267 [offer-coin]: The amount of offer coin to swap 268 [demand-coin-denom]: The denomination of the coin to exchange with offer coin 269 [order-price]: The limit order price for the swap order. The price is the exchange ratio of X/Y where X is the amount of the first coin and Y is the amount of the second coin when their denoms are sorted alphabetically 270 [swap-fee-rate]: The swap fee rate to pay for swap that is proportional to swap amount. The swap fee rate must be the value that set as liquidity parameter in the current network. 271 `, 272 version.AppName, types.ModuleName, 273 ), 274 ), 275 RunE: func(cmd *cobra.Command, args []string) error { 276 clientCtx, err := client.GetClientTxContext(cmd) 277 if err != nil { 278 return err 279 } 280 swapRequester := clientCtx.GetFromAddress() 281 282 // Get pool id 283 poolID, err := strconv.ParseUint(args[0], 10, 64) 284 if err != nil { 285 return fmt.Errorf("pool-id %s not a valid uint, input a valid unsigned 32-bit integer for pool-id", args[0]) 286 } 287 288 // Get swap type 289 swapTypeID, err := strconv.ParseUint(args[1], 10, 32) 290 if err != nil { 291 return fmt.Errorf("swap-type %s not a valid uint, input a valid unsigned 32-bit integer for swap-type", args[2]) 292 } 293 294 if swapTypeID != 1 { 295 return types.ErrSwapTypeNotExists 296 } 297 298 // Get offer coin 299 offerCoin, err := sdk.ParseCoinNormalized(args[2]) 300 if err != nil { 301 return err 302 } 303 304 err = offerCoin.Validate() 305 if err != nil { 306 return err 307 } 308 309 err = sdk.ValidateDenom(args[3]) 310 if err != nil { 311 return err 312 } 313 314 orderPrice, err := sdk.NewDecFromStr(args[4]) 315 if err != nil { 316 return err 317 } 318 319 swapFeeRate, err := sdk.NewDecFromStr(args[5]) 320 if err != nil { 321 return err 322 } 323 324 msg := types.NewMsgSwapWithinBatch(swapRequester, poolID, uint32(swapTypeID), offerCoin, args[3], orderPrice, swapFeeRate) 325 if err := msg.ValidateBasic(); err != nil { 326 return err 327 } 328 329 return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg) 330 }, 331 } 332 333 flags.AddTxFlagsToCmd(cmd) 334 335 return cmd 336 }