diff --git a/e2e/fiat_tf_test.go b/e2e/fiat_tf_test.go new file mode 100644 index 00000000..e45aaa7a --- /dev/null +++ b/e2e/fiat_tf_test.go @@ -0,0 +1,173 @@ +package e2e_test + +import ( + "context" + "testing" + + "cosmossdk.io/math" + fiattokenfactorytypes "github.com/circlefin/noble-fiattokenfactory/x/fiattokenfactory/types" + "github.com/noble-assets/noble/e2e" + "github.com/strangelove-ventures/interchaintest/v8" + "github.com/stretchr/testify/require" +) + +func TestFiatTFUpdateOwner(t *testing.T) { + if testing.Short() { + t.Skip() + } + t.Parallel() + + ctx := context.Background() + nw := e2e.NobleSpinUp(t, ctx, true) + noble := nw.Chain + val := noble.Validators[0] + + // ACTION: Update owner while TF is paused + // EXPECTED: Success; Pending owner set + + e2e.PauseFiatTF(t, ctx, val, nw.FiatTfRoles.Pauser) + + w := interchaintest.GetAndFundTestUsers(t, ctx, "new-owner-1", math.OneInt(), noble) + newOwner1 := w[0] + + _, err := val.ExecTx(ctx, nw.FiatTfRoles.Owner.KeyName(), "fiat-tokenfactory", "update-owner", newOwner1.FormattedAddress()) + require.NoError(t, err, "error broadcasting update owner message") + + e2e.UnpauseFiatTF(t, ctx, val, nw.FiatTfRoles.Pauser) + + // ACTION: Update owner from unprivileged account + // EXPECTED: Request fails; pending owner not set + + w = interchaintest.GetAndFundTestUsers(t, ctx, "alice", math.OneInt(), noble) + alice := w[0] + + _, err = val.ExecTx(ctx, alice.KeyName(), "fiat-tokenfactory", "update-owner", newOwner1.FormattedAddress()) + require.ErrorContains(t, err, "you are not the owner: unauthorized") + + // ACTION: Update Owner from blacklisted owner account + // EXPECTED: Success; pending owner set + + e2e.BlacklistAccount(t, ctx, val, nw.FiatTfRoles.Blacklister, nw.FiatTfRoles.Owner) + + _, err = val.ExecTx(ctx, nw.FiatTfRoles.Owner.KeyName(), "fiat-tokenfactory", "update-owner", newOwner1.FormattedAddress()) + require.NoError(t, err, "error broadcasting update owner message") + + // ACTION: Update Owner to a blacklisted account + // EXPECTED: Success; pending owner set + + e2e.BlacklistAccount(t, ctx, val, nw.FiatTfRoles.Blacklister, newOwner1) + + _, err = val.ExecTx(ctx, nw.FiatTfRoles.Owner.KeyName(), "fiat-tokenfactory", "update-owner", newOwner1.FormattedAddress()) + require.NoError(t, err, "error broadcasting update owner message") +} + +func TestFiatTFAcceptOwner(t *testing.T) { + if testing.Short() { + t.Skip() + } + t.Parallel() + + ctx := context.Background() + nw := e2e.NobleSpinUp(t, ctx, true) + noble := nw.Chain + val := noble.Validators[0] + + // ACTION: Happy path: accept owner + // EXPECTED: Success; pending owner accepted + + w := interchaintest.GetAndFundTestUsers(t, ctx, "new-owner-1", math.OneInt(), noble) + newOwner1 := w[0] + + _, err := val.ExecTx(ctx, nw.FiatTfRoles.Owner.KeyName(), "fiat-tokenfactory", "update-owner", newOwner1.FormattedAddress()) + require.NoError(t, err, "error broadcasting update owner message") + + _, err = val.ExecTx(ctx, newOwner1.KeyName(), "fiat-tokenfactory", "accept-owner") + require.NoError(t, err, "failed to accept owner") + + showOwnerRes, err := e2e.ShowOwner(ctx, val) + require.NoError(t, err, "failed to query show-owner") + expectedOwnerResponse := fiattokenfactorytypes.QueryGetOwnerResponse{ + Owner: fiattokenfactorytypes.Owner{ + Address: newOwner1.FormattedAddress(), + }, + } + require.Equal(t, expectedOwnerResponse.Owner, showOwnerRes.Owner) + + // ACTION: Accept owner when no pending owner is set + // EXPECTED: Request fails; pending owner not set + // Status: + // Owner: newOwner1 + + w = interchaintest.GetAndFundTestUsers(t, ctx, "new-owner-1", math.OneInt(), noble) + newOwner2 := w[0] + + _, err = val.ExecTx(ctx, newOwner2.KeyName(), "fiat-tokenfactory", "accept-owner") + require.ErrorContains(t, err, "pending owner is not set") + + showOwnerRes, err = e2e.ShowOwner(ctx, val) + require.NoError(t, err, "failed to query show-owner") + require.Equal(t, expectedOwnerResponse.Owner, showOwnerRes.Owner) + + // ACTION: Accept owner while TF is paused + // EXPECTED: Success; pending owner accepted + // Status: + // Owner: newOwner1 + + _, err = val.ExecTx(ctx, newOwner1.KeyName(), "fiat-tokenfactory", "update-owner", newOwner2.FormattedAddress()) + require.NoError(t, err, "error broadcasting update owner message") + + e2e.PauseFiatTF(t, ctx, val, nw.FiatTfRoles.Pauser) + + _, err = val.ExecTx(ctx, newOwner2.KeyName(), "fiat-tokenfactory", "accept-owner") + require.NoError(t, err, "failed to accept owner") + + showOwnerRes, err = e2e.ShowOwner(ctx, val) + require.NoError(t, err, "failed to query show-owner") + expectedOwnerResponse = fiattokenfactorytypes.QueryGetOwnerResponse{ + Owner: fiattokenfactorytypes.Owner{ + Address: newOwner2.FormattedAddress(), + }, + } + require.Equal(t, expectedOwnerResponse.Owner, showOwnerRes.Owner) + + e2e.UnpauseFiatTF(t, ctx, val, nw.FiatTfRoles.Pauser) + + // ACTION: Accept owner from non pending owner + // EXPECTED: Request fails; pending owner not accepted + // Status: + // Owner: newOwner2 + + w = interchaintest.GetAndFundTestUsers(t, ctx, "default", math.OneInt(), noble, noble) + newOwner3 := w[0] + alice := w[1] + + _, err = val.ExecTx(ctx, newOwner2.KeyName(), "fiat-tokenfactory", "update-owner", newOwner3.FormattedAddress()) + require.NoError(t, err, "error broadcasting update owner message") + + _, err = val.ExecTx(ctx, alice.KeyName(), "fiat-tokenfactory", "accept-owner") + require.ErrorContains(t, err, "you are not the pending owner: unauthorized") + + showOwnerRes, err = e2e.ShowOwner(ctx, val) + require.NoError(t, err, "failed to query show-owner") + require.Equal(t, expectedOwnerResponse.Owner, showOwnerRes.Owner) + + // ACTION: Accept owner from blacklisted pending owner + // EXPECTED: Success; pending owner accepted + // Status: + // Owner: newOwner2 + // Pending: newOwner3 + + e2e.BlacklistAccount(t, ctx, val, nw.FiatTfRoles.Blacklister, newOwner3) + + _, err = val.ExecTx(ctx, newOwner3.KeyName(), "fiat-tokenfactory", "accept-owner") + require.NoError(t, err, "failed to accept owner") + + showOwnerRes, err = e2e.ShowOwner(ctx, val) + require.NoError(t, err, "failed to query show-owner") + expectedOwnerResponse = fiattokenfactorytypes.QueryGetOwnerResponse{ + Owner: fiattokenfactorytypes.Owner{ + Address: newOwner3.FormattedAddress(), + }, + } + require.Equal(t, expectedOwnerResponse.Owner, showOwnerRes.Owner) +} diff --git a/e2e/utils.go b/e2e/utils.go index c9edb9ec..f562aac7 100644 --- a/e2e/utils.go +++ b/e2e/utils.go @@ -476,9 +476,9 @@ func NobleSpinUpIBC(t *testing.T, ctx context.Context, setupAllCircleRoles bool) // Fiat Token Factory Helpers // //////////////////////////////// -// blacklistAccount blacklists an account and then runs the `show-blacklisted` query to ensure the +// BlacklistAccount blacklists an account and then runs the `show-blacklisted` query to ensure the // account was successfully blacklisted on chain -func blacklistAccount(t *testing.T, ctx context.Context, val *cosmos.ChainNode, blacklister ibc.Wallet, toBlacklist ibc.Wallet) { +func BlacklistAccount(t *testing.T, ctx context.Context, val *cosmos.ChainNode, blacklister ibc.Wallet, toBlacklist ibc.Wallet) { _, err := val.ExecTx(ctx, blacklister.KeyName(), "fiat-tokenfactory", "blacklist", toBlacklist.FormattedAddress()) require.NoError(t, err, "failed to broadcast blacklist message") @@ -508,9 +508,9 @@ func unblacklistAccount(t *testing.T, ctx context.Context, val *cosmos.ChainNode require.Error(t, err, "query succeeded, blacklisted account should not exist") } -// pauseFiatTF pauses the fiat tokenfactory. It then runs the `show-paused` query to ensure the +// PauseFiatTF pauses the fiat tokenfactory. It then runs the `show-paused` query to ensure the // the tokenfactory was successfully paused -func pauseFiatTF(t *testing.T, ctx context.Context, val *cosmos.ChainNode, pauser ibc.Wallet) { +func PauseFiatTF(t *testing.T, ctx context.Context, val *cosmos.ChainNode, pauser ibc.Wallet) { _, err := val.ExecTx(ctx, pauser.KeyName(), "fiat-tokenfactory", "pause") require.NoError(t, err, "error pausing fiat-tokenfactory") @@ -529,9 +529,9 @@ func pauseFiatTF(t *testing.T, ctx context.Context, val *cosmos.ChainNode, pause require.Equal(t, expectedPaused, showPausedResponse) } -// unpauseFiatTF pauses the fiat tokenfactory. It then runs the `show-paused` query to ensure the +// UnpauseFiatTF pauses the fiat tokenfactory. It then runs the `show-paused` query to ensure the // the tokenfactory was successfully unpaused -func unpauseFiatTF(t *testing.T, ctx context.Context, val *cosmos.ChainNode, pauser ibc.Wallet) { +func UnpauseFiatTF(t *testing.T, ctx context.Context, val *cosmos.ChainNode, pauser ibc.Wallet) { _, err := val.ExecTx(ctx, pauser.KeyName(), "fiat-tokenfactory", "unpause") require.NoError(t, err, "error pausing fiat-tokenfactory") @@ -629,8 +629,8 @@ func showMinters(ctx context.Context, val *cosmos.ChainNode, minter ibc.Wallet) return showMinters, nil } -// showOwner queries for the token factory Owner by running: `query fiat-tokenfactory show-owner`. -func showOwner(ctx context.Context, val *cosmos.ChainNode) (fiattokenfactorytypes.QueryGetOwnerResponse, error) { +// ShowOwner queries for the token factory Owner by running: `query fiat-tokenfactory show-owner`. +func ShowOwner(ctx context.Context, val *cosmos.ChainNode) (fiattokenfactorytypes.QueryGetOwnerResponse, error) { res, _, err := val.ExecQuery(ctx, "fiat-tokenfactory", "show-owner") if err != nil { return fiattokenfactorytypes.QueryGetOwnerResponse{}, err