[rosetta] implement balance tracking and redo tx construction (#8729)
Co-authored-by: Alessio Treglia <alessio@tendermint.com> Co-authored-by: Robert Zaremba <robert@zaremba.ch>
This commit is contained in:
co-authored by
Alessio Treglia
Robert Zaremba
parent
280ee4f15e
commit
288f8dda4b
@@ -1,13 +1,6 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/coinbase/rosetta-sdk-go/types"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
@@ -69,83 +62,6 @@ func (msg MsgSend) GetSigners() []sdk.AccAddress {
|
||||
return []sdk.AccAddress{from}
|
||||
}
|
||||
|
||||
// Rosetta interface
|
||||
func (msg *MsgSend) ToOperations(withStatus bool, hasError bool) []*types.Operation {
|
||||
var operations []*types.Operation
|
||||
|
||||
fromAddress := msg.FromAddress
|
||||
toAddress := msg.ToAddress
|
||||
amounts := msg.Amount
|
||||
if len(amounts) == 0 {
|
||||
return []*types.Operation{}
|
||||
}
|
||||
|
||||
coin := amounts[0]
|
||||
sendOp := func(account, amount string, index int) *types.Operation {
|
||||
var status string
|
||||
if withStatus {
|
||||
status = "Success"
|
||||
if hasError {
|
||||
status = "Reverted"
|
||||
}
|
||||
}
|
||||
return &types.Operation{
|
||||
OperationIdentifier: &types.OperationIdentifier{
|
||||
Index: int64(index),
|
||||
},
|
||||
Type: proto.MessageName(msg),
|
||||
Status: status,
|
||||
Account: &types.AccountIdentifier{
|
||||
Address: account,
|
||||
},
|
||||
Amount: &types.Amount{
|
||||
Value: amount,
|
||||
Currency: &types.Currency{
|
||||
Symbol: coin.Denom,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
operations = append(operations,
|
||||
sendOp(fromAddress, "-"+coin.Amount.String(), 0),
|
||||
sendOp(toAddress, coin.Amount.String(), 1),
|
||||
)
|
||||
|
||||
return operations
|
||||
}
|
||||
|
||||
func (msg MsgSend) FromOperations(ops []*types.Operation) (sdk.Msg, error) {
|
||||
var (
|
||||
from, to sdk.AccAddress
|
||||
sendAmt sdk.Coin
|
||||
err error
|
||||
)
|
||||
|
||||
for _, op := range ops {
|
||||
if strings.HasPrefix(op.Amount.Value, "-") {
|
||||
from, err = sdk.AccAddressFromBech32(op.Account.Address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
to, err = sdk.AccAddressFromBech32(op.Account.Address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
amount, err := strconv.ParseInt(op.Amount.Value, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid amount")
|
||||
}
|
||||
|
||||
sendAmt = sdk.NewCoin(op.Amount.Currency.Symbol, sdk.NewInt(amount))
|
||||
}
|
||||
|
||||
return NewMsgSend(from, to, sdk.NewCoins(sendAmt)), nil
|
||||
}
|
||||
|
||||
var _ sdk.Msg = &MsgMultiSend{}
|
||||
|
||||
// NewMsgMultiSend - construct arbitrary multi-in, multi-out send msg.
|
||||
|
||||
@@ -2,12 +2,6 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
rosettatypes "github.com/coinbase/rosetta-sdk-go/types"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/server/rosetta"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
@@ -96,50 +90,6 @@ func (msg MsgWithdrawDelegatorReward) ValidateBasic() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (msg *MsgWithdrawDelegatorReward) ToOperations(withStatus, hasError bool) []*rosettatypes.Operation {
|
||||
|
||||
var status string
|
||||
if withStatus {
|
||||
status = rosetta.StatusSuccess
|
||||
if hasError {
|
||||
status = rosetta.StatusReverted
|
||||
}
|
||||
}
|
||||
|
||||
op := &rosettatypes.Operation{
|
||||
OperationIdentifier: &rosettatypes.OperationIdentifier{
|
||||
Index: 0,
|
||||
},
|
||||
RelatedOperations: nil,
|
||||
Type: proto.MessageName(msg),
|
||||
Status: status,
|
||||
Account: &rosettatypes.AccountIdentifier{
|
||||
Address: msg.DelegatorAddress,
|
||||
SubAccount: &rosettatypes.SubAccountIdentifier{
|
||||
Address: msg.ValidatorAddress,
|
||||
},
|
||||
},
|
||||
}
|
||||
return []*rosettatypes.Operation{op}
|
||||
}
|
||||
|
||||
func (msg *MsgWithdrawDelegatorReward) FromOperations(ops []*rosettatypes.Operation) (sdk.Msg, error) {
|
||||
if len(ops) != 1 {
|
||||
return nil, fmt.Errorf("expected one operation")
|
||||
}
|
||||
op := ops[0]
|
||||
if op.Account == nil {
|
||||
return nil, fmt.Errorf("account identifier must be specified")
|
||||
}
|
||||
if op.Account.SubAccount == nil {
|
||||
return nil, fmt.Errorf("account identifier subaccount must be specified")
|
||||
}
|
||||
return &MsgWithdrawDelegatorReward{
|
||||
DelegatorAddress: op.Account.Address,
|
||||
ValidatorAddress: op.Account.SubAccount.Address,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func NewMsgWithdrawValidatorCommission(valAddr sdk.ValAddress) *MsgWithdrawValidatorCommission {
|
||||
return &MsgWithdrawValidatorCommission{
|
||||
ValidatorAddress: valAddr.String(),
|
||||
|
||||
@@ -2,17 +2,9 @@ package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/gogo/protobuf/proto"
|
||||
|
||||
rosettatypes "github.com/coinbase/rosetta-sdk-go/types"
|
||||
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
"github.com/cosmos/cosmos-sdk/server/rosetta"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
@@ -264,90 +256,6 @@ func (msg MsgDelegate) ValidateBasic() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Rosetta Msg interface.
|
||||
func (msg *MsgDelegate) ToOperations(withStatus bool, hasError bool) []*rosettatypes.Operation {
|
||||
var operations []*rosettatypes.Operation
|
||||
delAddr := msg.DelegatorAddress
|
||||
valAddr := msg.ValidatorAddress
|
||||
coin := msg.Amount
|
||||
delOp := func(account *rosettatypes.AccountIdentifier, amount string, index int) *rosettatypes.Operation {
|
||||
var status string
|
||||
if withStatus {
|
||||
status = rosetta.StatusSuccess
|
||||
if hasError {
|
||||
status = rosetta.StatusReverted
|
||||
}
|
||||
}
|
||||
return &rosettatypes.Operation{
|
||||
OperationIdentifier: &rosettatypes.OperationIdentifier{
|
||||
Index: int64(index),
|
||||
},
|
||||
Type: proto.MessageName(msg),
|
||||
Status: status,
|
||||
Account: account,
|
||||
Amount: &rosettatypes.Amount{
|
||||
Value: amount,
|
||||
Currency: &rosettatypes.Currency{
|
||||
Symbol: coin.Denom,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
delAcc := &rosettatypes.AccountIdentifier{
|
||||
Address: delAddr,
|
||||
}
|
||||
valAcc := &rosettatypes.AccountIdentifier{
|
||||
Address: "staking_account",
|
||||
SubAccount: &rosettatypes.SubAccountIdentifier{
|
||||
Address: valAddr,
|
||||
},
|
||||
}
|
||||
operations = append(operations,
|
||||
delOp(delAcc, "-"+coin.Amount.String(), 0),
|
||||
delOp(valAcc, coin.Amount.String(), 1),
|
||||
)
|
||||
return operations
|
||||
}
|
||||
|
||||
func (msg *MsgDelegate) FromOperations(ops []*rosettatypes.Operation) (sdk.Msg, error) {
|
||||
var (
|
||||
delAddr sdk.AccAddress
|
||||
valAddr sdk.ValAddress
|
||||
sendAmt sdk.Coin
|
||||
err error
|
||||
)
|
||||
|
||||
for _, op := range ops {
|
||||
if strings.HasPrefix(op.Amount.Value, "-") {
|
||||
if op.Account == nil {
|
||||
return nil, fmt.Errorf("account identifier must be specified")
|
||||
}
|
||||
delAddr, err = sdk.AccAddressFromBech32(op.Account.Address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if op.Account.SubAccount == nil {
|
||||
return nil, fmt.Errorf("account identifier subaccount must be specified")
|
||||
}
|
||||
valAddr, err = sdk.ValAddressFromBech32(op.Account.SubAccount.Address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
amount, err := strconv.ParseInt(op.Amount.Value, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid amount: %w", err)
|
||||
}
|
||||
|
||||
sendAmt = sdk.NewCoin(op.Amount.Currency.Symbol, sdk.NewInt(amount))
|
||||
}
|
||||
|
||||
return NewMsgDelegate(delAddr, valAddr, sendAmt), nil
|
||||
}
|
||||
|
||||
// NewMsgBeginRedelegate creates a new MsgBeginRedelegate instance.
|
||||
//nolint:interfacer
|
||||
func NewMsgBeginRedelegate(
|
||||
@@ -403,103 +311,6 @@ func (msg MsgBeginRedelegate) ValidateBasic() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Rosetta Msg interface.
|
||||
func (msg *MsgBeginRedelegate) ToOperations(withStatus bool, hasError bool) []*rosettatypes.Operation {
|
||||
var operations []*rosettatypes.Operation
|
||||
delAddr := msg.DelegatorAddress
|
||||
srcValAddr := msg.ValidatorSrcAddress
|
||||
destValAddr := msg.ValidatorDstAddress
|
||||
coin := msg.Amount
|
||||
delOp := func(account *rosettatypes.AccountIdentifier, amount string, index int) *rosettatypes.Operation {
|
||||
var status string
|
||||
if withStatus {
|
||||
status = rosetta.StatusSuccess
|
||||
if hasError {
|
||||
status = rosetta.StatusReverted
|
||||
}
|
||||
}
|
||||
return &rosettatypes.Operation{
|
||||
OperationIdentifier: &rosettatypes.OperationIdentifier{
|
||||
Index: int64(index),
|
||||
},
|
||||
Type: proto.MessageName(msg),
|
||||
Status: status,
|
||||
Account: account,
|
||||
Amount: &rosettatypes.Amount{
|
||||
Value: amount,
|
||||
Currency: &rosettatypes.Currency{
|
||||
Symbol: coin.Denom,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
srcValAcc := &rosettatypes.AccountIdentifier{
|
||||
Address: delAddr,
|
||||
SubAccount: &rosettatypes.SubAccountIdentifier{
|
||||
Address: srcValAddr,
|
||||
},
|
||||
}
|
||||
destValAcc := &rosettatypes.AccountIdentifier{
|
||||
Address: "staking_account",
|
||||
SubAccount: &rosettatypes.SubAccountIdentifier{
|
||||
Address: destValAddr,
|
||||
},
|
||||
}
|
||||
operations = append(operations,
|
||||
delOp(srcValAcc, "-"+coin.Amount.String(), 0),
|
||||
delOp(destValAcc, coin.Amount.String(), 1),
|
||||
)
|
||||
return operations
|
||||
}
|
||||
|
||||
func (msg *MsgBeginRedelegate) FromOperations(ops []*rosettatypes.Operation) (sdk.Msg, error) {
|
||||
var (
|
||||
delAddr sdk.AccAddress
|
||||
srcValAddr sdk.ValAddress
|
||||
destValAddr sdk.ValAddress
|
||||
sendAmt sdk.Coin
|
||||
err error
|
||||
)
|
||||
|
||||
for _, op := range ops {
|
||||
if strings.HasPrefix(op.Amount.Value, "-") {
|
||||
if op.Account == nil {
|
||||
return nil, fmt.Errorf("account identifier must be specified")
|
||||
}
|
||||
delAddr, err = sdk.AccAddressFromBech32(op.Account.Address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if op.Account.SubAccount == nil {
|
||||
return nil, fmt.Errorf("account identifier subaccount must be specified")
|
||||
}
|
||||
srcValAddr, err = sdk.ValAddressFromBech32(op.Account.SubAccount.Address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if op.Account.SubAccount == nil {
|
||||
return nil, fmt.Errorf("account identifier subaccount must be specified")
|
||||
}
|
||||
destValAddr, err = sdk.ValAddressFromBech32(op.Account.SubAccount.Address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
amount, err := strconv.ParseInt(op.Amount.Value, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid amount: %w", err)
|
||||
}
|
||||
|
||||
sendAmt = sdk.NewCoin(op.Amount.Currency.Symbol, sdk.NewInt(amount))
|
||||
}
|
||||
|
||||
return NewMsgBeginRedelegate(delAddr, srcValAddr, destValAddr, sendAmt), nil
|
||||
}
|
||||
|
||||
// NewMsgUndelegate creates a new MsgUndelegate instance.
|
||||
//nolint:interfacer
|
||||
func NewMsgUndelegate(delAddr sdk.AccAddress, valAddr sdk.ValAddress, amount sdk.Coin) *MsgUndelegate {
|
||||
@@ -547,88 +358,3 @@ func (msg MsgUndelegate) ValidateBasic() error {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Rosetta Msg interface.
|
||||
func (msg *MsgUndelegate) ToOperations(withStatus bool, hasError bool) []*rosettatypes.Operation {
|
||||
var operations []*rosettatypes.Operation
|
||||
delAddr := msg.DelegatorAddress
|
||||
valAddr := msg.ValidatorAddress
|
||||
coin := msg.Amount
|
||||
delOp := func(account *rosettatypes.AccountIdentifier, amount string, index int) *rosettatypes.Operation {
|
||||
var status string
|
||||
if withStatus {
|
||||
status = rosetta.StatusSuccess
|
||||
if hasError {
|
||||
status = rosetta.StatusReverted
|
||||
}
|
||||
}
|
||||
return &rosettatypes.Operation{
|
||||
OperationIdentifier: &rosettatypes.OperationIdentifier{
|
||||
Index: int64(index),
|
||||
},
|
||||
Type: proto.MessageName(msg),
|
||||
Status: status,
|
||||
Account: account,
|
||||
Amount: &rosettatypes.Amount{
|
||||
Value: amount,
|
||||
Currency: &rosettatypes.Currency{
|
||||
Symbol: coin.Denom,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
delAcc := &rosettatypes.AccountIdentifier{
|
||||
Address: delAddr,
|
||||
}
|
||||
valAcc := &rosettatypes.AccountIdentifier{
|
||||
Address: "staking_account",
|
||||
SubAccount: &rosettatypes.SubAccountIdentifier{
|
||||
Address: valAddr,
|
||||
},
|
||||
}
|
||||
operations = append(operations,
|
||||
delOp(valAcc, "-"+coin.Amount.String(), 0),
|
||||
delOp(delAcc, coin.Amount.String(), 1),
|
||||
)
|
||||
return operations
|
||||
}
|
||||
|
||||
func (msg *MsgUndelegate) FromOperations(ops []*rosettatypes.Operation) (sdk.Msg, error) {
|
||||
var (
|
||||
delAddr sdk.AccAddress
|
||||
valAddr sdk.ValAddress
|
||||
undelAmt sdk.Coin
|
||||
err error
|
||||
)
|
||||
|
||||
for _, op := range ops {
|
||||
if strings.HasPrefix(op.Amount.Value, "-") {
|
||||
if op.Account.SubAccount == nil {
|
||||
return nil, fmt.Errorf("account identifier subaccount must be specified")
|
||||
}
|
||||
valAddr, err = sdk.ValAddressFromBech32(op.Account.SubAccount.Address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if op.Account == nil {
|
||||
return nil, fmt.Errorf("account identifier must be specified")
|
||||
}
|
||||
|
||||
delAddr, err = sdk.AccAddressFromBech32(op.Account.Address)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
amount, err := strconv.ParseInt(op.Amount.Value, 10, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid amount")
|
||||
}
|
||||
|
||||
undelAmt = sdk.NewCoin(op.Amount.Currency.Symbol, sdk.NewInt(amount))
|
||||
}
|
||||
|
||||
return NewMsgUndelegate(delAddr, valAddr, undelAmt), nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user