Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/relayer-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
linter-cache: false
docker-cache: false
- ci_step: "integration tests"
command: "make build-contract && make rebuild-dev-env && make restart-dev-env && make test-integration"
command: "make build-contract && make build-dev-env && make restart-dev-env && make test-integration"
go-cache: true
wasm-cache: true
linter-cache: false
Expand Down
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,8 @@ test-contract:
restart-dev-env:
crust znet remove && crust znet start --profiles=1cored,xrpl --timeout-commit 0.5s

.PHONY: rebuild-dev-env
rebuild-dev-env:
.PHONY: build-dev-env
build-dev-env:
crust build/crust images/cored

.PHONY: smoke
Expand Down
479 changes: 427 additions & 52 deletions integration-tests/coreum/contract_client_test.go

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion integration-tests/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,9 @@ func init() {
// parse additional flags
flag.Parse()

zapDevLogger, err := zap.NewDevelopment()
zapDevConfig := zap.NewDevelopmentConfig()
zapDevConfig.Level = zap.NewAtomicLevelAt(zap.InfoLevel)
zapDevLogger, err := zapDevConfig.Build()
if err != nil {
panic(errors.WithStack(err))
}
Expand Down
22 changes: 10 additions & 12 deletions integration-tests/processes/env_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,9 @@ func NewRunnerEnv(ctx context.Context, t *testing.T, cfg RunnerEnvConfig, chains
runners = append(
runners,
createDevRunner(
ctx,
t,
chains,
bridgeXRPLAddress,
relayerXRPLAddresses[i],
contractClient.GetContractAddress(),
relayerCoreumAddresses[i],
Expand All @@ -125,9 +125,9 @@ func NewRunnerEnv(ctx context.Context, t *testing.T, cfg RunnerEnvConfig, chains
runners = append(
runners,
createDevRunner(
ctx,
t,
chains,
bridgeXRPLAddress,
maliciousXRPLAddress,
contractClient.GetContractAddress(),
relayerCoreumAddresses[i],
Expand Down Expand Up @@ -269,12 +269,11 @@ func (r *RunnerEnv) RegisterXRPLOriginatedToken(
require.NoError(t, err)
// await for the trust set
r.AwaitNoPendingOperations(ctx, t)
registeredXRPLToken, err := r.ContractClient.GetXRPLToken(ctx, issuer.String(), xrpl.ConvertCurrencyToString(currency))
registeredXRPLToken, err := r.ContractClient.GetXRPLTokenByIssuerAndCurrency(ctx, issuer.String(), xrpl.ConvertCurrencyToString(currency))
require.NoError(t, err)
require.NotNil(t, registeredXRPLToken)
require.Equal(t, coreum.TokenStateEnabled, registeredXRPLToken.State)

return *registeredXRPLToken
return registeredXRPLToken
}

// RequireNoErrors check whether the runner err received runner errors.
Expand Down Expand Up @@ -347,7 +346,7 @@ func (r *RunnerEnv) SendXRPLMaxTrustSetTx(
issuer rippledata.Account,
currency rippledata.Currency,
) {
value, err := rippledata.NewValue("1000000000000", false)
value, err := rippledata.NewValue("1e80", false)
require.NoError(t, err)
trustSetTx := rippledata.TrustSet{
LimitAmount: rippledata.Amount{
Expand Down Expand Up @@ -439,12 +438,12 @@ func genBridgeXRPLAccountWithRelayers(
}

func createDevRunner(
ctx context.Context,
t *testing.T,
chains integrationtests.Chains,
bridgeXRPLAddress rippledata.Account,
xrplRelayerAcc rippledata.Account,
contractAddress sdk.AccAddress,
coreumRelayerAddress sdk.AccAddress,
relayerCoreumAddress sdk.AccAddress,
) *runner.Runner {
t.Helper()

Expand All @@ -458,7 +457,7 @@ func createDevRunner(

// reimport coreum key
coreumKr := chains.Coreum.ClientContext.Keyring()
keyInfo, err := coreumKr.KeyByAddress(coreumRelayerAddress)
keyInfo, err := coreumKr.KeyByAddress(relayerCoreumAddress)
require.NoError(t, err)
pass := uuid.NewString()
armor, err := coreumKr.ExportPrivKeyArmor(keyInfo.Name, pass)
Expand All @@ -474,9 +473,8 @@ func createDevRunner(
require.NoError(t, kr.ImportPrivKey(relayerXRPLKeyName, armor, pass))

relayerRunnerCfg := runner.DefaultConfig()
relayerRunnerCfg.LoggingConfig.Level = "debug"
relayerRunnerCfg.LoggingConfig.Level = "info"

relayerRunnerCfg.XRPL.BridgeAccount = bridgeXRPLAddress.String()
relayerRunnerCfg.XRPL.MultiSignerKeyName = relayerXRPLKeyName
relayerRunnerCfg.XRPL.RPC.URL = chains.XRPL.Config().RPCAddress
// make the scanner fast
Expand All @@ -493,7 +491,7 @@ func createDevRunner(
// make operation fetcher fast
relayerRunnerCfg.Processes.XRPLTxSubmitter.RepeatDelay = 500 * time.Millisecond

relayerRunner, err := runner.NewRunner(relayerRunnerCfg, kr)
relayerRunner, err := runner.NewRunner(ctx, relayerRunnerCfg, kr)
require.NoError(t, err)
return relayerRunner
}
92 changes: 92 additions & 0 deletions integration-tests/processes/send_from_coreum_to_xrpl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import (
rippledata "github.com/rubblelabs/ripple/data"
"github.com/stretchr/testify/require"

"github.com/CoreumFoundation/coreum/v3/pkg/client"
coreumintegration "github.com/CoreumFoundation/coreum/v3/testutil/integration"
assetfttypes "github.com/CoreumFoundation/coreum/v3/x/asset/ft/types"
integrationtests "github.com/CoreumFoundation/coreumbridge-xrpl/integration-tests"
"github.com/CoreumFoundation/coreumbridge-xrpl/relayer/coreum"
"github.com/CoreumFoundation/coreumbridge-xrpl/relayer/xrpl"
Expand Down Expand Up @@ -203,3 +205,93 @@ func TestSendFromXRPLToCoreumWithTicketsReallocation(t *testing.T) {
balance := runnerEnv.Chains.XRPL.GetAccountBalance(ctx, t, xrplRecipientAddress, xrplIssuerAddress, registeredXRPLCurrency)
require.Equal(t, totalSent.Quo(sdkmath.NewIntWithDecimal(1, XRPLTokenDecimals)).String(), balance.Value.String())
}

func TestRegisterCoreumOriginatedTokenAndSendFromXRPLToCoreum(t *testing.T) {
t.Parallel()

ctx, chains := integrationtests.NewTestingContext(t)

xrplRecipientAddress := chains.XRPL.GenAccount(ctx, t, 0)
t.Logf("XRPL recipient address: %s", xrplRecipientAddress)

coreumSenderAddress := chains.Coreum.GenAccount()
issueFee := chains.Coreum.QueryAssetFTParams(ctx, t).IssueFee
chains.Coreum.FundAccountWithOptions(ctx, t, coreumSenderAddress, coreumintegration.BalancesOptions{
Amount: issueFee.Amount.Add(sdkmath.NewInt(10_000_000)),
})

// issue asset ft and register it
sendingPrecision := int32(2)
tokenDecimals := uint32(4)
maxHoldingAmount, ok := sdk.NewIntFromString("10000000000000000")
require.True(t, ok)
issueMsg := &assetfttypes.MsgIssue{
Issuer: coreumSenderAddress.String(),
Symbol: "denom",
Subunit: "denom",
Precision: tokenDecimals, // token decimals in terms of the contract
InitialAmount: maxHoldingAmount,
}
_, err := client.BroadcastTx(
ctx,
chains.Coreum.ClientContext.WithFromAddress(coreumSenderAddress),
chains.Coreum.TxFactory().WithSimulateAndExecute(true),
issueMsg,
)
require.NoError(t, err)

envCfg := DefaultRunnerEnvConfig()
runnerEnv := NewRunnerEnv(ctx, t, envCfg, chains)

bridgeXRPLAccountInfo, err := chains.XRPL.RPCClient().AccountInfo(ctx, runnerEnv.bridgeXRPLAddress)
require.NoError(t, err)

// recover tickets so we can register tokens
numberOfTicketsToAllocate := uint32(200)
chains.XRPL.FundAccountForTicketAllocation(ctx, t, runnerEnv.bridgeXRPLAddress, numberOfTicketsToAllocate)
_, err = runnerEnv.ContractClient.RecoverTickets(ctx, runnerEnv.ContractOwner, *bridgeXRPLAccountInfo.AccountData.Sequence, &numberOfTicketsToAllocate)
require.NoError(t, err)

// start relayers
runnerEnv.StartAllRunnerProcesses(ctx, t)
runnerEnv.AwaitNoPendingOperations(ctx, t)
availableTickets, err := runnerEnv.ContractClient.GetAvailableTickets(ctx)
require.NoError(t, err)
require.Len(t, availableTickets, int(numberOfTicketsToAllocate))

// register Coreum originated token
require.NoError(t, err)
denom := assetfttypes.BuildDenom(issueMsg.Subunit, coreumSenderAddress)
_, err = runnerEnv.ContractClient.RegisterCoreumToken(ctx, runnerEnv.ContractOwner, denom, tokenDecimals, sendingPrecision, maxHoldingAmount)
require.NoError(t, err)
registeredCoreumOriginatedToken, err := runnerEnv.ContractClient.GetCoreumTokenByDenom(ctx, denom)
require.NoError(t, err)

// send TrustSet to be able to receive coins from the bridge
xrplCurrency, err := rippledata.NewCurrency(registeredCoreumOriginatedToken.XRPLCurrency)
require.NoError(t, err)
runnerEnv.SendXRPLMaxTrustSetTx(ctx, t, xrplRecipientAddress, runnerEnv.bridgeXRPLAddress, xrplCurrency)

// equal to 11.1111 on XRPL, but with the sending prec 2 we expect 11.11 to be received
amountToSend1 := sdkmath.NewInt(111111)
// TODO(dzmitryhil) update assertion once we add the final tx revert/recovery
_, err = runnerEnv.ContractClient.SendToXRPL(ctx, coreumSenderAddress, xrplRecipientAddress.String(), sdk.NewCoin(registeredCoreumOriginatedToken.Denom, amountToSend1))
require.NoError(t, err)

runnerEnv.AwaitNoPendingOperations(ctx, t)

// check the XRPL recipient balance
balance := runnerEnv.Chains.XRPL.GetAccountBalance(ctx, t, xrplRecipientAddress, runnerEnv.bridgeXRPLAddress, xrplCurrency)
require.Equal(t, "11.11", balance.Value.String())

amountToSend2 := maxHoldingAmount.QuoRaw(2)
require.NoError(t, err)
_, err = runnerEnv.ContractClient.SendToXRPL(ctx, coreumSenderAddress, xrplRecipientAddress.String(), sdk.NewCoin(registeredCoreumOriginatedToken.Denom, amountToSend2))
require.NoError(t, err)

runnerEnv.AwaitNoPendingOperations(ctx, t)

// check the XRPL recipient balance
balance = runnerEnv.Chains.XRPL.GetAccountBalance(ctx, t, xrplRecipientAddress, runnerEnv.bridgeXRPLAddress, xrplCurrency)
require.Equal(t, "50000000001111e-2", balance.Value.String())
}
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,12 @@ func TestRegisterXRPLOriginatedTokensAndSendFromXRPLToCoreum(t *testing.T) {
// await for the trust set
runnerEnv.AwaitNoPendingOperations(ctx, t)

registeredXRPLToken, err := runnerEnv.ContractClient.GetXRPLToken(ctx, xrplIssuerAddress.String(), xrpl.ConvertCurrencyToString(registeredXRPLCurrency))
registeredXRPLToken, err := runnerEnv.ContractClient.GetXRPLTokenByIssuerAndCurrency(ctx, xrplIssuerAddress.String(), xrpl.ConvertCurrencyToString(registeredXRPLCurrency))
require.NoError(t, err)
require.NotNil(t, registeredXRPLToken)
require.Equal(t, coreum.TokenStateEnabled, registeredXRPLToken.State)

registeredXRPLHexCurrencyToken, err := runnerEnv.ContractClient.GetXRPLToken(ctx, xrplIssuerAddress.String(), xrpl.ConvertCurrencyToString(registeredXRPLHexCurrency))
registeredXRPLHexCurrencyToken, err := runnerEnv.ContractClient.GetXRPLTokenByIssuerAndCurrency(ctx, xrplIssuerAddress.String(), xrpl.ConvertCurrencyToString(registeredXRPLHexCurrency))
require.NoError(t, err)
require.NotNil(t, registeredXRPLHexCurrencyToken)
require.Equal(t, coreum.TokenStateEnabled, registeredXRPLHexCurrencyToken.State)

lowValue, err := rippledata.NewValue("1.00000111", false)
Expand Down
11 changes: 10 additions & 1 deletion integration-tests/xrpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,16 @@ func (c XRPLChain) SubmitTx(ctx context.Context, t *testing.T, tx rippledata.Tra

// GetAccountBalance returns account balance for the provided issuer and currency.
func (c XRPLChain) GetAccountBalance(ctx context.Context, t *testing.T, account, issuer rippledata.Account, currency rippledata.Currency) rippledata.Amount {
return c.GetAccountBalances(ctx, t, account)[fmt.Sprintf("%s/%s", currency.String(), issuer.String())]
balance, ok := c.GetAccountBalances(ctx, t, account)[fmt.Sprintf("%s/%s", currency.String(), issuer.String())]
if !ok {
// equal to zero
return rippledata.Amount{
Value: &rippledata.Value{},
Currency: currency,
Issuer: issuer,
}
}
return balance
}

// GetAccountBalances returns account balances.
Expand Down
60 changes: 48 additions & 12 deletions relayer/coreum/contract.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,19 +127,24 @@ type ContractOwnership struct {

// XRPLToken is XRPL token representation on coreum.
type XRPLToken struct {
Issuer string `json:"issuer"`
Currency string `json:"currency"`
CoreumDenom string `json:"coreum_denom"`
State TokenState `json:"state"`
Issuer string `json:"issuer"`
Currency string `json:"currency"`
CoreumDenom string `json:"coreum_denom"`
SendingPrecision int32 `json:"sending_precision"`
MaxHoldingAmount sdkmath.Int `json:"max_holding_amount"`
State TokenState `json:"state"`
}

// CoreumToken is coreum token registered on the contract.
//
//nolint:revive //kept for the better naming convention.
type CoreumToken struct {
Denom string `json:"denom"`
Decimals uint32 `json:"decimals"`
XRPLCurrency string `json:"xrpl_currency"`
Denom string `json:"denom"`
Decimals uint32 `json:"decimals"`
XRPLCurrency string `json:"xrpl_currency"`
SendingPrecision int32 `json:"sending_precision"`
MaxHoldingAmount sdkmath.Int `json:"max_holding_amount"`
State TokenState `json:"state"`
}

// XRPLToCoreumTransferEvidence is evidence with values represented sending from XRPL to coreum.
Expand Down Expand Up @@ -717,19 +722,19 @@ func (c *ContractClient) GetContractOwnership(ctx context.Context) (ContractOwne
return response, nil
}

// GetXRPLToken returns an XRPL registered token or nil.
func (c *ContractClient) GetXRPLToken(ctx context.Context, issuer, currency string) (*XRPLToken, error) {
// GetXRPLTokenByIssuerAndCurrency returns a XRPL registered token by issuer and currency or error.
func (c *ContractClient) GetXRPLTokenByIssuerAndCurrency(ctx context.Context, issuer, currency string) (XRPLToken, error) {
tokens, err := c.GetXRPLTokens(ctx)
if err != nil {
return nil, err
return XRPLToken{}, err
}
for _, token := range tokens {
if token.Issuer == issuer && token.Currency == currency {
return &token, nil
return token, nil
}
}

return nil, nil //nolint:nilnil // if token not found we return nil instead of an error
return XRPLToken{}, errors.Errorf("token not found in the registered tokens list, issuer:%s, currency:%s", issuer, currency)
}

// GetXRPLTokens returns a list of all XRPL tokens.
Expand All @@ -751,6 +756,37 @@ func (c *ContractClient) GetXRPLTokens(ctx context.Context) ([]XRPLToken, error)
return tokens, nil
}

// GetCoreumTokenByDenom returns a coreum registered token or nil by the provided denom.
func (c *ContractClient) GetCoreumTokenByDenom(ctx context.Context, denom string) (CoreumToken, error) {
tokens, err := c.GetCoreumTokens(ctx)
if err != nil {
return CoreumToken{}, err
}
for _, token := range tokens {
if token.Denom == denom {
return token, nil
}
}

return CoreumToken{}, errors.Errorf("token not found in the registered tokens list, denom:%s", denom)
}

// GetCoreumTokenByXRPLCurrency returns a coreum registered token or nil by the provided xrpl currency.
func (c *ContractClient) GetCoreumTokenByXRPLCurrency(ctx context.Context, xrplCurrency string) (CoreumToken, error) {
// TODO(dzmitryhil) use new query function from the contract once we create it
tokens, err := c.GetCoreumTokens(ctx)
if err != nil {
return CoreumToken{}, err
}
for _, token := range tokens {
if token.XRPLCurrency == xrplCurrency {
return token, nil
}
}

return CoreumToken{}, errors.Errorf("token not found in the registered tokens list, xrplCurrency:%s", xrplCurrency)
}

// GetCoreumTokens returns a list of all coreum tokens.
func (c *ContractClient) GetCoreumTokens(ctx context.Context) ([]CoreumToken, error) {
tokens := make([]CoreumToken, 0)
Expand Down
2 changes: 1 addition & 1 deletion relayer/logger/zap.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func NewZapLogger(cfg ZapLoggerConfig) (*ZapLogger, error) {

zapLogger, err := zapCfg.Build(zap.AddCaller(), zap.AddCallerSkip(1), zap.AddStacktrace(zapcore.ErrorLevel))
if err != nil {
return nil, errors.Wrapf(err, "failed to build zap logger form the config, config:%+v", zapCfg)
return nil, errors.Wrapf(err, "failed to build zap logger from the config, config:%+v", zapCfg)
}

return &ZapLogger{
Expand Down
11 changes: 10 additions & 1 deletion relayer/processes/amount.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,16 @@ func ConvertXRPLOriginatedTokenCoreumAmountToXRPLAmount(coreumAmount sdkmath.Int
}, nil
}

tenPowerDec := big.NewInt(0).Exp(big.NewInt(10), big.NewInt(int64(XRPLIssuedCurrencyDecimals)), nil)
return convertCoreumAmountToXRPLAmountWithDecimals(coreumAmount, XRPLIssuedCurrencyDecimals, issuerString, currencyString)
}

// ConvertCoreumOriginatedTokenCoreumAmountToXRPLAmount converts the coreum originated token amount to XRPL amount based on decimals.
func ConvertCoreumOriginatedTokenCoreumAmountToXRPLAmount(coreumAmount sdkmath.Int, decimals uint32, issuerString, currencyString string) (rippledata.Amount, error) {
return convertCoreumAmountToXRPLAmountWithDecimals(coreumAmount, decimals, issuerString, currencyString)
}

func convertCoreumAmountToXRPLAmountWithDecimals(coreumAmount sdkmath.Int, decimals uint32, issuerString, currencyString string) (rippledata.Amount, error) {
tenPowerDec := big.NewInt(0).Exp(big.NewInt(10), big.NewInt(int64(decimals)), nil)
floatAmount := big.NewFloat(0).SetRat(big.NewRat(0, 1).SetFrac(coreumAmount.BigInt(), tenPowerDec))
// format with exponent
amountString := fmt.Sprintf("%s/%s/%s", floatAmount.Text('g', XRPLAmountPrec), currencyString, issuerString)
Expand Down
Loading