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

Stop rejecting contract instantiation if account holds funds #738

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 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
169 changes: 154 additions & 15 deletions integration-tests/modules/wasm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2118,12 +2118,12 @@ func TestWASMBankSendContractWithMultipleFundsAttached(t *testing.T) {

// TestWASMContractInstantiationIsRejectedIfThereAreTokensOnItsAccount verifies that smart contract instantiation
// is rejected if account exists.
func TestWASMContractInstantiationIsRejectedIfAccountExists(t *testing.T) {
func TestWASMContractInstantiationIsNotRejectedIfAccountExists(t *testing.T) {
t.Parallel()

ctx, chain := integrationtests.NewCoreumTestingContext(t)

admin := chain.GenAccount()
amount := chain.NewCoin(sdkmath.NewInt(500))

requireT := require.New(t)
chain.Faucet.FundAccounts(ctx, t,
Expand Down Expand Up @@ -2162,15 +2162,15 @@ func TestWASMContractInstantiationIsRejectedIfAccountExists(t *testing.T) {
msg := &banktypes.MsgSend{
FromAddress: admin.String(),
ToAddress: contract.String(),
Amount: sdk.NewCoins(chain.NewCoin(sdkmath.NewInt(500))),
Amount: sdk.NewCoins(amount),
}

_, err = client.BroadcastTx(ctx, clientCtx.WithFromAddress(admin), txf, msg)
requireT.NoError(err)

// Instantiate the smart contract. It should fail because its account holds some funds.
// Instantiate the smart contract.

_, err = chain.Wasm.InstantiateWASMContract(
contractAddr1, err := chain.Wasm.InstantiateWASMContract(
ctx,
txf,
admin,
Expand All @@ -2182,7 +2182,7 @@ func TestWASMContractInstantiationIsRejectedIfAccountExists(t *testing.T) {
Label: "bank_send",
},
)
requireT.ErrorContains(err, "contract account already exists")
requireT.NoError(err)

// Predict the address of another smart contract.

Expand All @@ -2197,16 +2197,14 @@ func TestWASMContractInstantiationIsRejectedIfAccountExists(t *testing.T) {
)
requireT.NoError(err)

// Create vesting account using address of the smart cotntract.
// Create vesting account using address of the smart contract.

createVestingAccMsg := &vestingtypes.MsgCreateVestingAccount{
FromAddress: admin.String(),
ToAddress: contract.String(),
Amount: sdk.NewCoins(
chain.NewCoin(sdkmath.NewInt(10000)),
),
EndTime: time.Now().Unix(),
Delayed: true,
Amount: sdk.NewCoins(amount),
EndTime: time.Now().Unix(),
Delayed: true,
}

_, err = client.BroadcastTx(
Expand All @@ -2221,9 +2219,17 @@ func TestWASMContractInstantiationIsRejectedIfAccountExists(t *testing.T) {

requireT.NoError(client.AwaitNextBlocks(ctx, clientCtx, 1))

// Instantiate the smart contract. It should fail because its account holds some funds.
bankClient := banktypes.NewQueryClient(chain.ClientContext)
qres, err := bankClient.Balance(ctx, &banktypes.QueryBalanceRequest{
Address: contract.String(),
Denom: amount.Denom,
})
requireT.NoError(err)
requireT.Equal(amount.String(), qres.Balance.String())

// Instantiate the smart contract.

_, err = chain.Wasm.InstantiateWASMContract(
contractAddr2, err := chain.Wasm.InstantiateWASMContract(
ctx,
txf,
admin,
Expand All @@ -2235,7 +2241,140 @@ func TestWASMContractInstantiationIsRejectedIfAccountExists(t *testing.T) {
Label: "bank_send",
},
)
requireT.ErrorContains(err, "contract account already exists")
requireT.NoError(err)

qres, err = bankClient.Balance(ctx, &banktypes.QueryBalanceRequest{
Address: contractAddr1,
Denom: amount.Denom,
})
requireT.NoError(err)
requireT.Equal(amount.String(), qres.Balance.String())

qres, err = bankClient.Balance(ctx, &banktypes.QueryBalanceRequest{
Address: contractAddr2,
Denom: amount.Denom,
})
requireT.NoError(err)
requireT.Equal(amount.String(), qres.Balance.String())
}

// TestVestingToWASMContract verifies that smart contract instantiated on top of vesting accunt receives funds correctly.
func TestVestingToWASMContract(t *testing.T) {
t.Parallel()

ctx, chain := integrationtests.NewCoreumTestingContext(t)
admin := chain.GenAccount()
recipient := chain.GenAccount()
amount := chain.NewCoin(sdkmath.NewInt(500))

requireT := require.New(t)
chain.Faucet.FundAccounts(ctx, t,
integration.NewFundedAccount(admin, chain.NewCoin(sdkmath.NewInt(5000000000))),
)

txf := chain.TxFactory().
WithSimulateAndExecute(true)

// Deploy smart contract.

codeID, err := chain.Wasm.DeployWASMContract(
ctx,
txf,
admin,
moduleswasm.BankSendWASM,
)
requireT.NoError(err)

// Predict the address of smart contract.

salt, err := chain.Wasm.GenerateSalt()
requireT.NoError(err)

contract, err := chain.Wasm.PredictWASMContractAddress(
ctx,
admin,
salt,
codeID,
)
requireT.NoError(err)

// Create vesting account using address of the smart contract.

vestingDuration := 30 * time.Second
createVestingAccMsg := &vestingtypes.MsgCreateVestingAccount{
FromAddress: admin.String(),
ToAddress: contract.String(),
Amount: sdk.NewCoins(amount),
EndTime: time.Now().Add(vestingDuration).Unix(),
Delayed: true,
}

_, err = client.BroadcastTx(
ctx,
chain.ClientContext.WithFromAddress(admin),
chain.TxFactory().WithGas(chain.GasLimitByMsgs(createVestingAccMsg)),
createVestingAccMsg,
)
requireT.NoError(err)

// Instantiate the smart contract.

contractAddr, err := chain.Wasm.InstantiateWASMContract(
ctx,
txf,
admin,
salt,
integration.InstantiateConfig{
CodeID: codeID,
AccessType: wasmtypes.AccessTypeUnspecified,
Payload: moduleswasm.EmptyPayload,
Label: "bank_send",
},
)
requireT.NoError(err)

// Check that this is still a vesting account.

authClient := authtypes.NewQueryClient(chain.ClientContext)
accountRes, err := authClient.Account(ctx, &authtypes.QueryAccountRequest{
Address: contractAddr,
})
requireT.NoError(err)
requireT.Equal("/cosmos.vesting.v1beta1.DelayedVestingAccount", accountRes.Account.TypeUrl)

// Await vesting time to unlock the vesting coins

select {
case <-ctx.Done():
return
case <-time.After(vestingDuration):
}

// Verify funds are there.

bankClient := banktypes.NewQueryClient(chain.ClientContext)
qres, err := bankClient.Balance(ctx, &banktypes.QueryBalanceRequest{
Address: contractAddr,
Denom: amount.Denom,
})
requireT.NoError(err)
requireT.Equal(amount.String(), qres.Balance.String())

// Send sth to verify that funds has been vested.

msgSend := &banktypes.MsgSend{
FromAddress: contractAddr,
ToAddress: recipient.String(),
Amount: sdk.NewCoins(chain.NewCoin(sdk.OneInt())),
}

_, err = client.BroadcastTx(
ctx,
chain.ClientContext.WithFromAddress(contract),
chain.TxFactory().WithGas(chain.GasLimitByMsgs(msgSend)),
msgSend,
)
requireT.NoError(err)
}

func randStringWithLength(n int) string {
Expand Down
2 changes: 1 addition & 1 deletion x/wasm/types/prunner.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ type AccountPruner struct{}

// CleanupExistingAccount informs wasm module to reject smart contract instantiation if account exists.
func (ap AccountPruner) CleanupExistingAccount(_ sdk.Context, _ authtypes.AccountI) (bool, error) {
return false, nil
return true, nil
}
Loading