From 2af011f4e16cba37fcb17e691aa270699ba1b0d1 Mon Sep 17 00:00:00 2001 From: Bi Phan <102435501+BiPhan4@users.noreply.github.com> Date: Fri, 10 May 2024 14:06:53 -0400 Subject: [PATCH] feat: cosmwasm migrate contract (#1121) * migrate contract * consume codeID * fix --------- Co-authored-by: Reece Williams <31943163+Reecepbcups@users.noreply.github.com> (cherry picked from commit e7c0c395f8ed2af621a16ae282726a808f6b1564) # Conflicts: # chain/cosmos/chain_node.go --- chain/cosmos/chain_node.go | 138 +++++++++++++++++++++++++++++++++++ chain/cosmos/cosmos_chain.go | 5 ++ 2 files changed, 143 insertions(+) diff --git a/chain/cosmos/chain_node.go b/chain/cosmos/chain_node.go index 658e3bd90..38c27849e 100644 --- a/chain/cosmos/chain_node.go +++ b/chain/cosmos/chain_node.go @@ -988,6 +988,144 @@ func (tn *ChainNode) GetBuildInformation(ctx context.Context) *BinaryBuildInform } } +<<<<<<< HEAD +======= +// InstantiateContract takes a code id for a smart contract and initialization message and returns the instantiated contract address. +func (tn *ChainNode) InstantiateContract(ctx context.Context, keyName string, codeID string, initMessage string, needsNoAdminFlag bool, extraExecTxArgs ...string) (string, error) { + command := []string{"wasm", "instantiate", codeID, initMessage, "--label", "wasm-contract"} + command = append(command, extraExecTxArgs...) + if needsNoAdminFlag { + command = append(command, "--no-admin") + } + txHash, err := tn.ExecTx(ctx, keyName, command...) + if err != nil { + return "", err + } + + txResp, err := tn.GetTransaction(tn.CliContext(), txHash) + if err != nil { + return "", fmt.Errorf("failed to get transaction %s: %w", txHash, err) + } + if txResp.Code != 0 { + return "", fmt.Errorf("error in transaction (code: %d): %s", txResp.Code, txResp.RawLog) + } + + stdout, _, err := tn.ExecQuery(ctx, "wasm", "list-contract-by-code", codeID) + if err != nil { + return "", err + } + + contactsRes := QueryContractResponse{} + if err := json.Unmarshal([]byte(stdout), &contactsRes); err != nil { + return "", err + } + + contractAddress := contactsRes.Contracts[len(contactsRes.Contracts)-1] + return contractAddress, nil +} + +// ExecuteContract executes a contract transaction with a message using it's address. +func (tn *ChainNode) ExecuteContract(ctx context.Context, keyName string, contractAddress string, message string, extraExecTxArgs ...string) (res *types.TxResponse, err error) { + cmd := []string{"wasm", "execute", contractAddress, message} + cmd = append(cmd, extraExecTxArgs...) + + txHash, err := tn.ExecTx(ctx, keyName, cmd...) + if err != nil { + return &types.TxResponse{}, err + } + + txResp, err := tn.GetTransaction(tn.CliContext(), txHash) + if err != nil { + return &types.TxResponse{}, fmt.Errorf("failed to get transaction %s: %w", txHash, err) + } + + if txResp.Code != 0 { + return txResp, fmt.Errorf("error in transaction (code: %d): %s", txResp.Code, txResp.RawLog) + } + + return txResp, nil +} + +// MigrateContract performs contract migration +func (tn *ChainNode) MigrateContract(ctx context.Context, keyName string, contractAddress string, codeID string, message string, extraExecTxArgs ...string) (res *types.TxResponse, err error) { + cmd := []string{"wasm", "migrate", contractAddress, codeID, message} + cmd = append(cmd, extraExecTxArgs...) + + txHash, err := tn.ExecTx(ctx, keyName, cmd...) + if err != nil { + return &types.TxResponse{}, err + } + + txResp, err := tn.GetTransaction(tn.CliContext(), txHash) + if err != nil { + return &types.TxResponse{}, fmt.Errorf("failed to get transaction %s: %w", txHash, err) + } + + if txResp.Code != 0 { + return txResp, fmt.Errorf("error in transaction (code: %d): %s", txResp.Code, txResp.RawLog) + } + + return txResp, nil +} + +// QueryContract performs a smart query, taking in a query struct and returning a error with the response struct populated. +func (tn *ChainNode) QueryContract(ctx context.Context, contractAddress string, queryMsg any, response any) error { + var query []byte + var err error + + if q, ok := queryMsg.(string); ok { + var jsonMap map[string]interface{} + if err := json.Unmarshal([]byte(q), &jsonMap); err != nil { + return err + } + + query, err = json.Marshal(jsonMap) + if err != nil { + return err + } + } else { + query, err = json.Marshal(queryMsg) + if err != nil { + return err + } + } + + stdout, _, err := tn.ExecQuery(ctx, "wasm", "contract-state", "smart", contractAddress, string(query)) + if err != nil { + return err + } + err = json.Unmarshal([]byte(stdout), response) + return err +} + +// StoreClientContract takes a file path to a client smart contract and stores it on-chain. Returns the contracts code id. +func (tn *ChainNode) StoreClientContract(ctx context.Context, keyName string, fileName string, extraExecTxArgs ...string) (string, error) { + content, err := os.ReadFile(fileName) + if err != nil { + return "", err + } + _, file := filepath.Split(fileName) + err = tn.WriteFile(ctx, content, file) + if err != nil { + return "", fmt.Errorf("writing contract file to docker volume: %w", err) + } + + cmd := []string{"ibc-wasm", "store-code", path.Join(tn.HomeDir(), file), "--gas", "auto"} + cmd = append(cmd, extraExecTxArgs...) + + _, err = tn.ExecTx(ctx, keyName, cmd...) + if err != nil { + return "", err + } + + codeHashByte32 := sha256.Sum256(content) + codeHash := hex.EncodeToString(codeHashByte32[:]) + + //return stdout, nil + return codeHash, nil +} + +>>>>>>> e7c0c39 (feat: cosmwasm migrate contract (#1121)) // QueryClientContractCode performs a query with the contract codeHash as the input and code as the output func (tn *ChainNode) QueryClientContractCode(ctx context.Context, codeHash string, response any) error { stdout, _, err := tn.ExecQuery(ctx, "ibc-wasm", "code", codeHash) diff --git a/chain/cosmos/cosmos_chain.go b/chain/cosmos/cosmos_chain.go index 04e7f6136..3ea9ac6d6 100644 --- a/chain/cosmos/cosmos_chain.go +++ b/chain/cosmos/cosmos_chain.go @@ -539,6 +539,11 @@ func (c *CosmosChain) ExecuteContract(ctx context.Context, keyName string, contr return c.getFullNode().ExecuteContract(ctx, keyName, contractAddress, message, extraExecTxArgs...) } +// MigrateContract performs contract migration +func (c *CosmosChain) MigrateContract(ctx context.Context, keyName string, contractAddress string, codeID string, message string, extraExecTxArgs ...string) (res *types.TxResponse, err error) { + return c.getFullNode().MigrateContract(ctx, keyName, contractAddress, codeID, message, extraExecTxArgs...) +} + // QueryContract performs a smart query, taking in a query struct and returning a error with the response struct populated. func (c *CosmosChain) QueryContract(ctx context.Context, contractAddress string, query any, response any) error { return c.getFullNode().QueryContract(ctx, contractAddress, query, response)