structs.go 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. package vaa
  2. import (
  3. "bytes"
  4. "crypto/ecdsa"
  5. "encoding/binary"
  6. "encoding/hex"
  7. "fmt"
  8. "io"
  9. "strings"
  10. "time"
  11. "github.com/ethereum/go-ethereum/common"
  12. "github.com/ethereum/go-ethereum/crypto"
  13. )
  14. type (
  15. // VAA is a verifiable action approval of the Wormhole protocol
  16. VAA struct {
  17. // Version of the VAA schema
  18. Version uint8
  19. // GuardianSetIndex is the index of the guardian set that signed this VAA
  20. GuardianSetIndex uint32
  21. // SignatureData is the signature of the guardian set
  22. Signatures []*Signature
  23. // Timestamp when the VAA was created
  24. Timestamp time.Time
  25. // Nonce of the VAA
  26. Nonce uint32
  27. // Sequence of the VAA
  28. Sequence uint64
  29. /// ConsistencyLevel of the VAA
  30. ConsistencyLevel uint8
  31. // EmitterChain the VAA was emitted on
  32. EmitterChain ChainID
  33. // EmitterAddress of the contract that emitted the Message
  34. EmitterAddress Address
  35. // Payload of the message
  36. Payload []byte
  37. }
  38. // ChainID of a Wormhole chain
  39. ChainID uint16
  40. // Action of a VAA
  41. Action uint8
  42. // Address is a Wormhole protocol address, it contains the native chain's address. If the address data type of a
  43. // chain is < 32bytes the value is zero-padded on the left.
  44. Address [32]byte
  45. // Signature of a single guardian
  46. Signature struct {
  47. // Index of the validator
  48. Index uint8
  49. // Signature data
  50. Signature SignatureData
  51. }
  52. SignatureData [65]byte
  53. )
  54. func (a Address) MarshalJSON() ([]byte, error) {
  55. return []byte(fmt.Sprintf(`"%s"`, a)), nil
  56. }
  57. func (a Address) String() string {
  58. return hex.EncodeToString(a[:])
  59. }
  60. func (a Address) Bytes() []byte {
  61. return a[:]
  62. }
  63. func (a SignatureData) MarshalJSON() ([]byte, error) {
  64. return []byte(fmt.Sprintf(`"%s"`, a)), nil
  65. }
  66. func (a SignatureData) String() string {
  67. return hex.EncodeToString(a[:])
  68. }
  69. func (c ChainID) String() string {
  70. switch c {
  71. case ChainIDUnset:
  72. return "unset"
  73. case ChainIDSolana:
  74. return "solana"
  75. case ChainIDEthereum:
  76. return "ethereum"
  77. case ChainIDTerra:
  78. return "terra"
  79. case ChainIDBSC:
  80. return "bsc"
  81. case ChainIDPolygon:
  82. return "polygon"
  83. case ChainIDAvalanche:
  84. return "avalanche"
  85. case ChainIDOasis:
  86. return "oasis"
  87. case ChainIDFantom:
  88. return "fantom"
  89. case ChainIDAlgorand:
  90. return "algorand"
  91. case ChainIDEthereumRopsten:
  92. return "ethereum-ropsten"
  93. default:
  94. return fmt.Sprintf("unknown chain ID: %d", c)
  95. }
  96. }
  97. func ChainIDFromString(s string) (ChainID, error) {
  98. s = strings.ToLower(s)
  99. switch s {
  100. case "solana":
  101. return ChainIDSolana, nil
  102. case "ethereum":
  103. return ChainIDEthereum, nil
  104. case "terra":
  105. return ChainIDTerra, nil
  106. case "bsc":
  107. return ChainIDBSC, nil
  108. case "polygon":
  109. return ChainIDPolygon, nil
  110. case "avalanche":
  111. return ChainIDAvalanche, nil
  112. case "oasis":
  113. return ChainIDOasis, nil
  114. case "fantom":
  115. return ChainIDFantom, nil
  116. case "algorand":
  117. return ChainIDAlgorand, nil
  118. case "ethereum-ropsten":
  119. return ChainIDEthereumRopsten, nil
  120. default:
  121. return ChainIDUnset, fmt.Errorf("unknown chain ID: %s", s)
  122. }
  123. }
  124. const (
  125. ChainIDUnset ChainID = 0
  126. // ChainIDSolana is the ChainID of Solana
  127. ChainIDSolana ChainID = 1
  128. // ChainIDEthereum is the ChainID of Ethereum
  129. ChainIDEthereum ChainID = 2
  130. // ChainIDTerra is the ChainID of Terra
  131. ChainIDTerra ChainID = 3
  132. // ChainIDBSC is the ChainID of Binance Smart Chain
  133. ChainIDBSC ChainID = 4
  134. // ChainIDPolygon is the ChainID of Polygon
  135. ChainIDPolygon ChainID = 5
  136. // ChainIDAvalanche is the ChainID of Avalanche
  137. ChainIDAvalanche ChainID = 6
  138. // ChainIDOasis is the ChainID of Oasis
  139. ChainIDOasis ChainID = 7
  140. // ChainIDAlgorand is the ChainID of Algorand
  141. ChainIDAlgorand ChainID = 8
  142. // ChainIDFantom is the ChainID of Fantom
  143. ChainIDFantom ChainID = 10
  144. // ChainIDEthereumRopsten is the ChainID of Ethereum Ropsten
  145. ChainIDEthereumRopsten ChainID = 10001
  146. minVAALength = 1 + 4 + 52 + 4 + 1 + 1
  147. SupportedVAAVersion = 0x01
  148. )
  149. // Unmarshal deserializes the binary representation of a VAA
  150. func Unmarshal(data []byte) (*VAA, error) {
  151. if len(data) < minVAALength {
  152. return nil, fmt.Errorf("VAA is too short")
  153. }
  154. v := &VAA{}
  155. v.Version = data[0]
  156. if v.Version != SupportedVAAVersion {
  157. return nil, fmt.Errorf("unsupported VAA version: %d", v.Version)
  158. }
  159. reader := bytes.NewReader(data[1:])
  160. if err := binary.Read(reader, binary.BigEndian, &v.GuardianSetIndex); err != nil {
  161. return nil, fmt.Errorf("failed to read guardian set index: %w", err)
  162. }
  163. lenSignatures, er := reader.ReadByte()
  164. if er != nil {
  165. return nil, fmt.Errorf("failed to read signature length")
  166. }
  167. v.Signatures = make([]*Signature, lenSignatures)
  168. for i := 0; i < int(lenSignatures); i++ {
  169. index, err := reader.ReadByte()
  170. if err != nil {
  171. return nil, fmt.Errorf("failed to read validator index [%d]", i)
  172. }
  173. signature := [65]byte{}
  174. if n, err := reader.Read(signature[:]); err != nil || n != 65 {
  175. return nil, fmt.Errorf("failed to read signature [%d]: %w", i, err)
  176. }
  177. v.Signatures[i] = &Signature{
  178. Index: index,
  179. Signature: signature,
  180. }
  181. }
  182. unixSeconds := uint32(0)
  183. if err := binary.Read(reader, binary.BigEndian, &unixSeconds); err != nil {
  184. return nil, fmt.Errorf("failed to read timestamp: %w", err)
  185. }
  186. v.Timestamp = time.Unix(int64(unixSeconds), 0)
  187. if err := binary.Read(reader, binary.BigEndian, &v.Nonce); err != nil {
  188. return nil, fmt.Errorf("failed to read nonce: %w", err)
  189. }
  190. if err := binary.Read(reader, binary.BigEndian, &v.EmitterChain); err != nil {
  191. return nil, fmt.Errorf("failed to read emitter chain: %w", err)
  192. }
  193. emitterAddress := Address{}
  194. if n, err := reader.Read(emitterAddress[:]); err != nil || n != 32 {
  195. return nil, fmt.Errorf("failed to read emitter address [%d]: %w", n, err)
  196. }
  197. v.EmitterAddress = emitterAddress
  198. if err := binary.Read(reader, binary.BigEndian, &v.Sequence); err != nil {
  199. return nil, fmt.Errorf("failed to read sequence: %w", err)
  200. }
  201. if err := binary.Read(reader, binary.BigEndian, &v.ConsistencyLevel); err != nil {
  202. return nil, fmt.Errorf("failed to read commitment: %w", err)
  203. }
  204. payload := make([]byte, 1000)
  205. n, err := reader.Read(payload)
  206. if err != nil || n == 0 {
  207. return nil, fmt.Errorf("failed to read payload [%d]: %w", n, err)
  208. }
  209. v.Payload = payload[:n]
  210. return v, nil
  211. }
  212. // signingBody returns the binary representation of the data that is relevant for signing and verifying the VAA
  213. func (v *VAA) signingBody() []byte {
  214. return v.serializeBody()
  215. }
  216. // SigningMsg returns the hash of the signing body. This is used for signature generation and verification
  217. func (v *VAA) SigningMsg() common.Hash {
  218. // In order to save space in the solana signature verification instruction, we hash twice so we only need to pass in
  219. // the first hash (32 bytes) vs the full body data.
  220. hash := crypto.Keccak256Hash(crypto.Keccak256Hash(v.signingBody()).Bytes())
  221. return hash
  222. }
  223. // VerifySignatures verifies the signature of the VAA given the signer addresses.
  224. // Returns true if the signatures were verified successfully.
  225. func (v *VAA) VerifySignatures(addresses []common.Address) bool {
  226. if len(addresses) < len(v.Signatures) {
  227. return false
  228. }
  229. h := v.SigningMsg()
  230. for _, sig := range v.Signatures {
  231. if int(sig.Index) >= len(addresses) {
  232. return false
  233. }
  234. pubKey, err := crypto.Ecrecover(h.Bytes(), sig.Signature[:])
  235. if err != nil {
  236. return false
  237. }
  238. addr := common.BytesToAddress(crypto.Keccak256(pubKey[1:])[12:])
  239. if addr != addresses[sig.Index] {
  240. return false
  241. }
  242. }
  243. return true
  244. }
  245. // Marshal returns the binary representation of the VAA
  246. func (v *VAA) Marshal() ([]byte, error) {
  247. buf := new(bytes.Buffer)
  248. MustWrite(buf, binary.BigEndian, v.Version)
  249. MustWrite(buf, binary.BigEndian, v.GuardianSetIndex)
  250. // Write signatures
  251. MustWrite(buf, binary.BigEndian, uint8(len(v.Signatures)))
  252. for _, sig := range v.Signatures {
  253. MustWrite(buf, binary.BigEndian, sig.Index)
  254. buf.Write(sig.Signature[:])
  255. }
  256. // Write Body
  257. buf.Write(v.serializeBody())
  258. return buf.Bytes(), nil
  259. }
  260. // MessageID returns a human-readable emitter_chain/emitter_address/sequence tuple.
  261. func (v *VAA) MessageID() string {
  262. return fmt.Sprintf("%d/%s/%d", v.EmitterChain, v.EmitterAddress, v.Sequence)
  263. }
  264. // HexDigest returns the hex-encoded digest.
  265. func (v *VAA) HexDigest() string {
  266. return hex.EncodeToString(v.SigningMsg().Bytes())
  267. }
  268. func (v *VAA) serializeBody() []byte {
  269. buf := new(bytes.Buffer)
  270. MustWrite(buf, binary.BigEndian, uint32(v.Timestamp.Unix()))
  271. MustWrite(buf, binary.BigEndian, v.Nonce)
  272. MustWrite(buf, binary.BigEndian, v.EmitterChain)
  273. buf.Write(v.EmitterAddress[:])
  274. MustWrite(buf, binary.BigEndian, v.Sequence)
  275. MustWrite(buf, binary.BigEndian, v.ConsistencyLevel)
  276. buf.Write(v.Payload)
  277. return buf.Bytes()
  278. }
  279. func (v *VAA) AddSignature(key *ecdsa.PrivateKey, index uint8) {
  280. sig, err := crypto.Sign(v.SigningMsg().Bytes(), key)
  281. if err != nil {
  282. panic(err)
  283. }
  284. sigData := [65]byte{}
  285. copy(sigData[:], sig)
  286. v.Signatures = append(v.Signatures, &Signature{
  287. Index: index,
  288. Signature: sigData,
  289. })
  290. }
  291. // MustWrite calls binary.Write and panics on errors
  292. func MustWrite(w io.Writer, order binary.ByteOrder, data interface{}) {
  293. if err := binary.Write(w, order, data); err != nil {
  294. panic(fmt.Errorf("failed to write binary data: %v", data).Error())
  295. }
  296. }
  297. // StringToAddress converts a hex-encoded adress into a vaa.Address
  298. func StringToAddress(value string) (Address, error) {
  299. var address Address
  300. res, err := hex.DecodeString(value)
  301. if err != nil {
  302. return address, err
  303. }
  304. copy(address[:], res)
  305. return address, nil
  306. }