Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(x/ecocredit): add tx bridge cmd #1636

Merged
merged 4 commits into from
Nov 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [#1623](https://github.com/regen-network/regen-ledger/pull/1623) Add `Msg/UpdateBatchMetadata`
- [#1625](https://github.com/regen-network/regen-ledger/pull/1625) Add `reason`/`retirement_reason`
- [#1634](https://github.com/regen-network/regen-ledger/pull/1634) Add `balances-by-batch` query command
- [#1636](https://github.com/regen-network/regen-ledger/pull/1636) Add `bridge` transaction command

#### Changed

Expand Down
67 changes: 61 additions & 6 deletions x/ecocredit/base/client/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ regen tx ecocredit create-class regen1elq7ys34gpkj3jyvqee0h6yk4h9wsfxmgqelsw,reg
// Get the class admin from the --from flag
admin := clientCtx.GetFromAddress()

// Parse the comma-separated list of issuers
// parse the comma-separated list of issuers
issuers := strings.Split(args[0], ",")
for i := range issuers {
issuers[i] = strings.TrimSpace(issuers[i])
Expand All @@ -82,7 +82,7 @@ regen tx ecocredit create-class regen1elq7ys34gpkj3jyvqee0h6yk4h9wsfxmgqelsw,reg
CreditTypeAbbrev: args[1],
}

// Parse and normalize credit class fee
// parse and normalize credit class fee
feeString, err := cmd.Flags().GetString(FlagClassFee)
if err != nil {
return err
Expand Down Expand Up @@ -267,7 +267,7 @@ Example JSON:
return err
}

// Parse the JSON file representing the request
// parse the JSON file representing the request
msg, err := parseMsgCreateBatch(clientCtx, args[0])
if err != nil {
return sdkerrors.ErrInvalidRequest.Wrapf("failed to parse json: %s", err)
Expand Down Expand Up @@ -368,7 +368,7 @@ Example JSON:
return err
}

// Parse the JSON file representing the credits
// parse the JSON file representing the credits
credits, err := parseSendCredits(args[1])
if err != nil {
return sdkerrors.ErrInvalidRequest.Wrapf("failed to parse json: %s", err)
Expand Down Expand Up @@ -419,7 +419,7 @@ Example JSON:
return err
}

// Parse the JSON file representing the credits
// parse the JSON file representing the credits
credits, err := parseCredits(args[0])
if err != nil {
return sdkerrors.ErrInvalidRequest.Wrapf("failed to parse json: %s", err)
Expand Down Expand Up @@ -470,7 +470,7 @@ Example JSON:
return err
}

// Parse the JSON file representing the credits
// parse the JSON file representing the credits
credits, err := parseCredits(args[0])
if err != nil {
return sdkerrors.ErrInvalidRequest.Wrapf("failed to parse json: %s", err)
Expand Down Expand Up @@ -717,3 +717,58 @@ Parameters:

return txFlags(cmd)
}

// TxBridgeCmd returns a transaction command that bridges credits to another chain.
func TxBridgeCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "bridge [target] [recipient] [credits-json]",
Short: "Bridge credits to another chain",
Long: `Bridge credits to another chain.

The '--from' flag must equal the owner of the credits.

Parameters:

- target: the target chain (e.g. "polygon")
- recipient: the address of the recipient on the other chain
- credits-json: path to JSON file containing credits to bridge`,
Example: `regen tx ecocredit bridge polygon 0x0000000000000000000000000000000000000001 credits.json

Example JSON:

[
{
"batch_denom": "C01-001-20200101-20210101-001",
"amount": "5"
},
{
"batch_denom": "C01-001-20200101-20210101-002",
"amount": "10"
}
]`,
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := sdkclient.GetClientTxContext(cmd)
if err != nil {
return err
}

// parse the JSON file representing the credits
credits, err := parseCredits(args[2])
if err != nil {
return sdkerrors.ErrInvalidRequest.Wrapf("failed to parse json: %s", err)
}

msg := types.MsgBridge{
Owner: clientCtx.GetFromAddress().String(),
Target: args[0],
Recipient: args[1],
Credits: credits,
}

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), &msg)
},
}

