package main import ( "bytes" "fmt" "io/ioutil" "net/http" "strings" "time" "github.com/cosmos/cosmos-sdk/codec" crkeys "github.com/cosmos/cosmos-sdk/crypto/keys" sdk "github.com/cosmos/cosmos-sdk/types" sdkrest "github.com/cosmos/cosmos-sdk/types/rest" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth" authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest" authclient "github.com/cosmos/cosmos-sdk/x/auth/client/utils" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/cosmos-sdk/x/staking" tmtime "github.com/tendermint/tendermint/types/time" "github.com/kava-labs/kava/app" "github.com/kava-labs/kava/x/cdp" "github.com/kava-labs/kava/x/pricefeed" ) func init() { version.Name = "kava" config := sdk.GetConfig() app.SetBech32AddressPrefixes(config) app.SetBip44CoinType(config) config.Seal() keybase = getKeybase() } var ( keybase crkeys.Keybase ) func main() { // setup messages send to blockchain so it is in the correct state for testing sendProposal() sendDeposit() sendVote() sendDelegation() sendUndelegation() sendCoins() // create an XRP cdp and send to blockchain sendXrpCdp() // create a BTC cdp and send to blockchain sendBtcCdp() // reduce the price of BTC to trigger an auction sendMsgPostPrice() } // lower the price of xrp to trigger an auction func sendMsgPostPrice() { // get the address address := getTestAddress() // get the keyname and password keyname, password := getKeynameAndPassword() addr, err := sdk.AccAddressFromBech32(address) // validator address if err != nil { panic(err) } price, err := sdk.NewDecFromStr("1") if err != nil { panic(err) } // set the expiry time expiry := tmtime.Now().Add(time.Second * 100000) // create a cdp message to send to the blockchain // from, assetcode, price, expiry msg := pricefeed.NewMsgPostPrice( addr, "btc:usd", price, expiry, ) // helper methods for transactions cdc := app.MakeCodec() // make codec for the app // get the keybase keybase := getKeybase() // cast to the generic msg type msgToSend := []sdk.Msg{msg} // send the message to the blockchain sendMsgToBlockchain(cdc, address, keyname, password, msgToSend, keybase) } func sendBtcCdp() { // get the address address := getTestAddress() // get the keyname and password keyname, password := getKeynameAndPassword() addr, err := sdk.AccAddressFromBech32(address) // validator address if err != nil { panic(err) } // create a cdp message to send to the blockchain // sender, collateral, principal msg := cdp.NewMsgCreateCDP( addr, sdk.NewInt64Coin("btc", 200000000), sdk.NewInt64Coin("usdx", 10000000), "btc-a", ) // helper methods for transactions cdc := app.MakeCodec() // make codec for the app // get the keybase keybase := getKeybase() // cast to the generic msg type msgToSend := []sdk.Msg{msg} // send the message to the blockchain sendMsgToBlockchain(cdc, address, keyname, password, msgToSend, keybase) } func sendXrpCdp() { // get the address address := getTestAddress() // get the keyname and password keyname, password := getKeynameAndPassword() addr, err := sdk.AccAddressFromBech32(address) // validator address if err != nil { panic(err) } // create a cdp message to send to the blockchain // sender, collateral, principal msg := cdp.NewMsgCreateCDP( addr, sdk.NewInt64Coin("xrp", 200000000), sdk.NewInt64Coin("usdx", 10000000), "xrp-a", ) // helper methods for transactions cdc := app.MakeCodec() // make codec for the app // get the keybase keybase := getKeybase() // cast to the generic msg type msgToSend := []sdk.Msg{msg} // send the message to the blockchain sendMsgToBlockchain(cdc, address, keyname, password, msgToSend, keybase) } func sendProposal() { // get the address address := getTestAddress() // get the keyname and password keyname, password := getKeynameAndPassword() proposalContent := gov.ContentFromProposalType("A Test Title", "A test description on this proposal.", gov.ProposalTypeText) addr, err := sdk.AccAddressFromBech32(address) // validator address if err != nil { panic(err) } // create a message to send to the blockchain msg := gov.NewMsgSubmitProposal( proposalContent, sdk.NewCoins(sdk.NewInt64Coin("stake", 1000)), addr, ) // helper methods for transactions cdc := app.MakeCodec() // make codec for the app // get the keybase keybase := getKeybase() // SEND THE PROPOSAL // cast to the generic msg type msgToSend := []sdk.Msg{msg} // send the PROPOSAL message to the blockchain sendMsgToBlockchain(cdc, address, keyname, password, msgToSend, keybase) } func sendDeposit() { // get the address address := getTestAddress() // get the keyname and password keyname, password := getKeynameAndPassword() addr, err := sdk.AccAddressFromBech32(address) // validator if err != nil { panic(err) } // helper methods for transactions cdc := app.MakeCodec() // make codec for the app // get the keybase keybase := getKeybase() // NOW SEND THE DEPOSIT // create a deposit transaction to send to the proposal amount := sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 10000000)) deposit := gov.NewMsgDeposit(addr, 1, amount) // Note: '1' must match 'x-example' in swagger.yaml depositToSend := []sdk.Msg{deposit} sendMsgToBlockchain(cdc, address, keyname, password, depositToSend, keybase) } func sendVote() { // get the address address := getTestAddress() // get the keyname and password keyname, password := getKeynameAndPassword() addr, err := sdk.AccAddressFromBech32(address) // validator if err != nil { panic(err) } // helper methods for transactions cdc := app.MakeCodec() // make codec for the app // get the keybase keybase := getKeybase() // NOW SEND THE VOTE // create a vote on a proposal to send to the blockchain vote := gov.NewMsgVote(addr, uint64(1), types.OptionYes) // Note: '1' must match 'x-example' in swagger.yaml // send a vote to the blockchain voteToSend := []sdk.Msg{vote} sendMsgToBlockchain(cdc, address, keyname, password, voteToSend, keybase) } // this should send coins from one address to another func sendCoins() { // get the address address := getTestAddress() // get the keyname and password keyname, password := getKeynameAndPassword() addrFrom, err := sdk.AccAddressFromBech32(address) // validator if err != nil { panic(err) } addrTo, err := sdk.AccAddressFromBech32("kava1ls82zzghsx0exkpr52m8vht5jqs3un0ceysshz") // Note: must match the faucet address if err != nil { panic(err) } // helper methods for transactions cdc := app.MakeCodec() // make codec for the app // get the keybase keybase := getKeybase() // create coins amount := sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 2000000)) coins := bank.NewMsgSend(addrFrom, addrTo, amount) // Note: '1' must match 'x-example' in swagger.yaml coinsToSend := []sdk.Msg{coins} // NOW SEND THE COINS // send the coin message to the blockchain sendMsgToBlockchain(cdc, address, keyname, password, coinsToSend, keybase) } func getTestAddress() (address string) { // the test address - Note: this must match with startchain.sh address = "kava1ffv7nhd3z6sych2qpqkk03ec6hzkmufy0r2s4c" return address } func getKeynameAndPassword() (keyname string, password string) { keyname = "vlad" // Note: this must match the keys in the startchain.sh script password = "" // Note: this must match the keys in the startchain.sh script return keyname, password } // this should send a delegation func sendDelegation() { // get the address address := getTestAddress() // get the keyname and password keyname, password := getKeynameAndPassword() addrFrom, err := sdk.AccAddressFromBech32(address) // validator if err != nil { panic(err) } // helper methods for transactions cdc := app.MakeCodec() // make codec for the app // get the keybase keybase := getKeybase() // get the validator address for delegation valAddr, err := sdk.ValAddressFromBech32("kavavaloper1ffv7nhd3z6sych2qpqkk03ec6hzkmufyz4scd0") // **FAUCET** if err != nil { panic(err) } // create delegation amount delAmount := sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000000) delegation := staking.NewMsgDelegate(addrFrom, valAddr, delAmount) delegationToSend := []sdk.Msg{delegation} // send the delegation to the blockchain sendMsgToBlockchain(cdc, address, keyname, password, delegationToSend, keybase) } // this should send a MsgUndelegate func sendUndelegation() { // get the address address := getTestAddress() // get the keyname and password keyname, password := getKeynameAndPassword() addrFrom, err := sdk.AccAddressFromBech32(address) // validator if err != nil { panic(err) } // helper methods for transactions cdc := app.MakeCodec() // make codec for the app // get the keybase keybase := getKeybase() // get the validator address for delegation valAddr, err := sdk.ValAddressFromBech32("kavavaloper1ffv7nhd3z6sych2qpqkk03ec6hzkmufyz4scd0") // **FAUCET** if err != nil { panic(err) } // create delegation amount undelAmount := sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000000) undelegation := staking.NewMsgUndelegate(addrFrom, valAddr, undelAmount) delegationToSend := []sdk.Msg{undelegation} // send the delegation to the blockchain sendMsgToBlockchain(cdc, address, keyname, password, delegationToSend, keybase) } func getKeybase() crkeys.Keybase { if keybase != nil { return keybase } // create a keybase // IMPORTANT - TAKE THIS FROM COMMAND LINE PARAMETER and does NOT work with tilde i.e. ~/ does NOT work // myKeybase, err := keys.NewKeyBaseFromDir("/tmp/kvcliHome") inBuf := strings.NewReader("") keybase, err := crkeys.NewKeyring(sdk.KeyringServiceName(), "test", "/tmp/kvcliHome", inBuf) if err != nil { panic(err) } return keybase } // sendMsgToBlockchain sends a message to the blockchain via the rest api func sendMsgToBlockchain(cdc *codec.Codec, address string, keyname string, password string, msg []sdk.Msg, keybase crkeys.Keybase) { // get the account number and sequence number accountNumber, sequenceNumber := getAccountNumberAndSequenceNumber(cdc, address) txBldr := auth.NewTxBuilder( authclient.GetTxEncoder(cdc), accountNumber, sequenceNumber, 500000, 0, true, "testing", "memo", sdk.NewCoins(), sdk.NewDecCoins(), ).WithTxEncoder(authclient.GetTxEncoder(cdc)).WithChainID("testing"). WithKeybase(keybase).WithAccountNumber(accountNumber). WithSequence(sequenceNumber).WithGas(500000) // build and sign the transaction // this is the *Amino* encoded version of the transaction txBytes, err := txBldr.BuildAndSign("vlad", "", msg) if err != nil { panic(err) } // fmt.Printf("txBytes: %s", txBytes) // need to convert the Amino encoded version back to an actual go struct var tx auth.StdTx cdc.UnmarshalBinaryLengthPrefixed(txBytes, &tx) // might be unmarshal binary bare // now we re-marshall it again into json jsonBytes, err := cdc.MarshalJSON( authrest.BroadcastReq{ Tx: tx, Mode: "block", }, ) fmt.Printf("%s", bytes.NewBuffer(jsonBytes)) if err != nil { panic(err) } fmt.Println() fmt.Println("post body: ", string(jsonBytes)) fmt.Println() resp, err := http.Post("http://localhost:1317/txs", "application/json", bytes.NewBuffer(jsonBytes)) if err != nil { panic(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { panic(err) } fmt.Printf("\n\nBody:\n\n") fmt.Println(string(body)) } // getAccountNumberAndSequenceNumber gets an account number and sequence number from the blockchain func getAccountNumberAndSequenceNumber(cdc *codec.Codec, address string) (accountNumber uint64, sequenceNumber uint64) { // we need to setup the account number and sequence in order to have a valid transaction resp, err := http.Get("http://localhost:1317/auth/accounts/" + address) if err != nil { panic(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { panic(err) } var bodyUnmarshalled sdkrest.ResponseWithHeight err = cdc.UnmarshalJSON(body, &bodyUnmarshalled) if err != nil { panic(err) } var account authexported.Account err = cdc.UnmarshalJSON(bodyUnmarshalled.Result, &account) if err != nil { panic(err) } return account.GetAccountNumber(), account.GetSequence() }