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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
- Default Max Open Connections per pool changed from 30 to 20 to prevent idle connection buildup in multi-tenant deployments [#932](https://github.com/stellar/stellar-disbursement-platform-backend/pull/932)
- Make docker compose environment variables configurable via `.env` file and add documentation [#953](https://github.com/stellar/stellar-disbursement-platform-backend/pull/953)
- Update Stellar Go SDK dependency from `github.com/stellar/go` to `github.com/stellar/go-stellar-sdk` [#956](https://github.com/stellar/stellar-disbursement-platform-backend/pull/956)
- Remove case insensitivity from asset code comparisons [#967](https://github.com/stellar/stellar-disbursement-platform-backend/pull/967)

### Fixed

Expand Down
9 changes: 4 additions & 5 deletions internal/data/assets.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"database/sql"
"errors"
"fmt"
"slices"
"strings"
"time"

Expand Down Expand Up @@ -44,23 +43,23 @@ func AssetColumnNames(tableReference, resultAlias string, includeDates bool) str
// IsNative returns true if the asset is the native asset (XLM).
func (a Asset) IsNative() bool {
return strings.TrimSpace(a.Issuer) == "" &&
slices.Contains([]string{"XLM", "NATIVE"}, strings.ToUpper(a.Code))
(a.Code == "XLM" || a.Code == "NATIVE")
}

// Equals returns true if the asset is the same as the other asset. Case-insensitive.
// Equals returns true if the asset is the same as the other asset.
func (a Asset) Equals(other Asset) bool {
if a.IsNative() && other.IsNative() {
return true
}
return strings.EqualFold(a.Code, other.Code) && strings.EqualFold(a.Issuer, other.Issuer)
return a.Code == other.Code && strings.EqualFold(a.Issuer, other.Issuer)
}

func (a Asset) EqualsHorizonAsset(horizonAsset base.Asset) bool {
if a.IsNative() && horizonAsset.Type == "native" {
return true
}

return strings.EqualFold(a.Code, horizonAsset.Code) && strings.EqualFold(a.Issuer, horizonAsset.Issuer)
return a.Code == horizonAsset.Code && strings.EqualFold(a.Issuer, horizonAsset.Issuer)
}

func (a Asset) ToBasicAsset() txnbuild.Asset {
Expand Down
41 changes: 27 additions & 14 deletions internal/data/assets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,10 +112,11 @@ func Test_Asset_Equals(t *testing.T) {
}{
{Asset{Code: "XLM"}, Asset{Code: "XLM"}, true},
{Asset{Code: "NATIVE"}, Asset{Code: "XLM"}, true},
{Asset{Code: "XLM"}, Asset{Code: "xlm"}, true},
{Asset{Code: "NATIVE"}, Asset{Code: "native"}, false},
{Asset{Code: "XLM"}, Asset{Code: "xlm"}, false},
{Asset{Code: "XLM"}, Asset{Code: "ABC"}, false},
{Asset{Issuer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", Code: "USDC"}, Asset{Issuer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", Code: "usdc"}, true},
{Asset{Issuer: "gbbD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", Code: "USDC"}, Asset{Issuer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", Code: "usdc"}, true},
{Asset{Issuer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", Code: "USDC"}, Asset{Issuer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", Code: "usdc"}, false},
{Asset{Issuer: "gbbD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", Code: "USDC"}, Asset{Issuer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", Code: "USDC"}, true},
{Asset{Issuer: "Issuer1", Code: "ABC"}, Asset{Issuer: "Issuer2", Code: "ABC"}, false},
{Asset{Issuer: "Issuer1", Code: "ABC"}, Asset{Issuer: "Issuer1", Code: "XYZ"}, false},
}
Expand All @@ -138,16 +139,16 @@ func Test_Asset_EqualsHorizonAsset(t *testing.T) {
expectedResult bool
}{
{
name: "🟢 native assets",
name: "🟢 XLM alias is equal to native type",
localAsset: Asset{Code: "XLM"},
horizonAsset: base.Asset{Type: "native"},
expectedResult: true,
},
{
name: "🟢 native asset 2",
localAsset: Asset{Code: "NATIVE"},
name: "🔴 xlm alias is not equal to native type",
localAsset: Asset{Code: "xlm"},
horizonAsset: base.Asset{Type: "native"},
expectedResult: true,
expectedResult: false,
},
{
name: "🟢 issued assets are equal",
Expand All @@ -156,31 +157,43 @@ func Test_Asset_EqualsHorizonAsset(t *testing.T) {
expectedResult: true,
},
{
name: "🟢 issued assets are equal2",
name: "🟢 issued assets with different case in issuer are equal",
localAsset: Asset{Code: "USDC", Issuer: "gbbD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"},
horizonAsset: base.Asset{Type: "credit_alphanum4", Code: "USDC", Issuer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"},
expectedResult: true,
},
{
name: "🔴 issued assets with different case in code are not equal",
localAsset: Asset{Code: "usdc", Issuer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"},
horizonAsset: base.Asset{Type: "credit_alphanum4", Code: "USdc", Issuer: "gbbD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"},
expectedResult: false,
},
{
name: "🟢 NATIVE asset alias is equal to native type",
localAsset: Asset{Code: "NATIVE"},
horizonAsset: base.Asset{Type: "native"},
expectedResult: true,
},
{
name: "🔴 native asset != issued asset",
localAsset: Asset{Code: "XLM"},
horizonAsset: base.Asset{Type: "credit_alphanum4", Code: "NATIVE", Issuer: "issuer"},
name: "🔴 native asset alias is not equal to native type",
localAsset: Asset{Code: "native"},
horizonAsset: base.Asset{Type: "native"},
expectedResult: false,
},
{
name: "🔴 issued asset != native asset",
name: "🔴 issued asset is not equal to native asset",
localAsset: Asset{Code: "USDC", Issuer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"},
horizonAsset: base.Asset{Type: "native"},
expectedResult: false,
},
{
name: "🔴 issued asset != issued asset",
name: "🔴 issued asset is not equal to issued asset with different code",
localAsset: Asset{Code: "USDC", Issuer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"},
horizonAsset: base.Asset{Type: "credit_alphanum4", Code: "EUROC", Issuer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"},
expectedResult: false,
},
{
name: "🔴 issued asset != issued asset 2",
name: "🔴 issued asset is not equal to issued asset with different issuer",
localAsset: Asset{Code: "USDC", Issuer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"},
horizonAsset: base.Asset{Type: "credit_alphanum4", Code: "USDC", Issuer: "another-issuer"},
expectedResult: false,
Expand Down
3 changes: 1 addition & 2 deletions internal/data/fixtures.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"image"
"image/color"
"math/big"
"strings"
"testing"
"time"

Expand All @@ -28,7 +27,7 @@ const (
func CreateAssetFixture(t *testing.T, ctx context.Context, sqlExec db.SQLExecuter, code, issuer string) *Asset {
issuerAddress := issuer

if issuerAddress == "" && strings.ToUpper(code) != "XLM" {
if issuerAddress == "" && code != "XLM" && code != "NATIVE" {
issuer, err := utils.RandomString(56)
require.NoError(t, err)
issuerAddress = issuer
Expand Down
13 changes: 8 additions & 5 deletions internal/serve/httphandler/assets_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,16 @@ import (
"github.com/stellar/stellar-disbursement-platform-backend/internal/serve/httperror"
"github.com/stellar/stellar-disbursement-platform-backend/internal/serve/validators"
"github.com/stellar/stellar-disbursement-platform-backend/internal/services"
"github.com/stellar/stellar-disbursement-platform-backend/internal/services/assets"
"github.com/stellar/stellar-disbursement-platform-backend/internal/transactionsubmission/engine"
tssUtils "github.com/stellar/stellar-disbursement-platform-backend/internal/transactionsubmission/utils"
"github.com/stellar/stellar-disbursement-platform-backend/internal/utils"
"github.com/stellar/stellar-disbursement-platform-backend/pkg/schema"
)

const stellarNativeAssetCode = "XLM"
func isNativeAssetCode(code string) bool {
return code == assets.XLMAssetCode || code == assets.XLMAssetCodeAlias
}

var errCouldNotRemoveTrustline = errors.New("could not remove trustline")

Expand Down Expand Up @@ -144,12 +147,12 @@ func (c AssetsHandler) CreateAsset(w http.ResponseWriter, r *http.Request) {
return
}

assetCode := strings.TrimSpace(strings.ToUpper(assetRequest.Code))
assetCode := strings.TrimSpace(assetRequest.Code)
assetIssuer := strings.TrimSpace(assetRequest.Issuer)

v := validators.NewValidator()
v.Check(assetCode != "", "code", "code is required")
if assetCode != stellarNativeAssetCode {
if !isNativeAssetCode(assetCode) {
v.Check(strkey.IsValidEd25519PublicKey(assetIssuer), "issuer", "issuer is invalid")
}

Expand Down Expand Up @@ -267,7 +270,7 @@ func (c AssetsHandler) handleUpdateAssetTrustlineForDistributionAccount(

changeTrustOperations := make([]*txnbuild.ChangeTrust, 0)
// remove asset
if assetToRemoveTrustline != nil && strings.ToUpper(assetToRemoveTrustline.Code) != stellarNativeAssetCode {
if assetToRemoveTrustline != nil && !isNativeAssetCode(assetToRemoveTrustline.Code) {
for _, balance := range acc.Balances {
if balance.Asset.Code == assetToRemoveTrustline.Code && balance.Asset.Issuer == assetToRemoveTrustline.Issuer {
assetToRemoveTrustlineBalance, parseBalErr := amount.ParseInt64(balance.Balance)
Expand Down Expand Up @@ -305,7 +308,7 @@ func (c AssetsHandler) handleUpdateAssetTrustlineForDistributionAccount(
}

// add asset
if assetToAddTrustline != nil && strings.ToUpper(assetToAddTrustline.Code) != stellarNativeAssetCode {
if assetToAddTrustline != nil && !isNativeAssetCode(assetToAddTrustline.Code) {
var assetToAddTrustlineFound bool
for _, balance := range acc.Balances {
if balance.Asset.Code == assetToAddTrustline.Code && balance.Asset.Issuer == assetToAddTrustline.Issuer {
Expand Down
2 changes: 1 addition & 1 deletion internal/serve/validators/wallet_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ func (wv *WalletValidator) inferAssetType(asset AssetReference) AssetReference {
// Inference logic for backward compatibility
result := asset

if strings.ToUpper(asset.Code) == assets.XLMAssetCode && asset.Issuer == "" {
if (asset.Code == assets.XLMAssetCode || asset.Code == assets.XLMAssetCodeAlias) && asset.Issuer == "" {
result.Type = string(AssetReferenceTypeNative)
result.Code = ""
return result
Expand Down
6 changes: 2 additions & 4 deletions internal/serve/validators/wallet_validator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -635,8 +635,7 @@ func TestWalletValidator_inferAssetType(t *testing.T) {
Issuer: "",
},
expected: AssetReference{
Type: "native",
Code: "",
Code: "xlm",
Issuer: "",
},
},
Expand Down Expand Up @@ -693,8 +692,7 @@ func TestWalletValidator_inferAssetType(t *testing.T) {
Code: "XLm",
},
expected: AssetReference{
Type: "native",
Code: "",
Code: "XLm",
},
},
}
Expand Down
2 changes: 2 additions & 0 deletions internal/services/assets/assets_pubnet.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ var EURCAssetPubnet = data.Asset{

const XLMAssetCode = "XLM"

const XLMAssetCodeAlias = "NATIVE"

var XLMAsset = data.Asset{
Code: XLMAssetCode,
Issuer: "",
Expand Down
6 changes: 5 additions & 1 deletion internal/services/payment_to_submitter_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/stellar/stellar-disbursement-platform-backend/internal/circle"
"github.com/stellar/stellar-disbursement-platform-backend/internal/data"
"github.com/stellar/stellar-disbursement-platform-backend/internal/sdpcontext"
"github.com/stellar/stellar-disbursement-platform-backend/internal/services/assets"
"github.com/stellar/stellar-disbursement-platform-backend/internal/services/paymentdispatchers"
"github.com/stellar/stellar-disbursement-platform-backend/internal/transactionsubmission/engine/signing"
txSubStore "github.com/stellar/stellar-disbursement-platform-backend/internal/transactionsubmission/store"
Expand Down Expand Up @@ -167,7 +168,10 @@ func validatePaymentReadyForSending(p *data.Payment) error {
return fmt.Errorf("payment asset code is empty for payment %s", p.ID)
}
// 3. payment.asset.Issuer is used as transaction.AssetIssuer
if strings.TrimSpace(p.Asset.Issuer) == "" && strings.TrimSpace(strings.ToUpper(p.Asset.Code)) != "XLM" {
codeTrimmed := strings.TrimSpace(p.Asset.Code)
if strings.TrimSpace(p.Asset.Issuer) == "" &&
codeTrimmed != assets.XLMAssetCode &&
codeTrimmed != assets.XLMAssetCodeAlias {
return fmt.Errorf("payment asset issuer is empty for payment %s", p.ID)
}
// 4. payment.Amount is used as transaction.Amount
Expand Down
4 changes: 2 additions & 2 deletions internal/services/send_receiver_wallets_invite_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"html/template"
"net/url"
"path"
"slices"
"strings"
"time"

Expand All @@ -18,6 +17,7 @@ import (
"github.com/stellar/stellar-disbursement-platform-backend/internal/data"
"github.com/stellar/stellar-disbursement-platform-backend/internal/message"
"github.com/stellar/stellar-disbursement-platform-backend/internal/sdpcontext"
"github.com/stellar/stellar-disbursement-platform-backend/internal/services/assets"
"github.com/stellar/stellar-disbursement-platform-backend/internal/utils"
)

Expand Down Expand Up @@ -329,7 +329,7 @@ type WalletDeepLink struct {

func (wdl WalletDeepLink) isNativeAsset() bool {
return wdl.AssetIssuer == "" &&
slices.Contains([]string{"XLM", "NATIVE"}, strings.ToUpper(wdl.AssetCode))
(wdl.AssetCode == assets.XLMAssetCode || wdl.AssetCode == assets.XLMAssetCodeAlias)
}

func (wdl WalletDeepLink) assetName() string {
Expand Down
16 changes: 8 additions & 8 deletions internal/services/send_receiver_wallets_invite_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1213,10 +1213,10 @@ func Test_WalletDeepLink_isNativeAsset(t *testing.T) {
wantResult: true,
},
{
name: "🟢 xLm without issuer should be native asset (case insensitive)",
assetCode: "XLM",
name: "🔴 xLm without issuer should NOT be native asset (case sensitive)",
assetCode: "xLm",
assetIssuer: "",
wantResult: true,
wantResult: false,
},
{
name: "🔴 XLM with issuer should NOT be native asset",
Expand All @@ -1225,16 +1225,16 @@ func Test_WalletDeepLink_isNativeAsset(t *testing.T) {
wantResult: false,
},
{
name: "🟢 native without issuer should be native asset",
assetCode: "native",
name: "🟢 NATIVE without issuer should be native asset",
assetCode: "NATIVE",
assetIssuer: "",
wantResult: true,
},
{
name: "🟢 NaTiVe without issuer should be native asset (case insensitive)",
name: "🔴 NaTiVe without issuer should NOT be native asset (case sensitive)",
assetCode: "NaTiVe",
assetIssuer: "",
wantResult: true,
wantResult: false,
},
{
name: "🔴 native with issuer should NOT be native asset",
Expand Down Expand Up @@ -1286,7 +1286,7 @@ func Test_WalletDeepLink_assetName(t *testing.T) {
name: "'native' native asset",
assetCode: "native",
assetIssuer: "",
wantResult: "native",
wantResult: "native-",
},
{
name: "'native' with an issuer",
Expand Down
5 changes: 2 additions & 3 deletions internal/transactionsubmission/services/horizon.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"slices"
"sort"
"strconv"
"strings"
"time"

"github.com/avast/retry-go/v4"
Expand Down Expand Up @@ -410,7 +409,7 @@ func getAccountDetails(client horizonclient.ClientInterface, accountID string) (
return &account, nil
}

// getAssetID returns asset identifier formatted as CODE:issuer.
// getAssetID returns asset identifier formatted as code:issuer.
func getAssetID(code, issuer string) string {
return fmt.Sprintf("%s:%s", strings.ToUpper(code), issuer)
return fmt.Sprintf("%s:%s", code, issuer)
}
4 changes: 2 additions & 2 deletions internal/transactionsubmission/transaction_worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"errors"
"fmt"
"slices"
"strings"

"github.com/google/uuid"
"github.com/stellar/go-stellar-sdk/clients/horizonclient"
Expand All @@ -17,6 +16,7 @@ import (
"github.com/stellar/stellar-disbursement-platform-backend/db"
"github.com/stellar/stellar-disbursement-platform-backend/internal/crashtracker"
sdpMonitor "github.com/stellar/stellar-disbursement-platform-backend/internal/monitor"
"github.com/stellar/stellar-disbursement-platform-backend/internal/services/assets"
"github.com/stellar/stellar-disbursement-platform-backend/internal/transactionsubmission/engine"
tssMonitor "github.com/stellar/stellar-disbursement-platform-backend/internal/transactionsubmission/monitor"
"github.com/stellar/stellar-disbursement-platform-backend/internal/transactionsubmission/store"
Expand Down Expand Up @@ -435,7 +435,7 @@ func (tw *TransactionWorker) buildAndSignTransaction(ctx context.Context, txJob
return nil, fmt.Errorf("asset code cannot be empty")
}
var asset txnbuild.Asset = txnbuild.NativeAsset{}
if strings.ToUpper(txJob.Transaction.AssetCode) != "XLM" {
if txJob.Transaction.AssetCode != assets.XLMAssetCode && txJob.Transaction.AssetCode != assets.XLMAssetCodeAlias {
if !strkey.IsValidEd25519PublicKey(txJob.Transaction.AssetIssuer) {
return nil, fmt.Errorf("invalid asset issuer: %v", txJob.Transaction.AssetIssuer)
}
Expand Down
4 changes: 2 additions & 2 deletions internal/transactionsubmission/transaction_worker_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"errors"
"fmt"
"net/http"
"strings"
"testing"

"github.com/google/uuid"
Expand All @@ -29,6 +28,7 @@ import (
"github.com/stellar/stellar-disbursement-platform-backend/internal/crashtracker"
sdpMonitor "github.com/stellar/stellar-disbursement-platform-backend/internal/monitor"
"github.com/stellar/stellar-disbursement-platform-backend/internal/serve/httpclient"
"github.com/stellar/stellar-disbursement-platform-backend/internal/services/assets"
"github.com/stellar/stellar-disbursement-platform-backend/internal/transactionsubmission/engine"
engineMocks "github.com/stellar/stellar-disbursement-platform-backend/internal/transactionsubmission/engine/mocks"
"github.com/stellar/stellar-disbursement-platform-backend/internal/transactionsubmission/engine/preconditions"
Expand Down Expand Up @@ -1575,7 +1575,7 @@ func Test_TransactionWorker_buildAndSignTransaction(t *testing.T) {

// Check that the transaction was built correctly:
var wantAsset txnbuild.Asset = txnbuild.NativeAsset{}
if strings.ToUpper(txJob.Transaction.AssetCode) != "XLM" {
if txJob.Transaction.AssetCode != assets.XLMAssetCode && txJob.Transaction.AssetCode != assets.XLMAssetCodeAlias {
wantAsset = txnbuild.CreditAsset{
Code: txJob.Transaction.AssetCode,
Issuer: txJob.Transaction.AssetIssuer,
Expand Down