Added missing e2e tests between Terra and Ethereum/Solana (#168)
* Added missing e2e tests between Terra and Ethereum/Solana * Review comments fixed * Uncommented Solana<->ETH code, missing Ethereum utils file added
This commit is contained in:
parent
5256d2025a
commit
d9bb5f6802
|
@ -142,6 +142,7 @@ using `kubectl exec solana-devnet-0 -c setup -- cli airdrop solana-devnet:9900`
|
|||
| `0xe78A0F7E598Cc8b0Bb87894B0F60dD2a88d6a8Ab` | Wrapped asset contract |
|
||||
| `0xCfEB869F69431e42cdB54A4F4f105C19C080A601` | Example ERC20 token |
|
||||
| `0xf5b1d8fab1054b9cf7db274126972f97f9d42a11` | Wrapped asset address for the 6qRhs8oA... SPL token |
|
||||
| `0x62b47a23cd900da982bdbe75aeb891d3ed18cc36` | Wrapped asset address for the terra18v... Terra token |
|
||||
|
||||
**Terra**
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
|
||||
"github.com/certusone/wormhole/bridge/pkg/ethereum"
|
||||
"github.com/certusone/wormhole/bridge/pkg/vaa"
|
||||
)
|
||||
|
||||
|
@ -322,14 +323,5 @@ func generateKeys(n int) (keys []*ecdsa.PrivateKey) {
|
|||
|
||||
func hexToAddress(hex string) vaa.Address {
|
||||
hexAddr := common.HexToAddress(hex)
|
||||
return padAddress(hexAddr)
|
||||
}
|
||||
|
||||
func padAddress(address common.Address) vaa.Address {
|
||||
paddedAddress := common.LeftPadBytes(address[:], 32)
|
||||
|
||||
addr := vaa.Address{}
|
||||
copy(addr[:], paddedAddress)
|
||||
|
||||
return addr
|
||||
return ethereum.PadAddress(hexAddr)
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/crypto"
|
||||
|
||||
"github.com/certusone/wormhole/bridge/pkg/devnet"
|
||||
"github.com/certusone/wormhole/bridge/pkg/ethereum"
|
||||
"github.com/certusone/wormhole/bridge/pkg/vaa"
|
||||
)
|
||||
|
||||
|
@ -39,7 +40,7 @@ func main() {
|
|||
SourceChain: 1,
|
||||
TargetChain: 2,
|
||||
SourceAddress: vaa.Address{2, 1, 4},
|
||||
TargetAddress: padAddress(devnet.GanacheClientDefaultAccountAddress),
|
||||
TargetAddress: ethereum.PadAddress(devnet.GanacheClientDefaultAccountAddress),
|
||||
Asset: &vaa.AssetMeta{
|
||||
Chain: vaa.ChainIDSolana,
|
||||
Address: hexToAddress("0x347ef34687bdc9f189e87a9200658d9c40e9988"),
|
||||
|
@ -58,7 +59,7 @@ func main() {
|
|||
SourceChain: 1,
|
||||
TargetChain: 2,
|
||||
SourceAddress: vaa.Address{2, 1, 4},
|
||||
TargetAddress: padAddress(devnet.GanacheClientDefaultAccountAddress),
|
||||
TargetAddress: ethereum.PadAddress(devnet.GanacheClientDefaultAccountAddress),
|
||||
Asset: &vaa.AssetMeta{
|
||||
Chain: vaa.ChainIDEthereum,
|
||||
Address: hexToAddress("0xd833215cbcc3f914bd1c9ece3ee7bf8b14f841bb"),
|
||||
|
@ -101,7 +102,7 @@ func main() {
|
|||
SourceChain: 1,
|
||||
TargetChain: 2,
|
||||
SourceAddress: vaa.Address{2, 1, 4},
|
||||
TargetAddress: padAddress(devnet.GanacheClientDefaultAccountAddress),
|
||||
TargetAddress: ethereum.PadAddress(devnet.GanacheClientDefaultAccountAddress),
|
||||
Asset: &vaa.AssetMeta{
|
||||
Chain: vaa.ChainIDSolana,
|
||||
Address: hexToAddress("0x347ef34687bdc9f189e87a9200658d9c40e9988"),
|
||||
|
@ -120,7 +121,7 @@ func main() {
|
|||
SourceChain: 1,
|
||||
TargetChain: 2,
|
||||
SourceAddress: vaa.Address{2, 1, 5},
|
||||
TargetAddress: padAddress(devnet.GanacheClientDefaultAccountAddress),
|
||||
TargetAddress: ethereum.PadAddress(devnet.GanacheClientDefaultAccountAddress),
|
||||
Asset: &vaa.AssetMeta{
|
||||
Chain: vaa.ChainIDSolana,
|
||||
Address: hexToAddress("0x347ef34687bdc9f189e87a9200658d9c40e9988"),
|
||||
|
@ -139,7 +140,7 @@ func main() {
|
|||
SourceChain: 1,
|
||||
TargetChain: 2,
|
||||
SourceAddress: vaa.Address{2, 1, 5},
|
||||
TargetAddress: padAddress(devnet.GanacheClientDefaultAccountAddress),
|
||||
TargetAddress: ethereum.PadAddress(devnet.GanacheClientDefaultAccountAddress),
|
||||
Asset: &vaa.AssetMeta{
|
||||
Chain: vaa.ChainIDSolana,
|
||||
Address: hexToAddress("0x347ef34687bdc9f189e87a9200658d9c40e9988"),
|
||||
|
@ -158,7 +159,7 @@ func main() {
|
|||
SourceChain: 1,
|
||||
TargetChain: 2,
|
||||
SourceAddress: vaa.Address{2, 1, 5},
|
||||
TargetAddress: padAddress(devnet.GanacheClientDefaultAccountAddress),
|
||||
TargetAddress: ethereum.PadAddress(devnet.GanacheClientDefaultAccountAddress),
|
||||
Asset: &vaa.AssetMeta{
|
||||
Chain: vaa.ChainIDSolana,
|
||||
Address: hexToAddress("0x347ef34687bdc9f189e87a9200658d9c40e9988"),
|
||||
|
@ -194,7 +195,7 @@ func main() {
|
|||
SourceChain: 1,
|
||||
TargetChain: 2,
|
||||
SourceAddress: vaa.Address{2, 1, 5},
|
||||
TargetAddress: padAddress(devnet.GanacheClientDefaultAccountAddress),
|
||||
TargetAddress: ethereum.PadAddress(devnet.GanacheClientDefaultAccountAddress),
|
||||
Asset: &vaa.AssetMeta{
|
||||
Chain: vaa.ChainIDSolana,
|
||||
Address: hexToAddress("0x347ef34687bdc9f189e87a9200658d9c40e9988"),
|
||||
|
@ -213,7 +214,7 @@ func main() {
|
|||
SourceChain: 1,
|
||||
TargetChain: 2,
|
||||
SourceAddress: vaa.Address{2, 1, 5},
|
||||
TargetAddress: padAddress(devnet.GanacheClientDefaultAccountAddress),
|
||||
TargetAddress: ethereum.PadAddress(devnet.GanacheClientDefaultAccountAddress),
|
||||
Asset: &vaa.AssetMeta{
|
||||
Chain: vaa.ChainIDSolana,
|
||||
Address: hexToAddress("0x347ef34687bdc9f189e87a9200658d9c40e9988"),
|
||||
|
@ -253,14 +254,5 @@ func generateKeys(n int) (keys []*ecdsa.PrivateKey) {
|
|||
|
||||
func hexToAddress(hex string) vaa.Address {
|
||||
hexAddr := common.HexToAddress(hex)
|
||||
return padAddress(hexAddr)
|
||||
}
|
||||
|
||||
func padAddress(address common.Address) vaa.Address {
|
||||
paddedAddress := common.LeftPadBytes(address[:], 32)
|
||||
|
||||
addr := vaa.Address{}
|
||||
copy(addr[:], paddedAddress)
|
||||
|
||||
return addr
|
||||
return ethereum.PadAddress(hexAddr)
|
||||
}
|
||||
|
|
|
@ -2,16 +2,20 @@ package e2e
|
|||
|
||||
import (
|
||||
"context"
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
"github.com/mr-tron/base58"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
"github.com/certusone/wormhole/bridge/pkg/devnet"
|
||||
"github.com/certusone/wormhole/bridge/pkg/ethereum"
|
||||
"github.com/certusone/wormhole/bridge/pkg/vaa"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
)
|
||||
|
||||
func setup(t *testing.T) (*kubernetes.Clientset, *ethclient.Client, *bind.TransactOpts) {
|
||||
func setup(t *testing.T) (*kubernetes.Clientset, *ethclient.Client, *bind.TransactOpts, *TerraClient) {
|
||||
// List of pods we need in a ready state before we can run tests.
|
||||
want := []string{
|
||||
// Our test guardian set.
|
||||
|
@ -48,7 +52,13 @@ func setup(t *testing.T) (*kubernetes.Clientset, *ethclient.Client, *bind.Transa
|
|||
}
|
||||
kt := devnet.GetKeyedTransactor(context.Background())
|
||||
|
||||
return c, ec, kt
|
||||
// Terra client
|
||||
tc, err := NewTerraClient()
|
||||
if err != nil {
|
||||
t.Fatalf("creating devnet terra client failed: %v", err)
|
||||
}
|
||||
|
||||
return c, ec, kt, tc
|
||||
}
|
||||
|
||||
// Careful about parallel tests - accounts on some chains like Ethereum cannot be
|
||||
|
@ -56,7 +66,7 @@ func setup(t *testing.T) (*kubernetes.Clientset, *ethclient.Client, *bind.Transa
|
|||
// Either use different Ethereum account, or do not run Ethereum tests in parallel.
|
||||
|
||||
func TestEndToEnd_SOL_ETH(t *testing.T) {
|
||||
c, ec, kt := setup(t)
|
||||
c, ec, kt, _ := setup(t)
|
||||
|
||||
t.Run("[SOL] Native -> [ETH] Wrapped", func(t *testing.T) {
|
||||
testSolanaLockup(t, context.Background(), ec, c,
|
||||
|
@ -117,12 +127,7 @@ func TestEndToEnd_SOL_ETH(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestEndToEnd_SOL_Terra(t *testing.T) {
|
||||
c, _, _ := setup(t)
|
||||
|
||||
tc, err := NewTerraClient()
|
||||
if err != nil {
|
||||
t.Fatalf("creating devnet terra client failed: %v", err)
|
||||
}
|
||||
c, _, _, tc := setup(t)
|
||||
|
||||
t.Run("[Terra] Native -> [SOL] Wrapped", func(t *testing.T) {
|
||||
testTerraLockup(t, context.Background(), tc, c,
|
||||
|
@ -137,14 +142,29 @@ func TestEndToEnd_SOL_Terra(t *testing.T) {
|
|||
)
|
||||
})
|
||||
|
||||
// TODO(https://github.com/certusone/wormhole/issues/164): [SOL] Wrapped -> [Terra] Native
|
||||
t.Run("[SOL] Wrapped -> [Terra] Native", func(t *testing.T) {
|
||||
testSolanaToTerraLockup(t, context.Background(), c,
|
||||
// Source SPL account
|
||||
devnet.SolanaExampleWrappedCWTokenOwningAccount,
|
||||
// Source SPL token
|
||||
devnet.SolanaExampleWrappedCWToken,
|
||||
// Wrapped
|
||||
false,
|
||||
// Amount of SPL token value to transfer.
|
||||
2*devnet.TerraDefaultPrecision,
|
||||
// Same precision - same amount, no precision gained.
|
||||
0,
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("[SOL] Native -> [Terra] Wrapped", func(t *testing.T) {
|
||||
testSolanaToTerraLockup(t, context.Background(), tc, c,
|
||||
testSolanaToTerraLockup(t, context.Background(), c,
|
||||
// Source SPL account
|
||||
devnet.SolanaExampleTokenOwningAccount,
|
||||
// Source SPL token
|
||||
devnet.SolanaExampleToken,
|
||||
// Native
|
||||
true,
|
||||
// Amount of SPL token value to transfer.
|
||||
50*devnet.SolanaDefaultPrecision,
|
||||
// Same precision - same amount, no precision gained.
|
||||
|
@ -152,7 +172,91 @@ func TestEndToEnd_SOL_Terra(t *testing.T) {
|
|||
)
|
||||
})
|
||||
|
||||
// TODO(https://github.com/certusone/wormhole/issues/164): [Terra] Wrapped -> [SOL] Native
|
||||
t.Run("[Terra] Wrapped -> [SOL] Native", func(t *testing.T) {
|
||||
|
||||
tokenSlice, err := base58.Decode(devnet.SolanaExampleToken)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
wrappedAsset, err := waitTerraAsset(t, context.Background(), devnet.TerraBridgeAddress, vaa.ChainIDSolana, tokenSlice)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
testTerraLockup(t, context.Background(), tc, c,
|
||||
// Source wrapped token
|
||||
wrappedAsset,
|
||||
// Destination SPL token account
|
||||
devnet.SolanaExampleTokenOwningAccount,
|
||||
// Amount of Terra token value to transfer.
|
||||
50*devnet.SolanaDefaultPrecision,
|
||||
// Same precision
|
||||
0,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
// TODO(https://github.com/certusone/wormhole/issues/164): TestEndToEnd_ETH_Terra
|
||||
func TestEndToEnd_ETH_Terra(t *testing.T) {
|
||||
_, ec, kt, tc := setup(t)
|
||||
|
||||
t.Run("[Terra] Native -> [ETH] Wrapped", func(t *testing.T) {
|
||||
testTerraToEthLockup(t, context.Background(), tc, ec,
|
||||
// Source CW20 token
|
||||
devnet.TerraTokenAddress,
|
||||
// Destination ETH token
|
||||
devnet.GanacheExampleERC20WrappedTerra,
|
||||
// Amount
|
||||
2*devnet.TerraDefaultPrecision,
|
||||
// Same precision - same amount, no precision gained.
|
||||
0,
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("[ETH] Wrapped -> [Terra] Native", func(t *testing.T) {
|
||||
testEthereumToTerraLockup(t, context.Background(), ec, kt,
|
||||
// Source Ethereum token
|
||||
devnet.GanacheExampleERC20WrappedTerra,
|
||||
// Wrapped
|
||||
false,
|
||||
// Amount of Ethereum token value to transfer.
|
||||
2*devnet.TerraDefaultPrecision,
|
||||
// Same precision
|
||||
0,
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("[ETH] Native -> [Terra] Wrapped", func(t *testing.T) {
|
||||
testEthereumToTerraLockup(t, context.Background(), ec, kt,
|
||||
// Source Ethereum token
|
||||
devnet.GanacheExampleERC20Token,
|
||||
// Native
|
||||
true,
|
||||
// Amount of Ethereum token value to transfer.
|
||||
0.000000012*devnet.ERC20DefaultPrecision,
|
||||
// We lose 9 digits of precision on this path, as the default ERC20 token has 10**18 precision.
|
||||
9,
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("[Terra] Wrapped -> [ETH] Native", func(t *testing.T) {
|
||||
|
||||
paddedTokenAddress := ethereum.PadAddress(devnet.GanacheExampleERC20Token)
|
||||
wrappedAsset, err := waitTerraAsset(t, context.Background(), devnet.TerraBridgeAddress, vaa.ChainIDEthereum, paddedTokenAddress[:])
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
testTerraToEthLockup(t, context.Background(), tc, ec,
|
||||
// Source wrapped token
|
||||
wrappedAsset,
|
||||
// Destination ETH token
|
||||
devnet.GanacheExampleERC20Token,
|
||||
// Amount of Terra token value to transfer.
|
||||
0.000000012*1e9, // 10**9 because default ETH precision is 18 and we lost 9 digits on wrapping
|
||||
// We gain 9 digits of precision on Eth.
|
||||
9,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package e2e
|
|||
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"math"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
@ -15,6 +16,7 @@ import (
|
|||
"k8s.io/client-go/kubernetes"
|
||||
|
||||
"github.com/certusone/wormhole/bridge/pkg/devnet"
|
||||
"github.com/certusone/wormhole/bridge/pkg/ethereum"
|
||||
"github.com/certusone/wormhole/bridge/pkg/ethereum/abi"
|
||||
"github.com/certusone/wormhole/bridge/pkg/ethereum/erc20"
|
||||
"github.com/certusone/wormhole/bridge/pkg/vaa"
|
||||
|
@ -105,3 +107,84 @@ func testEthereumLockup(t *testing.T, ctx context.Context, ec *ethclient.Client,
|
|||
// Source account decreases by the full amount.
|
||||
waitEthBalance(t, ctx, token, beforeErc20, -int64(amount))
|
||||
}
|
||||
|
||||
func testEthereumToTerraLockup(t *testing.T, ctx context.Context, ec *ethclient.Client, kt *bind.TransactOpts,
|
||||
tokenAddr common.Address, isNative bool, amount int64, precisionLoss int) {
|
||||
|
||||
// Bridge client
|
||||
ethBridge, err := abi.NewAbi(devnet.GanacheBridgeContractAddress, ec)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Source token client
|
||||
token, err := erc20.NewErc20(tokenAddr, ec)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Store balance of source ERC20 token
|
||||
beforeErc20, err := token.BalanceOf(nil, devnet.GanacheClientDefaultAccountAddress)
|
||||
if err != nil {
|
||||
beforeErc20 = new(big.Int)
|
||||
t.Log(err) // account may not yet exist, defaults to 0
|
||||
}
|
||||
t.Logf("ERC20 balance: %v", beforeErc20)
|
||||
|
||||
// Store balance of destination CW20 token
|
||||
paddedTokenAddress := ethereum.PadAddress(tokenAddr)
|
||||
var terraToken string
|
||||
if isNative {
|
||||
terraToken, err = getAssetAddress(ctx, devnet.TerraBridgeAddress, vaa.ChainIDEthereum, paddedTokenAddress[:])
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
} else {
|
||||
terraToken = devnet.TerraTokenAddress
|
||||
}
|
||||
|
||||
// Get balance if deployed
|
||||
beforeCw20, err := getTerraBalance(ctx, terraToken)
|
||||
if err != nil {
|
||||
beforeCw20 = new(big.Int)
|
||||
t.Log(err) // account may not yet exist, defaults to 0
|
||||
}
|
||||
t.Logf("CW20 balance: %v", beforeCw20)
|
||||
|
||||
// Send lockup
|
||||
dstAddress, err := hex.DecodeString(devnet.TerraMainTestAddressHex)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var dstAddressBytes [32]byte
|
||||
copy(dstAddressBytes[:], dstAddress)
|
||||
tx, err := ethBridge.LockAssets(kt,
|
||||
// asset address
|
||||
tokenAddr,
|
||||
// token amount
|
||||
new(big.Int).SetInt64(amount),
|
||||
// recipient address on target chain
|
||||
dstAddressBytes,
|
||||
// target chain
|
||||
vaa.ChainIDTerra,
|
||||
// random nonce
|
||||
rand.Uint32(),
|
||||
// refund dust?
|
||||
false,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
t.Logf("sent lockup tx: %v", tx.Hash().Hex())
|
||||
|
||||
// Destination account increases by the full amount.
|
||||
if isNative {
|
||||
waitTerraUnknownBalance(t, ctx, devnet.TerraBridgeAddress, vaa.ChainIDEthereum, paddedTokenAddress[:], beforeCw20, int64(float64(amount)/math.Pow10(precisionLoss)))
|
||||
} else {
|
||||
waitTerraBalance(t, ctx, devnet.TerraTokenAddress, beforeCw20, int64(float64(amount)/math.Pow10(precisionLoss)))
|
||||
}
|
||||
|
||||
// Source account decreases by the full amount.
|
||||
waitEthBalance(t, ctx, token, beforeErc20, -int64(amount))
|
||||
}
|
||||
|
|
|
@ -119,14 +119,22 @@ func testSolanaLockup(t *testing.T, ctx context.Context, ec *ethclient.Client, c
|
|||
waitSPLBalance(t, ctx, c, sourceAcct, beforeSPL, -int64(amount))
|
||||
}
|
||||
|
||||
func testSolanaToTerraLockup(t *testing.T, ctx context.Context, tc *TerraClient, c *kubernetes.Clientset,
|
||||
sourceAcct string, tokenAddr string, amount int, precisionGain int) {
|
||||
func testSolanaToTerraLockup(t *testing.T, ctx context.Context, c *kubernetes.Clientset,
|
||||
sourceAcct string, tokenAddr string, isNative bool, amount int, precisionGain int) {
|
||||
|
||||
tokenSlice, err := base58.Decode(tokenAddr)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
terraToken, err := getAssetAddress(ctx, devnet.TerraBridgeAddress, vaa.ChainIDSolana, tokenSlice)
|
||||
var terraToken string
|
||||
if isNative {
|
||||
terraToken, err = getAssetAddress(ctx, devnet.TerraBridgeAddress, vaa.ChainIDSolana, tokenSlice)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
} else {
|
||||
terraToken = devnet.TerraTokenAddress
|
||||
}
|
||||
|
||||
// Get balance if deployed
|
||||
beforeCw20, err := getTerraBalance(ctx, terraToken)
|
||||
|
@ -168,5 +176,9 @@ func testSolanaToTerraLockup(t *testing.T, ctx context.Context, tc *TerraClient,
|
|||
waitSPLBalance(t, ctx, c, sourceAcct, beforeSPL, -int64(amount))
|
||||
|
||||
// Destination account increases by the full amount.
|
||||
waitTerraUnknownBalance(t, ctx, devnet.TerraBridgeAddress, vaa.ChainIDSolana, tokenSlice, beforeCw20, int64(float64(amount)*math.Pow10(precisionGain)))
|
||||
if isNative {
|
||||
waitTerraUnknownBalance(t, ctx, devnet.TerraBridgeAddress, vaa.ChainIDSolana, tokenSlice, beforeCw20, int64(float64(amount)*math.Pow10(precisionGain)))
|
||||
} else {
|
||||
waitTerraBalance(t, ctx, devnet.TerraTokenAddress, beforeCw20, int64(float64(amount)*math.Pow10(precisionGain)))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,11 +9,16 @@ import (
|
|||
"math"
|
||||
"math/big"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/certusone/wormhole/bridge/pkg/devnet"
|
||||
"github.com/certusone/wormhole/bridge/pkg/ethereum"
|
||||
"github.com/certusone/wormhole/bridge/pkg/ethereum/erc20"
|
||||
"github.com/certusone/wormhole/bridge/pkg/vaa"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/ethclient"
|
||||
"github.com/tendermint/tendermint/libs/rand"
|
||||
"github.com/terra-project/terra.go/client"
|
||||
"github.com/terra-project/terra.go/key"
|
||||
|
@ -168,7 +173,7 @@ func getAssetAddress(ctx context.Context, contract string, chain uint8, asset []
|
|||
|
||||
func terraQuery(ctx context.Context, contract string, query string) (string, error) {
|
||||
|
||||
requestURL := fmt.Sprintf("%s/wasm/contracts/%s/store?query_msg=%s", devnet.TerraLCDURL, contract, query)
|
||||
requestURL := fmt.Sprintf("%s/wasm/contracts/%s/store?query_msg=%s", devnet.TerraLCDURL, contract, url.QueryEscape(query))
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, requestURL, nil)
|
||||
if err != nil {
|
||||
|
@ -193,21 +198,27 @@ func terraQuery(ctx context.Context, contract string, query string) (string, err
|
|||
|
||||
// waitTerraAsset waits for asset contract to be deployed on terra
|
||||
func waitTerraAsset(t *testing.T, ctx context.Context, contract string, chain uint8, asset []byte) (string, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, 60*time.Second)
|
||||
ctx, cancel := context.WithTimeout(ctx, 90*time.Second)
|
||||
defer cancel()
|
||||
|
||||
assetAddress := ""
|
||||
|
||||
err := wait.PollUntil(1*time.Second, func() (bool, error) {
|
||||
err := wait.PollUntil(3*time.Second, func() (bool, error) {
|
||||
|
||||
address, err := getAssetAddress(ctx, contract, chain, asset)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
return true, nil
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// Check the case if request was successful, but asset address is not yet in the registry
|
||||
if address == "" {
|
||||
return false, nil
|
||||
}
|
||||
t.Logf("Returning asset: %s", address)
|
||||
|
||||
assetAddress = address
|
||||
return false, nil
|
||||
return true, nil
|
||||
}, ctx.Done())
|
||||
|
||||
if err != nil {
|
||||
|
@ -252,10 +263,10 @@ func waitTerraUnknownBalance(t *testing.T, ctx context.Context, contract string,
|
|||
return
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(ctx, 60*time.Second)
|
||||
ctx, cancel := context.WithTimeout(ctx, 90*time.Second)
|
||||
defer cancel()
|
||||
|
||||
err = wait.PollUntil(1*time.Second, func() (bool, error) {
|
||||
err = wait.PollUntil(3*time.Second, func() (bool, error) {
|
||||
|
||||
after, err := getTerraBalance(ctx, token)
|
||||
if err != nil {
|
||||
|
@ -322,3 +333,54 @@ func testTerraLockup(t *testing.T, ctx context.Context, tc *TerraClient,
|
|||
// Source account decreases by the full amount.
|
||||
waitTerraBalance(t, ctx, token, beforeCw20, -int64(amount))
|
||||
}
|
||||
|
||||
func testTerraToEthLockup(t *testing.T, ctx context.Context, tc *TerraClient,
|
||||
ec *ethclient.Client, tokenAddr string, destination common.Address, amount int64, precisionGain int) {
|
||||
|
||||
token, err := erc20.NewErc20(destination, ec)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Store balance of source CW20 token
|
||||
beforeCw20, err := getTerraBalance(ctx, tokenAddr)
|
||||
if err != nil {
|
||||
t.Log(err) // account may not yet exist, defaults to 0
|
||||
beforeCw20 = new(big.Int)
|
||||
}
|
||||
t.Logf("CW20 balance: %v", beforeCw20)
|
||||
|
||||
/// Store balance of wrapped destination token
|
||||
beforeErc20, err := token.BalanceOf(nil, devnet.GanacheClientDefaultAccountAddress)
|
||||
if err != nil {
|
||||
t.Log(err) // account may not yet exist, defaults to 0
|
||||
beforeErc20 = new(big.Int)
|
||||
}
|
||||
t.Logf("ERC20 balance: %v", beforeErc20)
|
||||
|
||||
// Send lockup
|
||||
tx, err := tc.lockAssets(
|
||||
t, ctx,
|
||||
// asset address
|
||||
tokenAddr,
|
||||
// token amount
|
||||
new(big.Int).SetInt64(amount),
|
||||
// recipient address on target chain
|
||||
ethereum.PadAddress(devnet.GanacheClientDefaultAccountAddress),
|
||||
// target chain
|
||||
vaa.ChainIDEthereum,
|
||||
// random nonce
|
||||
rand.Uint32(),
|
||||
)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
t.Logf("sent lockup tx: %s", tx.TxHash)
|
||||
|
||||
// Destination account increases by full amount.
|
||||
waitEthBalance(t, ctx, token, beforeErc20, int64(float64(amount)*math.Pow10(precisionGain)))
|
||||
|
||||
// Source account decreases by the full amount.
|
||||
waitTerraBalance(t, ctx, tokenAddr, beforeCw20, -int64(amount))
|
||||
}
|
||||
|
|
|
@ -26,8 +26,9 @@ var (
|
|||
GanacheBridgeContractAddress = common.HexToAddress("0x5b1869D9A4C187F2EAa108f3062412ecf0526b24")
|
||||
|
||||
// ERC20 example tokens.
|
||||
GanacheExampleERC20Token = common.HexToAddress("0xCfEB869F69431e42cdB54A4F4f105C19C080A601")
|
||||
GanacheExampleERC20WrappedSOL = common.HexToAddress("0xf5b1d8fab1054b9cf7db274126972f97f9d42a11")
|
||||
GanacheExampleERC20Token = common.HexToAddress("0xCfEB869F69431e42cdB54A4F4f105C19C080A601")
|
||||
GanacheExampleERC20WrappedSOL = common.HexToAddress("0xf5b1d8fab1054b9cf7db274126972f97f9d42a11")
|
||||
GanacheExampleERC20WrappedTerra = common.HexToAddress("0x62b47a23cd900da982bdbe75aeb891d3ed18cc36")
|
||||
)
|
||||
|
||||
const (
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
package ethereum
|
||||
|
||||
import (
|
||||
"github.com/certusone/wormhole/bridge/pkg/vaa"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
)
|
||||
|
||||
// PadAddress creates 32-byte VAA.Address from 20-byte Ethereum addresses by adding 12 0-bytes at the left
|
||||
func PadAddress(address common.Address) vaa.Address {
|
||||
paddedAddress := common.LeftPadBytes(address[:], 32)
|
||||
|
||||
addr := vaa.Address{}
|
||||
copy(addr[:], paddedAddress)
|
||||
|
||||
return addr
|
||||
}
|
|
@ -3,11 +3,12 @@ package ethereum
|
|||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"math/big"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"github.com/ethereum/go-ethereum/accounts/abi/bind"
|
||||
eth_common "github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
|
|
|
@ -353,6 +353,7 @@ fn vaa_transfer<S: Storage, A: Api, Q: Querier>(
|
|||
const TARGET_ADDRESS_POS: usize = 38;
|
||||
const TOKEN_CHAIN_POS: usize = 70;
|
||||
const TOKEN_ADDRESS_POS: usize = 71;
|
||||
const DECIMALS_POS: usize = 103;
|
||||
const AMOUNT_POS: usize = 104;
|
||||
const PAYLOAD_LEN: usize = 136;
|
||||
|
||||
|
@ -413,7 +414,7 @@ fn vaa_transfer<S: Storage, A: Api, Q: Querier>(
|
|||
msg: to_binary(&WrappedInit {
|
||||
asset_chain: token_chain,
|
||||
asset_address: asset_address.to_vec().into(),
|
||||
decimals: data.get_u8(103),
|
||||
decimals: data.get_u8(DECIMALS_POS),
|
||||
mint: Some(InitMint {
|
||||
recipient: deps
|
||||
.api
|
||||
|
|
Loading…
Reference in New Issue