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(cosmwasm): easily deployable frameworks; daodao & polytone #1215

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
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
227 changes: 227 additions & 0 deletions chain/cosmos/base.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
package cosmos

import (
"context"
"encoding/json"
"fmt"
"log"
"strconv"

"github.com/strangelove-ventures/interchaintest/v8/examples/cosmwasm/external_contracts/daodaocore"
"github.com/strangelove-ventures/interchaintest/v8/ibc"
"github.com/strangelove-ventures/interchaintest/v8/testreporter"
)

func (c *CosmosChain) SetupDAODAO(ctx context.Context, ibcPath string, keyName string) (any, error) {
daoProposalSingleCodeID, err := c.StoreContract(ctx, keyName, "../../../external_contracts/daodao/dao_proposal_single.wasm")
if err != nil {
return nil, err
}

propCodeID, err := strconv.Atoi(daoProposalSingleCodeID)
if err != nil {
return nil, err
}

votingTokenStakedCodeID, err := c.StoreContract(ctx, keyName, "../../../external_contracts/daodao/dao_voting_token_staked.wasm")
if err != nil {
return nil, err
}

userAddrBz, err := c.GetAddress(ctx, keyName)
if err != nil {
return nil, err
}
userAddr := string(userAddrBz)

coreInitMsg := daodaocore.InstantiateMsg{
ImageUrl: nil,
InitialItems: []daodaocore.InitialItem{},
Name: "V2_DAO",
ProposalModulesInstantiateInfo: []daodaocore.ModuleInstantiateInfo{
{
Admin: &daodaocore.Admin{
Address: nil,
CoreModule: &daodaocore.Admin_CoreModule{},
},
CodeId: propCodeID,
Funds: []daodaocore.Coin{},
Label: "v2_dao",
Msg: "",
},
},
VotingModuleInstantiateInfo: daodaocore.ModuleInstantiateInfo{},
AutomaticallyAddCw721S: true,
AutomaticallyAddCw20S: true,
DaoUri: nil,
Description: "V2_DAO",
Admin: &userAddr,
}

initMsg, err := json.Marshal(coreInitMsg)

if err != nil {
return nil, err
}

daoCore, err := c.UploadAndInstantiateContract(ctx, keyName, "../../../external_contracts/daodao/dao_dao_core.wasm",
string(initMsg), "daodao_core", true,
)
if err != nil {
return nil, err
}

log.Println(daoProposalSingleCodeID, votingTokenStakedCodeID, daoCore)

return nil, nil
}

func (c *CosmosChain) SetupPolytone(
ctx context.Context,
r ibc.Relayer,
eRep *testreporter.RelayerExecReporter,
ibcPath string,
keyName string,
destinationChain *CosmosChain,
destinationKeyName string,
) (*PolytoneInstantiation, error) {
note, listener, err := c.SetupPolytoneSourceChain(ctx, keyName, destinationChain.Config().ChainID)
if err != nil || note == nil || listener == nil {
return nil, err
}

voice, err := destinationChain.SetupPolytoneDestinationChain(ctx, destinationKeyName, c.Config().ChainID)
if err != nil || voice == nil {
return nil, err
}

channelId, err := c.FinishPolytoneSetup(ctx, r, eRep, ibcPath, note.ContractInfo.IbcPortID, voice.ContractInfo.IbcPortID, destinationChain.Config().ChainID)
if err != nil {
return nil, err
}

return &PolytoneInstantiation{
Note: *note,
Listener: *listener,
Voice: *voice,
ChannelID: channelId,
}, nil
}

func (c *CosmosChain) SetupPolytoneDestinationChain(ctx context.Context, keyName string, sourceChainId string) (*ContractInfoResponse, error) {

var blockGasLimit uint64
queriedLimit, err := c.GetBlockGasLimit(ctx)
if err != nil {
return nil, err
}

if queriedLimit == nil {
// Default to 100M gas limit
blockGasLimit = uint64(100_000_000)
} else {
blockGasLimit = *queriedLimit
}

proxyCodeID, err := c.StoreContract(
ctx,
keyName,
"../../../external_contracts/polytone/v1.0.0/polytone_proxy.wasm")

if err != nil {
return nil, err
}

voice, err := c.UploadAndInstantiateContract(ctx, keyName,
"../../../external_contracts/polytone/v1.0.0/polytone_voice.wasm",
fmt.Sprintf("{\"proxy_code_id\":\"%s\", \"block_max_gas\":\"%d\"}", proxyCodeID, blockGasLimit),
fmt.Sprintf("polytone_voice_from_%s", sourceChainId),
true)

if err != nil {
return nil, err
}

return voice, nil

}

