209 lines
4.7 KiB
Go
209 lines
4.7 KiB
Go
package bank
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
)
|
|
|
|
// SendMsg - high level transaction of the coin module
|
|
type SendMsg struct {
|
|
Inputs []Input `json:"inputs"`
|
|
Outputs []Output `json:"outputs"`
|
|
}
|
|
|
|
var _ sdk.Msg = SendMsg{}
|
|
|
|
// NewSendMsg - construct arbitrary multi-in, multi-out send msg.
|
|
func NewSendMsg(in []Input, out []Output) SendMsg {
|
|
return SendMsg{Inputs: in, Outputs: out}
|
|
}
|
|
|
|
// Implements Msg.
|
|
func (msg SendMsg) Type() string { return "bank" } // TODO: "bank/send"
|
|
|
|
// Implements Msg.
|
|
func (msg SendMsg) ValidateBasic() sdk.Error {
|
|
// this just makes sure all the inputs and outputs are properly formatted,
|
|
// not that they actually have the money inside
|
|
if len(msg.Inputs) == 0 {
|
|
return ErrNoInputs().Trace("")
|
|
}
|
|
if len(msg.Outputs) == 0 {
|
|
return ErrNoOutputs().Trace("")
|
|
}
|
|
// make sure all inputs and outputs are individually valid
|
|
var totalIn, totalOut sdk.Coins
|
|
for _, in := range msg.Inputs {
|
|
if err := in.ValidateBasic(); err != nil {
|
|
return err.Trace("")
|
|
}
|
|
totalIn = totalIn.Plus(in.Coins)
|
|
}
|
|
for _, out := range msg.Outputs {
|
|
if err := out.ValidateBasic(); err != nil {
|
|
return err.Trace("")
|
|
}
|
|
totalOut = totalOut.Plus(out.Coins)
|
|
}
|
|
// make sure inputs and outputs match
|
|
if !totalIn.IsEqual(totalOut) {
|
|
return sdk.ErrInvalidCoins(totalIn.String()).Trace("inputs and outputs don't match")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (msg SendMsg) String() string {
|
|
return fmt.Sprintf("SendMsg{%v->%v}", msg.Inputs, msg.Outputs)
|
|
}
|
|
|
|
// Implements Msg.
|
|
func (msg SendMsg) Get(key interface{}) (value interface{}) {
|
|
return nil
|
|
}
|
|
|
|
// Implements Msg.
|
|
func (msg SendMsg) GetSignBytes() []byte {
|
|
b, err := json.Marshal(msg) // XXX: ensure some canonical form
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return b
|
|
}
|
|
|
|
// Implements Msg.
|
|
func (msg SendMsg) GetSigners() []sdk.Address {
|
|
addrs := make([]sdk.Address, len(msg.Inputs))
|
|
for i, in := range msg.Inputs {
|
|
addrs[i] = in.Address
|
|
}
|
|
return addrs
|
|
}
|
|
|
|
//----------------------------------------
|
|
// IssueMsg
|
|
|
|
// IssueMsg - high level transaction of the coin module
|
|
type IssueMsg struct {
|
|
Banker sdk.Address `json:"banker"`
|
|
Outputs []Output `json:"outputs"`
|
|
}
|
|
|
|
// NewIssueMsg - construct arbitrary multi-in, multi-out send msg.
|
|
func NewIssueMsg(banker sdk.Address, out []Output) IssueMsg {
|
|
return IssueMsg{Banker: banker, Outputs: out}
|
|
}
|
|
|
|
// Implements Msg.
|
|
func (msg IssueMsg) Type() string { return "bank" } // TODO: "bank/issue"
|
|
|
|
// Implements Msg.
|
|
func (msg IssueMsg) ValidateBasic() sdk.Error {
|
|
// XXX
|
|
if len(msg.Outputs) == 0 {
|
|
return ErrNoOutputs().Trace("")
|
|
}
|
|
for _, out := range msg.Outputs {
|
|
if err := out.ValidateBasic(); err != nil {
|
|
return err.Trace("")
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (msg IssueMsg) String() string {
|
|
return fmt.Sprintf("IssueMsg{%v#%v}", msg.Banker, msg.Outputs)
|
|
}
|
|
|
|
// Implements Msg.
|
|
func (msg IssueMsg) Get(key interface{}) (value interface{}) {
|
|
return nil
|
|
}
|
|
|
|
// Implements Msg.
|
|
func (msg IssueMsg) GetSignBytes() []byte {
|
|
b, err := json.Marshal(msg) // XXX: ensure some canonical form
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return b
|
|
}
|
|
|
|
// Implements Msg.
|
|
func (msg IssueMsg) GetSigners() []sdk.Address {
|
|
return []sdk.Address{msg.Banker}
|
|
}
|
|
|
|
//----------------------------------------
|
|
// Input
|
|
|
|
// Transaction Output
|
|
type Input struct {
|
|
Address sdk.Address `json:"address"`
|
|
Coins sdk.Coins `json:"coins"`
|
|
}
|
|
|
|
// ValidateBasic - validate transaction input
|
|
func (in Input) ValidateBasic() sdk.Error {
|
|
if len(in.Address) == 0 {
|
|
return sdk.ErrInvalidAddress(in.Address.String())
|
|
}
|
|
if !in.Coins.IsValid() {
|
|
return sdk.ErrInvalidCoins(in.Coins.String())
|
|
}
|
|
if !in.Coins.IsPositive() {
|
|
return sdk.ErrInvalidCoins(in.Coins.String())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (in Input) String() string {
|
|
return fmt.Sprintf("Input{%v,%v}", in.Address, in.Coins)
|
|
}
|
|
|
|
// NewInput - create a transaction input, used with SendMsg
|
|
func NewInput(addr sdk.Address, coins sdk.Coins) Input {
|
|
input := Input{
|
|
Address: addr,
|
|
Coins: coins,
|
|
}
|
|
return input
|
|
}
|
|
|
|
//----------------------------------------
|
|
// Output
|
|
|
|
// Transaction Output
|
|
type Output struct {
|
|
Address sdk.Address `json:"address"`
|
|
Coins sdk.Coins `json:"coins"`
|
|
}
|
|
|
|
// ValidateBasic - validate transaction output
|
|
func (out Output) ValidateBasic() sdk.Error {
|
|
if len(out.Address) == 0 {
|
|
return sdk.ErrInvalidAddress(out.Address.String())
|
|
}
|
|
if !out.Coins.IsValid() {
|
|
return sdk.ErrInvalidCoins(out.Coins.String())
|
|
}
|
|
if !out.Coins.IsPositive() {
|
|
return sdk.ErrInvalidCoins(out.Coins.String())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (out Output) String() string {
|
|
return fmt.Sprintf("Output{%X,%v}", out.Address, out.Coins)
|
|
}
|
|
|
|
// NewOutput - create a transaction output, used with SendMsg
|
|
func NewOutput(addr sdk.Address, coins sdk.Coins) Output {
|
|
output := Output{
|
|
Address: addr,
|
|
Coins: coins,
|
|
}
|
|
return output
|
|
}
|