return txFlags(cmd)
}
8 changes: 8 additions & 0 deletions x/ecocredit/client/testsuite/suite.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,14 @@ func (s *IntegrationTestSuite) setupGenesis() {
})
require.NoError(err)

// set batch contract for bridge testing
err = baseStore.BatchContractTable().Insert(ctx, &baseapi.BatchContract{
BatchKey: 1,
ClassKey: 1,
Contract: "0x0000000000000000000000000000000000000000",
})
require.NoError(err)

// export genesis into target
target := ormjson.NewRawMessageTarget()
err = mdb.ExportJSON(ctx, target)
Expand Down
149 changes: 141 additions & 8 deletions x/ecocredit/client/testsuite/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ func (s *IntegrationTestSuite) TestTxSendBulkCmd() {
}
}

func (s *IntegrationTestSuite) TestTxRetire() {
func (s *IntegrationTestSuite) TestTxRetireCmd() {
require := s.Require()

owner := s.addr1.String()
Expand Down Expand Up @@ -662,7 +662,7 @@ func (s *IntegrationTestSuite) TestTxRetire() {
}
}

func (s *IntegrationTestSuite) TestTxCancel() {
func (s *IntegrationTestSuite) TestTxCancelCmd() {
require := s.Require()

owner := s.addr1.String()
Expand Down Expand Up @@ -785,7 +785,7 @@ func (s *IntegrationTestSuite) TestTxCancel() {
}
}

func (s *IntegrationTestSuite) TestTxUpdateClassAdmin() {
func (s *IntegrationTestSuite) TestTxUpdateClassAdminCmd() {
require := s.Require()

admin := s.addr1.String()
Expand Down Expand Up @@ -892,7 +892,7 @@ func (s *IntegrationTestSuite) TestTxUpdateClassAdmin() {
}
}

func (s *IntegrationTestSuite) TestTxUpdateIssuers() {
func (s *IntegrationTestSuite) TestTxUpdateIssuersCmd() {
require := s.Require()

admin := s.addr1.String()
Expand Down Expand Up @@ -986,7 +986,7 @@ func (s *IntegrationTestSuite) TestTxUpdateIssuers() {
}
}

func (s *IntegrationTestSuite) TestTxUpdateClassMetadata() {
func (s *IntegrationTestSuite) TestTxUpdateClassMetadataCmd() {
require := s.Require()

admin := s.addr1.String()
Expand Down Expand Up @@ -1065,7 +1065,7 @@ func (s *IntegrationTestSuite) TestTxUpdateClassMetadata() {
}
}

func (s *IntegrationTestSuite) TestUpdateProjectAdmin() {
func (s *IntegrationTestSuite) TestTxUpdateProjectAdminCmd() {
require := s.Require()

admin := s.addr1.String()
Expand Down Expand Up @@ -1172,7 +1172,7 @@ func (s *IntegrationTestSuite) TestUpdateProjectAdmin() {
}
}

func (s *IntegrationTestSuite) TestUpdateProjectMetadata() {
func (s *IntegrationTestSuite) TestTxUpdateProjectMetadataCmd() {
require := s.Require()

admin := s.addr1.String()
Expand Down Expand Up @@ -1251,7 +1251,7 @@ func (s *IntegrationTestSuite) TestUpdateProjectMetadata() {
}
}

func (s *IntegrationTestSuite) TestUpdateBatchMetadata() {
func (s *IntegrationTestSuite) TestTxUpdateBatchMetadataCmd() {
require := s.Require()

issuer := s.addr1.String()
Expand Down Expand Up @@ -1329,3 +1329,136 @@ func (s *IntegrationTestSuite) TestUpdateBatchMetadata() {
})
}
}

func (s *IntegrationTestSuite) TestTxBridgeCmd() {
require := s.Require()

owner := s.addr1.String()

// using json package because array is not a proto message
bz, err := json.Marshal([]types.Credits{
{
BatchDenom: s.batchDenom,
Amount: "10",
},
{
BatchDenom: s.batchDenom,
Amount: "10",
},
})
require.NoError(err)

validJSON := testutil.WriteToNewTempFile(s.T(), string(bz)).Name()
invalidJSON := testutil.WriteToNewTempFile(s.T(), `{foo:bar}`).Name()
duplicateJSON := testutil.WriteToNewTempFile(s.T(), `{"foo":"bar","foo":"bar"`).Name()

testCases := []struct {
name string
args []string
expErr bool
expErrMsg string
}{
{
name: "missing args",
args: []string{"foo", "bar"},
expErr: true,
expErrMsg: "Error: accepts 3 arg(s), received 2",
},
{
name: "too many args",
args: []string{"foo", "bar", "baz", "foo"},
expErr: true,
expErrMsg: "Error: accepts 3 arg(s), received 4",
},
{
name: "missing from flag",
args: []string{
s.bridgeChain,
"0x0000000000000000000000000000000000000001",
validJSON,
},
expErr: true,
expErrMsg: "Error: required flag(s) \"from\" not set",
},
{
name: "invalid json file",
args: []string{
s.bridgeChain,
"0x0000000000000000000000000000000000000001",
"foo.bar",
fmt.Sprintf("--%s=%s", flags.FlagFrom, owner),
},
expErr: true,
expErrMsg: "no such file or directory",
},
{
name: "invalid json format",
args: []string{
s.bridgeChain,
"0x0000000000000000000000000000000000000001",
invalidJSON,
fmt.Sprintf("--%s=%s", flags.FlagFrom, owner),
},
expErr: true,
expErrMsg: "failed to parse json: invalid character",
},
{
name: "duplicate json key",
args: []string{
s.bridgeChain,
"0x0000000000000000000000000000000000000001",
duplicateJSON,
fmt.Sprintf("--%s=%s", flags.FlagFrom, owner),
},
expErr: true,
expErrMsg: "failed to parse json: duplicate key",
},
{
name: "valid",
args: []string{
s.bridgeChain,
"0x0000000000000000000000000000000000000001",
validJSON,
fmt.Sprintf("--%s=%s", flags.FlagFrom, owner),
},
},
{
name: "valid from key-name",
args: []string{
s.bridgeChain,
"0x0000000000000000000000000000000000000001",
validJSON,
fmt.Sprintf("--%s=%s", flags.FlagFrom, s.val.Moniker),
},
},
{
name: "valid with amino-json",
args: []string{
s.bridgeChain,
"0x0000000000000000000000000000000000000001",
validJSON,
fmt.Sprintf("--%s=%s", flags.FlagFrom, owner),
fmt.Sprintf("--%s=%s", flags.FlagSignMode, flags.SignModeLegacyAminoJSON),
},
},
}

for _, tc := range testCases {
args := tc.args
s.Run(tc.name, func() {
cmd := client.TxBridgeCmd()
args = append(args, s.commonTxFlags()...)
out, err := cli.ExecTestCLICmd(s.val.ClientCtx, cmd, args)
if tc.expErr {
require.Error(err)
require.Contains(out.String(), tc.expErrMsg)
} else {
require.NoError(err)

var res sdk.TxResponse
require.NoError(s.val.ClientCtx.Codec.UnmarshalJSON(out.Bytes(), &res))
require.Zero(res.Code, res.RawLog)
}
})
}
}
1 change: 1 addition & 0 deletions x/ecocredit/client/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ func TxCmd(name string) *cobra.Command {
baseclient.TxUpdateProjectAdminCmd(),
baseclient.TxUpdateProjectMetadataCmd(),
baseclient.TxUpdateBatchMetadataCmd(),
baseclient.TxBridgeCmd(),
basketclient.TxCreateBasketCmd(),
basketclient.TxPutInBasketCmd(),
basketclient.TxTakeFromBasketCmd(),
Expand Down