func (c *CosmosChain) SetupPolytoneSourceChain(ctx context.Context, keyName string, destinationChainId string) (*ContractInfoResponse, *ContractInfoResponse, error) {
var blockGasLimit uint64
queriedLimit, err := c.GetBlockGasLimit(ctx)
if err != nil {
return nil, nil, err
}

if queriedLimit == nil {
// Default to 100M gas limit
blockGasLimit = uint64(100_000_000)
} else {
blockGasLimit = *queriedLimit
}

// Upload the note contract- it emits the ibc messages
note, err := c.UploadAndInstantiateContract(ctx, keyName,
"../../../external_contracts/polytone/v1.0.0/polytone_note.wasm",
fmt.Sprintf(`{"block_max_gas":"%d"}`, blockGasLimit),
fmt.Sprintf("polytone_note_to_%v", destinationChainId),
true)

if err != nil {
return nil, nil, err
}

// Upload the listener contract- it listens for the ibc messages
listener, err := c.UploadAndInstantiateContract(ctx, keyName,
"../../../external_contracts/polytone/v1.0.0/polytone_listener.wasm",
fmt.Sprintf("{\"note\":\"%s\"}", note.Address),
fmt.Sprintf("polytone_listener_from_%v", destinationChainId),
true)

if err != nil {
return nil, nil, err
}

return note, listener, nil
}

func (c *CosmosChain) FinishPolytoneSetup(ctx context.Context, r ibc.Relayer, eRep *testreporter.RelayerExecReporter, ibcPath string, notePortId string, voicePortId string, destChainId string) (string, error) {

// Create the channel between the two contracts
err := r.CreateChannel(ctx, eRep, ibcPath, ibc.CreateChannelOptions{
SourcePortName: notePortId,
DestPortName: voicePortId,
Order: ibc.Unordered,
Version: "polytone-1",
})
if err != nil {
return "", err
}

err = r.StopRelayer(ctx, eRep)
if err != nil {
return "", err
}

err = r.StartRelayer(ctx, eRep)
if err != nil {
return "", err
}

channelsInfo, err := r.GetChannels(ctx, eRep, c.Config().ChainID)
if err != nil {
return "", err
}

channelId := channelsInfo[len(channelsInfo)-1].ChannelID

return channelId, nil

}

