wormhole/sdk/vaa/payloads.go

496 lines
18 KiB
Go

package vaa
import (
"bytes"
"encoding/binary"
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/holiman/uint256"
)
// CoreModule is the identifier of the Core module (which is used for governance messages)
var CoreModule = []byte{00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x43, 0x6f, 0x72, 0x65}
// WasmdModule is the identifier of the Wormchain Wasmd module (which is used for governance messages)
var WasmdModule = [32]byte{00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x57, 0x61, 0x73, 0x6D, 0x64, 0x4D, 0x6F, 0x64, 0x75, 0x6C, 0x65}
var WasmdModuleStr = string(WasmdModule[:])
// GatewayModule is the identifier of the Gateway module (which is used for general Gateway-related governance messages)
var GatewayModule = [32]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65,
}
var GatewayModuleStr = string(GatewayModule[:])
// CircleIntegrationModule is the identifier of the Circle Integration module (which is used for governance messages).
// It is the hex representation of "CircleIntegration" left padded with zeroes.
var CircleIntegrationModule = [32]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43,
0x69, 0x72, 0x63, 0x6c, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
}
var CircleIntegrationModuleStr = string(CircleIntegrationModule[:])
// IbcReceiverModule is the identifier of the Wormchain ibc_receiver contract module (which is used for governance messages)
// It is the hex representation of "IbcReceiver" left padded with zeroes.
var IbcReceiverModule = [32]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x62, 0x63, 0x52, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72,
}
var IbcReceiverModuleStr = string(IbcReceiverModule[:])
// IbcTranslatorModule is the identifier of the Wormchain ibc_receiver contract module (which is used for governance messages)
// It is the hex representation of "IbcTranslator" left padded with zeroes.
var IbcTranslatorModule = [32]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x49, 0x62, 0x63, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x6c, 0x61, 0x74, 0x6f, 0x72,
}
var IbcTranslatorModuleStr = string(IbcTranslatorModule[:])
// WormholeRelayerModule is the identifier of the Wormhole Relayer module (which is used for governance messages).
// It is the hex representation of "WormholeRelayer" left padded with zeroes.
var WormholeRelayerModule = [32]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x57, 0x6f, 0x72, 0x6d, 0x68, 0x6f, 0x6c, 0x65, 0x52, 0x65, 0x6c, 0x61, 0x79, 0x65, 0x72,
}
var WormholeRelayerModuleStr = string(WormholeRelayerModule[:])
var GeneralPurposeGovernanceModule = [32]byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x65, 0x6E, 0x65, 0x72, 0x61, 0x6C,
0x50, 0x75, 0x72, 0x70, 0x6F, 0x73, 0x65, 0x47, 0x6F, 0x76, 0x65, 0x72, 0x6E, 0x61, 0x6E,
0x63, 0x65,
}
var GeneralPurposeGovernanceModuleStr = string(GeneralPurposeGovernanceModule[:])
type GovernanceAction uint8
var (
// Wormhole core governance actions
// See e.g. GovernanceStructs.sol for semantic meaning of these
ActionContractUpgrade GovernanceAction = 1
ActionGuardianSetUpdate GovernanceAction = 2
ActionCoreSetMessageFee GovernanceAction = 3
ActionCoreTransferFees GovernanceAction = 4
ActionCoreRecoverChainId GovernanceAction = 5
// Wormchain cosmwasm/middleware governance actions
ActionStoreCode GovernanceAction = 1
ActionInstantiateContract GovernanceAction = 2
ActionMigrateContract GovernanceAction = 3
ActionAddWasmInstantiateAllowlist GovernanceAction = 4
ActionDeleteWasmInstantiateAllowlist GovernanceAction = 5
// Gateway governance actions
ActionScheduleUpgrade GovernanceAction = 1
ActionCancelUpgrade GovernanceAction = 2
ActionSetIbcComposabilityMwContract GovernanceAction = 3
// Accountant governance actions
ActionModifyBalance GovernanceAction = 1
// Wormhole tokenbridge governance actions
ActionRegisterChain GovernanceAction = 1
ActionUpgradeTokenBridge GovernanceAction = 2
ActionTokenBridgeRecoverChainId GovernanceAction = 3
// Circle Integration governance actions
CircleIntegrationActionUpdateWormholeFinality GovernanceAction = 1
CircleIntegrationActionRegisterEmitterAndDomain GovernanceAction = 2
CircleIntegrationActionUpgradeContractImplementation GovernanceAction = 3
// Ibc Receiver governance actions
IbcReceiverActionUpdateChannelChain GovernanceAction = 1
// Ibc Translator governance actions
IbcTranslatorActionUpdateChannelChain GovernanceAction = 1
// Wormhole relayer governance actions
WormholeRelayerSetDefaultDeliveryProvider GovernanceAction = 3
)
type (
// BodyContractUpgrade is a governance message to perform a contract upgrade of the core module
BodyContractUpgrade struct {
ChainID ChainID
NewContract Address
}
// BodyGuardianSetUpdate is a governance message to set a new guardian set
BodyGuardianSetUpdate struct {
Keys []common.Address
NewIndex uint32
}
// BodyTokenBridgeRegisterChain is a governance message to register a chain on the token bridge
BodyTokenBridgeRegisterChain struct {
Module string
ChainID ChainID
EmitterAddress Address
}
// BodyTokenBridgeUpgradeContract is a governance message to upgrade the token bridge.
BodyTokenBridgeUpgradeContract struct {
Module string
TargetChainID ChainID
NewContract Address
}
// BodyRecoverChainId is a governance message to recover a chain id.
BodyRecoverChainId struct {
Module string
EvmChainID *uint256.Int
NewChainID ChainID
}
// BodyTokenBridgeModifyBalance is a governance message to modify accountant balances for the tokenbridge.
BodyAccountantModifyBalance struct {
Module string
TargetChainID ChainID
Sequence uint64
ChainId ChainID
TokenChain ChainID
TokenAddress Address
Kind uint8
Amount *uint256.Int
Reason string
}
// BodyWormchainStoreCode is a governance message to upload a new cosmwasm contract to wormchain
BodyWormchainStoreCode struct {
WasmHash [32]byte
}
// BodyWormchainInstantiateContract is a governance message to instantiate a cosmwasm contract on wormchain
BodyWormchainInstantiateContract struct {
InstantiationParamsHash [32]byte
}
// BodyWormchainInstantiateContract is a governance message to migrate a cosmwasm contract on wormchain
BodyWormchainMigrateContract struct {
MigrationParamsHash [32]byte
}
// BodyWormchainAllowlistInstantiateContract is a governance message to allowlist a specific contract address to instantiate a specific wasm code id.
BodyWormchainWasmAllowlistInstantiate struct {
ContractAddr [32]byte
CodeId uint64
}
// BodyGatewayScheduleUpgrade is a governance message to schedule an upgrade on Gateway
BodyGatewayScheduleUpgrade struct {
Name string
Height uint64
}
// BodyGatewayIbcComposabilityMwContract is a governance message to set a specific contract (i.e. IBC Translator) for the ibc composability middleware to use
BodyGatewayIbcComposabilityMwContract struct {
ContractAddr [32]byte
}
// BodyCircleIntegrationUpdateWormholeFinality is a governance message to update the wormhole finality for Circle Integration.
BodyCircleIntegrationUpdateWormholeFinality struct {
TargetChainID ChainID
Finality uint8
}
// BodyCircleIntegrationRegisterEmitterAndDomain is a governance message to register an emitter and domain for Circle Integration.
BodyCircleIntegrationRegisterEmitterAndDomain struct {
TargetChainID ChainID
ForeignEmitterChainId ChainID
ForeignEmitterAddress [32]byte
CircleDomain uint32
}
// BodyCircleIntegrationUpgradeContractImplementation is a governance message to upgrade the contract implementation for Circle Integration.
BodyCircleIntegrationUpgradeContractImplementation struct {
TargetChainID ChainID
NewImplementationAddress [32]byte
}
// BodyIbcUpdateChannelChain is a governance message to update the ibc channel_id -> chain_id mapping in either of the ibc_receiver or ibc_translator contracts
BodyIbcUpdateChannelChain struct {
// The chain that this governance VAA should be redeemed on
TargetChainId ChainID
// This should follow the IBC channel identifier standard: https://github.com/cosmos/ibc/tree/main/spec/core/ics-024-host-requirements#paths-identifiers-separators
// If the identifier string is shorter than 64 bytes, the correct number of 0x00 bytes should be prepended.
ChannelId [64]byte
ChainId ChainID
}
// BodyWormholeRelayerSetDefaultDeliveryProvider is a governance message to set the default relay provider for the Wormhole Relayer.
BodyWormholeRelayerSetDefaultDeliveryProvider struct {
ChainID ChainID
NewDefaultDeliveryProviderAddress Address
}
// BodyGeneralPurposeGovernanceEvm is a general purpose governance message for EVM chains
BodyGeneralPurposeGovernanceEvm struct {
ChainID ChainID
GovernanceContract Address
TargetContract Address
Payload []byte
}
// BodyGeneralPurposeGovernanceSolana is a general purpose governance message for Solana chains
BodyGeneralPurposeGovernanceSolana struct {
ChainID ChainID
GovernanceContract Address
// NOTE: unlike in EVM, no target contract in the schema here, the
// instruction encodes the target contract address (unlike in EVM, where
// an abi encoded calldata doesn't include the target contract address)
Instruction []byte
}
)
func (b BodyContractUpgrade) Serialize() []byte {
buf := new(bytes.Buffer)
// Module
buf.Write(CoreModule)
// Action
MustWrite(buf, binary.BigEndian, ActionContractUpgrade)
// ChainID
MustWrite(buf, binary.BigEndian, uint16(b.ChainID))
buf.Write(b.NewContract[:])
return buf.Bytes()
}
func (b BodyGuardianSetUpdate) Serialize() []byte {
buf := new(bytes.Buffer)
// Module
buf.Write(CoreModule)
// Action
MustWrite(buf, binary.BigEndian, ActionGuardianSetUpdate)
// ChainID - 0 for universal
MustWrite(buf, binary.BigEndian, uint16(0))
MustWrite(buf, binary.BigEndian, b.NewIndex)
MustWrite(buf, binary.BigEndian, uint8(len(b.Keys)))
for _, k := range b.Keys {
buf.Write(k[:])
}
return buf.Bytes()
}
func (r BodyTokenBridgeRegisterChain) Serialize() []byte {
payload := &bytes.Buffer{}
MustWrite(payload, binary.BigEndian, r.ChainID)
payload.Write(r.EmitterAddress[:])
// target chain 0 = universal
return serializeBridgeGovernanceVaa(r.Module, ActionRegisterChain, 0, payload.Bytes())
}
func (r BodyTokenBridgeUpgradeContract) Serialize() []byte {
return serializeBridgeGovernanceVaa(r.Module, ActionUpgradeTokenBridge, r.TargetChainID, r.NewContract[:])
}
func (r BodyRecoverChainId) Serialize() []byte {
// Module
buf := LeftPadBytes(r.Module, 32)
// Action
var action GovernanceAction
if r.Module == "Core" {
action = ActionCoreRecoverChainId
} else {
action = ActionTokenBridgeRecoverChainId
}
MustWrite(buf, binary.BigEndian, action)
// EvmChainID
MustWrite(buf, binary.BigEndian, r.EvmChainID.Bytes32())
// NewChainID
MustWrite(buf, binary.BigEndian, r.NewChainID)
return buf.Bytes()
}
func (r BodyAccountantModifyBalance) Serialize() []byte {
payload := &bytes.Buffer{}
MustWrite(payload, binary.BigEndian, r.Sequence)
MustWrite(payload, binary.BigEndian, r.ChainId)
MustWrite(payload, binary.BigEndian, r.TokenChain)
payload.Write(r.TokenAddress[:])
payload.WriteByte(r.Kind)
amount_bytes := r.Amount.Bytes32()
payload.Write(amount_bytes[:])
reason := make([]byte, 32)
// truncate or pad "reason"
count := copy(reason, r.Reason)
for i := range reason[count:] {
reason[i] = ' '
}
payload.Write(reason)
return serializeBridgeGovernanceVaa(r.Module, ActionModifyBalance, r.TargetChainID, payload.Bytes())
}
func (r BodyWormchainStoreCode) Serialize() []byte {
return serializeBridgeGovernanceVaa(WasmdModuleStr, ActionStoreCode, ChainIDWormchain, r.WasmHash[:])
}
func (r BodyWormchainInstantiateContract) Serialize() []byte {
return serializeBridgeGovernanceVaa(WasmdModuleStr, ActionInstantiateContract, ChainIDWormchain, r.InstantiationParamsHash[:])
}
func (r BodyWormchainMigrateContract) Serialize() []byte {
return serializeBridgeGovernanceVaa(WasmdModuleStr, ActionMigrateContract, ChainIDWormchain, r.MigrationParamsHash[:])
}
func (r BodyWormchainWasmAllowlistInstantiate) Serialize(action GovernanceAction) []byte {
payload := &bytes.Buffer{}
payload.Write(r.ContractAddr[:])
MustWrite(payload, binary.BigEndian, r.CodeId)
return serializeBridgeGovernanceVaa(WasmdModuleStr, action, ChainIDWormchain, payload.Bytes())
}
func (r *BodyWormchainWasmAllowlistInstantiate) Deserialize(bz []byte) {
if len(bz) != 40 {
panic("incorrect payload length")
}
var contractAddr [32]byte
copy(contractAddr[:], bz[0:32])
codeId := binary.BigEndian.Uint64(bz[32:40])
r.ContractAddr = contractAddr
r.CodeId = codeId
}
func (r BodyGatewayIbcComposabilityMwContract) Serialize() []byte {
payload := &bytes.Buffer{}
payload.Write(r.ContractAddr[:])
return serializeBridgeGovernanceVaa(GatewayModuleStr, ActionSetIbcComposabilityMwContract, ChainIDWormchain, payload.Bytes())
}
func (r *BodyGatewayIbcComposabilityMwContract) Deserialize(bz []byte) {
if len(bz) != 32 {
panic("incorrect payload length")
}
var contractAddr [32]byte
copy(contractAddr[:], bz[0:32])
r.ContractAddr = contractAddr
}
func (r BodyGatewayScheduleUpgrade) Serialize() []byte {
payload := &bytes.Buffer{}
payload.Write([]byte(r.Name))
MustWrite(payload, binary.BigEndian, r.Height)
return serializeBridgeGovernanceVaa(GatewayModuleStr, ActionScheduleUpgrade, ChainIDWormchain, payload.Bytes())
}
func (r *BodyGatewayScheduleUpgrade) Deserialize(bz []byte) {
r.Name = string(bz[0 : len(bz)-8])
r.Height = binary.BigEndian.Uint64(bz[len(bz)-8:])
}
func (r BodyCircleIntegrationUpdateWormholeFinality) Serialize() []byte {
return serializeBridgeGovernanceVaa(CircleIntegrationModuleStr, CircleIntegrationActionUpdateWormholeFinality, r.TargetChainID, []byte{r.Finality})
}
func (r BodyCircleIntegrationRegisterEmitterAndDomain) Serialize() []byte {
payload := &bytes.Buffer{}
MustWrite(payload, binary.BigEndian, r.ForeignEmitterChainId)
payload.Write(r.ForeignEmitterAddress[:])
MustWrite(payload, binary.BigEndian, r.CircleDomain)
return serializeBridgeGovernanceVaa(CircleIntegrationModuleStr, CircleIntegrationActionRegisterEmitterAndDomain, r.TargetChainID, payload.Bytes())
}
func (r BodyCircleIntegrationUpgradeContractImplementation) Serialize() []byte {
payload := &bytes.Buffer{}
payload.Write(r.NewImplementationAddress[:])
return serializeBridgeGovernanceVaa(CircleIntegrationModuleStr, CircleIntegrationActionUpgradeContractImplementation, r.TargetChainID, payload.Bytes())
}
func (r BodyIbcUpdateChannelChain) Serialize(module string) []byte {
if module != IbcReceiverModuleStr && module != IbcTranslatorModuleStr {
panic("module for BodyIbcUpdateChannelChain must be either IbcReceiver or IbcTranslator")
}
payload := &bytes.Buffer{}
payload.Write(r.ChannelId[:])
MustWrite(payload, binary.BigEndian, r.ChainId)
return serializeBridgeGovernanceVaa(module, IbcReceiverActionUpdateChannelChain, r.TargetChainId, payload.Bytes())
}
func (r BodyWormholeRelayerSetDefaultDeliveryProvider) Serialize() []byte {
payload := &bytes.Buffer{}
payload.Write(r.NewDefaultDeliveryProviderAddress[:])
return serializeBridgeGovernanceVaa(WormholeRelayerModuleStr, WormholeRelayerSetDefaultDeliveryProvider, r.ChainID, payload.Bytes())
}
func (r BodyGeneralPurposeGovernanceEvm) Serialize() []byte {
payload := &bytes.Buffer{}
payload.Write(r.GovernanceContract[:])
payload.Write(r.TargetContract[:])
// write payload len as uint16
MustWrite(payload, binary.BigEndian, uint16(len(r.Payload)))
payload.Write(r.Payload)
return serializeBridgeGovernanceVaa(GeneralPurposeGovernanceModuleStr, GovernanceAction(1), r.ChainID, payload.Bytes())
}
func (r BodyGeneralPurposeGovernanceSolana) Serialize() []byte {
payload := &bytes.Buffer{}
payload.Write(r.GovernanceContract[:])
// NOTE: unlike in EVM, we don't write the payload here, because we're using
// a custom instruction encoding (there is no standard encoding like evm ABI
// encoding), generated by an external tool. That tool length-prefixes all
// the relevant dynamic fields.
payload.Write(r.Instruction)
return serializeBridgeGovernanceVaa(GeneralPurposeGovernanceModuleStr, GovernanceAction(2), r.ChainID, payload.Bytes())
}
func EmptyPayloadVaa(module string, actionId GovernanceAction, chainId ChainID) []byte {
return serializeBridgeGovernanceVaa(module, actionId, chainId, []byte{})
}
func serializeBridgeGovernanceVaa(module string, actionId GovernanceAction, chainId ChainID, payload []byte) []byte {
buf := LeftPadBytes(module, 32)
// Write action ID
MustWrite(buf, binary.BigEndian, actionId)
// Write target chain
MustWrite(buf, binary.BigEndian, chainId)
// Write emitter address of chain to be registered
buf.Write(payload[:])
return buf.Bytes()
}
func LeftPadIbcChannelId(channelId string) [64]byte {
channelIdBuf := LeftPadBytes(channelId, 64)
var channelIdIdLeftPadded [64]byte
copy(channelIdIdLeftPadded[:], channelIdBuf.Bytes())
return channelIdIdLeftPadded
}
// Prepends 0x00 bytes to the payload buffer, up to a size of `length`
func LeftPadBytes(payload string, length int) *bytes.Buffer {
if length < 0 {
panic("cannot prepend bytes to a negative length buffer")
}
if len(payload) > length {
panic(fmt.Sprintf("payload longer than %d bytes", length))
}
buf := &bytes.Buffer{}
// Prepend correct number of 0x00 bytes to the payload slice
for i := 0; i < (length - len(payload)); i++ {
buf.WriteByte(0x00)
}
// add the payload slice
buf.Write([]byte(payload))
return buf
}