eth.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. package e2e
  2. import (
  3. "context"
  4. "encoding/hex"
  5. "math"
  6. "math/big"
  7. "testing"
  8. "time"
  9. "github.com/ethereum/go-ethereum/accounts/abi/bind"
  10. "github.com/ethereum/go-ethereum/common"
  11. "github.com/ethereum/go-ethereum/ethclient"
  12. "github.com/tendermint/tendermint/libs/rand"
  13. "k8s.io/apimachinery/pkg/util/wait"
  14. "k8s.io/client-go/kubernetes"
  15. "github.com/certusone/wormhole/bridge/pkg/devnet"
  16. "github.com/certusone/wormhole/bridge/pkg/ethereum"
  17. "github.com/certusone/wormhole/bridge/pkg/ethereum/abi"
  18. "github.com/certusone/wormhole/bridge/pkg/ethereum/erc20"
  19. "github.com/certusone/wormhole/bridge/pkg/vaa"
  20. )
  21. // waitEthBalance waits for target account before to increase.
  22. func waitEthBalance(t *testing.T, ctx context.Context, token *erc20.Erc20, before *big.Int, target int64) {
  23. ctx, cancel := context.WithTimeout(ctx, 60*time.Second)
  24. defer cancel()
  25. err := wait.PollUntil(1*time.Second, func() (bool, error) {
  26. after, err := token.BalanceOf(nil, devnet.GanacheClientDefaultAccountAddress)
  27. if err != nil {
  28. t.Log(err)
  29. return false, nil
  30. }
  31. d := new(big.Int).Sub(after, before)
  32. t.Logf("ERC20 balance after: %d -> %d, delta %d", before, after, d)
  33. if after.Cmp(before) != 0 {
  34. if d.Cmp(new(big.Int).SetInt64(target)) != 0 {
  35. t.Errorf("expected ERC20 delta of %v, got: %v", target, d)
  36. }
  37. return true, nil
  38. }
  39. return false, nil
  40. }, ctx.Done())
  41. if err != nil {
  42. t.Error(err)
  43. }
  44. }
  45. func testEthereumLockup(t *testing.T, ctx context.Context, ec *ethclient.Client, kt *bind.TransactOpts,
  46. c *kubernetes.Clientset, tokenAddr common.Address, destination string, amount int64, precisionLoss int) {
  47. // Bridge client
  48. ethBridge, err := abi.NewAbi(devnet.GanacheBridgeContractAddress, ec)
  49. if err != nil {
  50. panic(err)
  51. }
  52. // Source token client
  53. token, err := erc20.NewErc20(tokenAddr, ec)
  54. if err != nil {
  55. panic(err)
  56. }
  57. // Store balance of source ERC20 token
  58. beforeErc20, err := token.BalanceOf(nil, devnet.GanacheClientDefaultAccountAddress)
  59. if err != nil {
  60. t.Log(err) // account may not yet exist, defaults to 0
  61. }
  62. t.Logf("ERC20 balance: %v", beforeErc20)
  63. // Store balance of destination SPL token
  64. beforeSPL, err := getSPLBalance(ctx, c, destination)
  65. if err != nil {
  66. t.Fatal(err)
  67. }
  68. t.Logf("SPL balance: %d", beforeSPL)
  69. // Send lockup
  70. tx, err := ethBridge.LockAssets(kt,
  71. // asset address
  72. tokenAddr,
  73. // token amount
  74. new(big.Int).SetInt64(amount),
  75. // recipient address on target chain
  76. devnet.MustBase58ToEthAddress(destination),
  77. // target chain
  78. vaa.ChainIDSolana,
  79. // random nonce
  80. rand.Uint32(),
  81. // refund dust?
  82. false,
  83. )
  84. if err != nil {
  85. t.Fatal(err)
  86. }
  87. t.Logf("sent lockup tx: %v", tx.Hash().Hex())
  88. // Destination account increases by full amount.
  89. waitSPLBalance(t, ctx, c, destination, beforeSPL, int64(float64(amount)/math.Pow10(precisionLoss)))
  90. // Source account decreases by the full amount.
  91. waitEthBalance(t, ctx, token, beforeErc20, -int64(amount))
  92. }
  93. func testEthereumToTerraLockup(t *testing.T, ctx context.Context, ec *ethclient.Client, kt *bind.TransactOpts,
  94. tokenAddr common.Address, isNative bool, amount int64, precisionLoss int) {
  95. // Bridge client
  96. ethBridge, err := abi.NewAbi(devnet.GanacheBridgeContractAddress, ec)
  97. if err != nil {
  98. panic(err)
  99. }
  100. // Source token client
  101. token, err := erc20.NewErc20(tokenAddr, ec)
  102. if err != nil {
  103. panic(err)
  104. }
  105. // Store balance of source ERC20 token
  106. beforeErc20, err := token.BalanceOf(nil, devnet.GanacheClientDefaultAccountAddress)
  107. if err != nil {
  108. beforeErc20 = new(big.Int)
  109. t.Log(err) // account may not yet exist, defaults to 0
  110. }
  111. t.Logf("ERC20 balance: %v", beforeErc20)
  112. // Store balance of destination CW20 token
  113. paddedTokenAddress := ethereum.PadAddress(tokenAddr)
  114. var terraToken string
  115. if isNative {
  116. terraToken, err = getAssetAddress(ctx, devnet.TerraBridgeAddress, vaa.ChainIDEthereum, paddedTokenAddress[:])
  117. if err != nil {
  118. t.Log(err)
  119. }
  120. } else {
  121. terraToken = devnet.TerraTokenAddress
  122. }
  123. // Get balance if deployed
  124. beforeCw20, err := getTerraBalance(ctx, terraToken)
  125. if err != nil {
  126. beforeCw20 = new(big.Int)
  127. t.Log(err) // account may not yet exist, defaults to 0
  128. }
  129. t.Logf("CW20 balance: %v", beforeCw20)
  130. // Send lockup
  131. dstAddress, err := hex.DecodeString(devnet.TerraMainTestAddressHex)
  132. if err != nil {
  133. t.Fatal(err)
  134. }
  135. var dstAddressBytes [32]byte
  136. copy(dstAddressBytes[:], dstAddress)
  137. tx, err := ethBridge.LockAssets(kt,
  138. // asset address
  139. tokenAddr,
  140. // token amount
  141. new(big.Int).SetInt64(amount),
  142. // recipient address on target chain
  143. dstAddressBytes,
  144. // target chain
  145. vaa.ChainIDTerra,
  146. // random nonce
  147. rand.Uint32(),
  148. // refund dust?
  149. false,
  150. )
  151. if err != nil {
  152. t.Fatal(err)
  153. }
  154. t.Logf("sent lockup tx: %v", tx.Hash().Hex())
  155. // Destination account increases by the full amount.
  156. if isNative {
  157. waitTerraUnknownBalance(t, ctx, devnet.TerraBridgeAddress, vaa.ChainIDEthereum, paddedTokenAddress[:], beforeCw20, int64(float64(amount)/math.Pow10(precisionLoss)))
  158. } else {
  159. waitTerraBalance(t, ctx, devnet.TerraTokenAddress, beforeCw20, int64(float64(amount)/math.Pow10(precisionLoss)))
  160. }
  161. // Source account decreases by the full amount.
  162. waitEthBalance(t, ctx, token, beforeErc20, -int64(amount))
  163. }