cosmos-trustless-swap is a module for swapping and selling tokens between two users.
It is implemented as Cosmos module.
sequenceDiagram
actor Alice
participant Module
actor Bob
Alice ->> Module: transfer 10token (price 20stake)
Note over Module: have 10token
Bob ->>+ Module: request receive
Module ->> Alice: transfer 20stake from Bob<br/> (tx is signed by bob)
Module ->>- Bob: transfer 10token
Note over Alice: have 20stake
Note over Bob: have 10token
sequenceDiagram
actor Alice
participant Module
actor Bob
Alice ->> Module: transfer NFT (price 20stake)
Note over Module: have NFT
Bob ->>+ Module: request receive
Module ->> Alice: transfer 20stake from Bob<br/> (tx is signed by bob)
Module ->>- Bob: transfer NFT
Note over Alice: have 20stake
Note over Bob: have NFT
simd
is your blockchain cli built by ignite chain build
.
$ simd tx swap send [id] [receiver] [amount] [amountToReceive] --from keyname
# ex) simd tx swap send 1 cosmos1p496u9my9uv6s3klsxuhud5y7jxwmd4lal8ym4 10coin 1stake --from alice
proeprty | description | ex |
---|---|---|
[id] | Any number of type uint64. It must be unique for --from user. If swap is completed by cancel or receive , it can be reused.. If swap is completed by cancel or receive, it can be reused |
1 |
[receiver] | The recipient's address | cosmos1p496u9my9uv6s3klsxuhud5y7jxwmd4lal8ym4 |
[amount] | The amout of token to transfer | 10tokenA |
[amountToReceive] | The amount of tokens required for the recipient to receive | 20tokenB |
$ simd query swap show [sender] [id]
# ex) simd query swap show cosmos1s7p7h4k3v9qcqs7ku2tpq0cajydertggeg8z4m 1
# Here is the result
# swap:
# creator: cosmos1s7p7h4k3v9qcqs7ku2tpq0cajydertggeg8z4m
# id: "1"
# receiver: cosmos1p496u9my9uv6s3klsxuhud5y7jxwmd4lal8ym4
# amount: 10tokenA
# amountToReceive: 20tokenB
$ simd tx swap receive [sender] [id] --from keyname
# ex) simd tx swap receive cosmos1s7p7h4k3v9qcqs7ku2tpq0cajydertggeg8z4m 1 --from bob
proeprty | description | ex |
---|---|---|
[id] | The id specified when sending | 1 |
[sender] | The address of the sender(swap creator). | cosmos1p496u9my9uv6s3klsxuhud5y7jxwmd4lal8ym4 |
--from | The recipient. It must match the address specified in [receiver] in saved sale |
bob |
$ simd tx swap cancel [id] --from keyname
# ex) simd tx swap cancel 1 --from alice
proeprty | description | ex |
---|---|---|
[id] | The id specified when sending | 1 |
--from | It must match the address specified in [creator] in saved sale |
alice |
$ simd tx swap send-nft [id] [receiver] [classId] [nftId] [amountToReceive] --from keyname
# ex) simd tx swap send-nft 1 cosmos1p496u9my9uv6s3klsxuhud5y7jxwmd4lal8ym4 class1 nft1 --from alice
proeprty | description | ex |
---|---|---|
[id] | Any number of type uint64. It must be unique for --from user. If swap is completed by cancel or receive , it can be reused.. If swap is completed by cancel or receive, it can be reused |
1 |
[receiver] | The recipient's address | cosmos1p496u9my9uv6s3klsxuhud5y7jxwmd4lal8ym4 |
[classId] | The NFT's classId | class1 |
[nftId] | The NFT's nftId | class1 |
[amountToReceive] | The amount of tokens required for the recipient to receive | 20tokenB |
--from | It must be the owner of the NFT | alice |
$ simd query swap show-nft [sender] [id]
# ex) simd query swap show-nft cosmos1s7p7h4k3v9qcqs7ku2tpq0cajydertggeg8z4m 1
# Here is the result
# swap:
# amountToReceive: 3token
# classId: class1
# creator: cosmos1s7p7h4k3v9qcqs7ku2tpq0cajydertggeg8z4m
# id: "1"
# nftId: nft1
# receiver: cosmos1p496u9my9uv6s3klsxuhud5y7jxwmd4lal8ym4
$ simd tx swap receive-nft [sender] [id] --from keyname
# ex) simd tx swap receive-nft cosmos1s7p7h4k3v9qcqs7ku2tpq0cajydertggeg8z4m 1 --from bob
proeprty | description | ex |
---|---|---|
[id] | The id specified when sending | 1 |
[sender] | The address of the sender(swap creator) | cosmos1p496u9my9uv6s3klsxuhud5y7jxwmd4lal8ym4 |
--from | The recipient. It must match the address specified in [receiver] in saved sale |
bob |
$ simd tx swap cancel-nft [id] --from keyname
# ex) simd tx swap cancel-nft 1 --from alice
proeprty | description | ex |
---|---|---|
[id] | The id specified when sending | 1 |
--from | It must match the address specified in [creator] in saved sale |
alice |
$ simd tx sale sell [id] [amount] [amountToReceive] --from keyname
# ex) simd tx sale sell 1 10coin 1stake --from alice
proeprty | description | ex |
---|---|---|
[id] | Any number of type uint64. It must be unique for the signer. If swap is completed by cancel or receive , it can be reused.. If swap is completed by cancel or receive, it can be reused |
1 |
[amount] | The amount of token to transfer | 10tokenA |
[amountToReceive] | The amount of tokens required for the recipient to receive | 20tokenB |
$ simd query sale show [seller] [id]
# ex) simd query sale show cosmos1s7p7h4k3v9qcqs7ku2tpq0cajydertggeg8z4m 1
# Here is the result
# sell:
# creator: cosmos1s7p7h4k3v9qcqs7ku2tpq0cajydertggeg8z4m
# id: "1"
# amount: 10tokenA
# amountToReceive: 20tokenB
$ simd tx sale buy [seller] [id] --from keyname
# ex) simd tx sale buy cosmos1s7p7h4k3v9qcqs7ku2tpq0cajydertggeg8z4m 1 --from bob
proeprty | description | ex |
---|---|---|
[id] | The id specified when selling | 1 |
[seller] | The address of the seller(sale creator) | cosmos1p496u9my9uv6s3klsxuhud5y7jxwmd4lal8ym4 |
--from | The buyer | bob |
$ simd tx sale cancel [id] --from keyname
# ex) simd tx sale cancel 1 --from alice
proeprty | description | ex |
---|---|---|
[id] | The id specified when selling | 1 |
--from | It must match the address specified in [creator] in saved sale |
alice |
$ simd tx sale sell-nft [id] [classId] [nftId] [amountToReceive] --from keyname
# ex) simd tx sale sell-nft 1 class1 nft1 --from alice
proeprty | description | ex |
---|---|---|
[id] | Any number of type uint64. It must be unique for --from user. If swap is completed by cancel or receive , it can be reused.. If swap is completed by cancel or buy, it can be reused |
1 |
[classId] | The NFT's classId | class1 |
[nftId] | The NFT's nftId | class1 |
[amountToReceive] | The amount of tokens required for the recipient to receive | 20tokenB |
--from | It must be the owner of the NFT | alice |
$ simd query sale show-nft [sender] [id]
# ex) simd query sale show-nft cosmos1s7p7h4k3v9qcqs7ku2tpq0cajydertggeg8z4m 1
# Here is the result
# sale:
# amountToReceive: 3token
# classId: class1
# creator: cosmos1s7p7h4k3v9qcqs7ku2tpq0cajydertggeg8z4m
# id: "1"
# nftId: nft1
$ simd tx sale buy-nft [seller] [id] --from keyname
# ex) simd tx sale buy-nft cosmos1s7p7h4k3v9qcqs7ku2tpq0cajydertggeg8z4m 1 --from bob
proeprty | description | ex |
---|---|---|
[id] | The id specified when selling | 1 |
[seller] | The address of the seller(sale creator) | cosmos1p496u9my9uv6s3klsxuhud5y7jxwmd4lal8ym4 |
--from | The buyer | bob |
$ simd tx swap cancel-nft [id] --from keyname
# ex) simd tx swap cancel-nft 1 --from alice
proeprty | description | ex |
---|---|---|
[id] | The id specified when selling | 1 |
--from | IIt must match the address specified in [creator] in saved sale |
alice |
go get -u github.com/yoshidan/cosmos-trustless-swap
Modify app/app.go
included in the blockchain boilerplate output by Ignite CLI as follows.
- Import
nft
andswap
andsale
modules. nft
is not required if you do not swap or sell NFTs.
import (
...
"github.com/cosmos/cosmos-sdk/x/nft"
nftkeeper "github.com/cosmos/cosmos-sdk/x/nft/keeper"
nftmodule "github.com/cosmos/cosmos-sdk/x/nft/module"
swapmodule "github.com/yoshidan/cosmos-trustless-swap/x/swap"
swapmodulekeeper "github.com/yoshidan/cosmos-trustless-swap/x/swap/keeper"
swapmoduletypes "github.com/yoshidan/cosmos-trustless-swap/x/swap/types"
salemodule "github.com/yoshidan/cosmos-trustless-swap/x/sale"
salemodulekeeper "github.com/yoshidan/cosmos-trustless-swap/x/sale/keeper"
salemoduletypes "github.com/yoshidan/cosmos-trustless-swap/x/sale/types"
)
- Add these modules to
ModuleBasics
andmaccPerms
var (
ModuleBasics = module.NewBasicManager(
...
nftmodule.AppModuleBasic{},
swapmodule.AppModuleBasic{},
salemodule.AppModuleBasic{},
)
maccPerms = map[string][]string{
...
nft.ModuleName: nil,
swapmoduletypes.ModuleName: nil,
salemoduletypes.ModuleName: nil,
}
)
- Add the
keepers
toApp
struct
type App struct {
...
NFTKeeper nftkeeper.Keeper
SwapKeeper swapmodulekeeper.Keeper
SaleKeeper salemodulekeeper.Keeper
}
- Initialize the modules in
func New
func New(
...
) *App {
...
keys := sdk.NewKVStoreKeys(
...
nft.StoreKey,
swapmoduletypes.StoreKey,
salemoduletypes.StoreKey,
)
...
app.NFTKeeper = nftkeeper.NewKeeper(
keys[nft.StoreKey],
appCodec,
app.AccountKeeper,
app.BankKeeper,
)
nftModules := nftmodule.NewAppModule(appCodec, app.NFTKeeper, app.AccountKeeper, app.BankKeeper, app.interfaceRegistry)
app.SwapKeeper = *swapmodulekeeper.NewKeeper(
appCodec,
keys[swapmoduletypes.StoreKey],
keys[swapmoduletypes.MemStoreKey],
app.GetSubspace(swapmoduletypes.ModuleName),
app.AccountKeeper,
app.BankKeeper,
app.NFTKeeper,
)
swapModule := swapmodule.NewAppModule(appCodec, app.SwapKeeper, app.AccountKeeper, app.BankKeeper)
app.SaleKeeper = *salemodulekeeper.NewKeeper(
appCodec,
keys[salemoduletypes.StoreKey],
keys[salemoduletypes.MemStoreKey],
app.GetSubspace(salemoduletypes.ModuleName),
app.BankKeeper,
app.AccountKeeper,
app.NFTKeeper,
)
saleModule := salemodule.NewAppModule(appCodec, app.SaleKeeper, app.AccountKeeper, app.BankKeeper)
app.mm = module.NewManager(
...
nftModules,
swapModule,
saleModule,
)
app.mm.SetOrderBeginBlockers(
...
nft.ModuleName,
swapmoduletypes.ModuleName,
salemoduletypes.ModuleName,
)
app.mm.SetOrderEndBlockers(
...
nft.ModuleName,
swapmoduletypes.ModuleName,
salemoduletypes.ModuleName,
)
app.mm.SetOrderInitGenesis(
...
nft.ModuleName,
swapmoduletypes.ModuleName,
salemoduletypes.ModuleName,
)
app.sm = module.NewSimulationManager(
...
nftModules,
swapModule,
saleModule,
)
...
return app
}
Then you can generate openapi.yml
and TypeScript client.
ignite generate ts-client --clear-cache
ignite generate openapi --clear-cache