type PolytoneInstantiation struct {
Note ContractInfoResponse
Listener ContractInfoResponse
Voice ContractInfoResponse
ChannelID string
}
16 changes: 15 additions & 1 deletion chain/cosmos/chain_node.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ func (tn *ChainNode) NewClient(addr string) error {

tn.Client = rpcClient

grpcConn, err := grpc.Dial(
grpcConn, err := grpc.NewClient(
tn.hostGRPCPort, grpc.WithTransportCredentials(insecure.NewCredentials()),
)
if err != nil {
Expand Down Expand Up @@ -1046,6 +1046,20 @@ func (tn *ChainNode) QueryBankMetadata(ctx context.Context, denom string) (*Bank
return &meta, nil
}

// QueryConsensusParams returns the consensus parameters of the chain.
func (tn *ChainNode) QueryConsensusParams(ctx context.Context) (*ConsensusParamsResponse, error) {
stdout, _, err := tn.ExecQuery(ctx, "consensus", "params")
if err != nil {
return nil, err
}
var params ConsensusParamsResponse
err = json.Unmarshal(stdout, &params)
if err != nil {
return nil, err
}
return &params, nil
}

func (tn *ChainNode) ExportState(ctx context.Context, height int64) (string, error) {
tn.lock.Lock()
defer tn.lock.Unlock()
Expand Down
43 changes: 42 additions & 1 deletion chain/cosmos/cosmos_chain.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,6 @@ func (c *CosmosChain) WithPreStartNodes(preStartNodes func(*CosmosChain)) {
c.preStartNodes = preStartNodes
}


// GetCodec returns the codec for the chain.
func (c *CosmosChain) GetCodec() *codec.ProtoCodec {
return c.cdc
Expand Down Expand Up @@ -544,6 +543,26 @@ func (c *CosmosChain) InstantiateContract(ctx context.Context, keyName string, c
return c.getFullNode().InstantiateContract(ctx, keyName, codeID, initMessage, needsNoAdminFlag, extraExecTxArgs...)
}

// UploadAndInstantiateContract uploads a contract and then instantiates it immediately. Returns both the code id and the new address.
func (c *CosmosChain) UploadAndInstantiateContract(ctx context.Context, keyName string, fileName string, initMessage string, label string, needsNoAdminFlag bool, extraExecTxArgs ...string) (*ContractInfoResponse, error) {
codeID, err := c.StoreContract(ctx, keyName, fileName)
if err != nil {
return nil, err
}

contractAddress, err := c.getFullNode().InstantiateLabeledContract(ctx, keyName, codeID, initMessage, label, needsNoAdminFlag, extraExecTxArgs...)
if err != nil {
return nil, err
}

contractInfo, err := c.QueryContractInfo(ctx, contractAddress)
if err != nil {
return nil, err
}

return contractInfo, err
}

// ExecuteContract executes a contract transaction with a message using it's address.
func (c *CosmosChain) ExecuteContract(ctx context.Context, keyName string, contractAddress string, message string, extraExecTxArgs ...string) (res *types.TxResponse, err error) {
return c.getFullNode().ExecuteContract(ctx, keyName, contractAddress, message, extraExecTxArgs...)
Expand All @@ -559,6 +578,11 @@ func (c *CosmosChain) QueryContract(ctx context.Context, contractAddress string,
return c.getFullNode().QueryContract(ctx, contractAddress, query, response)
}

// NullableQueryContract performs a smart query, taking in a query struct and returning a error with the response struct possibly populated. If the query returned null the response will be nil.
func (c *CosmosChain) NullableQueryContract(ctx context.Context, contractAddress string, query any, response any) error {
return c.getFullNode().NullableQueryContract(ctx, contractAddress, query, response)
}

// DumpContractState dumps the state of a contract at a block height.
func (c *CosmosChain) DumpContractState(ctx context.Context, contractAddress string, height int64) (*DumpContractStateResponse, error) {
return c.getFullNode().DumpContractState(ctx, contractAddress, height)
Expand Down Expand Up @@ -596,6 +620,23 @@ func (c *CosmosChain) GetGasFeesInNativeDenom(gasPaid int64) int64 {
return int64(math.Ceil(fees))
}

// GetBlockGasLimit returns the gas limit for a block on the chain.
func (c *CosmosChain) GetBlockGasLimit(ctx context.Context) (*uint64, error) {
consensus_params, err := c.ConsensusQueryParams(ctx)
if err == nil {
max_gas_limit := consensus_params.Params.Block.MaxGas
// the chain only has a block gas limit if it's not set to -1
if max_gas_limit > -1 {
var gas_limit = uint64(max_gas_limit)
return &gas_limit, nil
} else {
return nil, nil

}
}
return nil, err
}

func (c *CosmosChain) UpgradeVersion(ctx context.Context, cli *client.Client, containerRepo, version string) {
c.cfg.Images[0].Version = version
for _, n := range c.Validators {
Expand Down
13 changes: 13 additions & 0 deletions chain/cosmos/module_consensus.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package cosmos

import (
"context"

consensustypes "github.com/cosmos/cosmos-sdk/x/consensus/types"
)

// ConsensusQueryParams queries the chain consensus parameters via grpc.
func (c *CosmosChain) ConsensusQueryParams(ctx context.Context) (*consensustypes.QueryParamsResponse, error) {
res, err := consensustypes.NewQueryClient(c.GetNode().GrpcConn).Params(ctx, &consensustypes.QueryParamsRequest{})
return res, err
}
Loading
Loading