Skip to content

Commit 9767f36

Browse files
committed
Remove case insensitivity from asset code
1 parent 04c07ff commit 9767f36

File tree

13 files changed

+64
-48
lines changed

13 files changed

+64
-48
lines changed

internal/data/assets.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"database/sql"
66
"errors"
77
"fmt"
8-
"slices"
98
"strings"
109
"time"
1110

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

5049
// Equals returns true if the asset is the same as the other asset. Case-insensitive.
5150
func (a Asset) Equals(other Asset) bool {
5251
if a.IsNative() && other.IsNative() {
5352
return true
5453
}
55-
return strings.EqualFold(a.Code, other.Code) && strings.EqualFold(a.Issuer, other.Issuer)
54+
return a.Code == other.Code && strings.EqualFold(a.Issuer, other.Issuer)
5655
}
5756

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

63-
return strings.EqualFold(a.Code, horizonAsset.Code) && strings.EqualFold(a.Issuer, horizonAsset.Issuer)
62+
return a.Code == horizonAsset.Code && strings.EqualFold(a.Issuer, horizonAsset.Issuer)
6463
}
6564

6665
func (a Asset) ToBasicAsset() txnbuild.Asset {

internal/data/assets_test.go

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,11 @@ func Test_Asset_Equals(t *testing.T) {
112112
}{
113113
{Asset{Code: "XLM"}, Asset{Code: "XLM"}, true},
114114
{Asset{Code: "NATIVE"}, Asset{Code: "XLM"}, true},
115-
{Asset{Code: "XLM"}, Asset{Code: "xlm"}, true},
115+
{Asset{Code: "NATIVE"}, Asset{Code: "native"}, false},
116+
{Asset{Code: "XLM"}, Asset{Code: "xlm"}, false},
116117
{Asset{Code: "XLM"}, Asset{Code: "ABC"}, false},
117-
{Asset{Issuer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", Code: "USDC"}, Asset{Issuer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", Code: "usdc"}, true},
118-
{Asset{Issuer: "gbbD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", Code: "USDC"}, Asset{Issuer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", Code: "usdc"}, true},
118+
{Asset{Issuer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", Code: "USDC"}, Asset{Issuer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", Code: "usdc"}, false},
119+
{Asset{Issuer: "gbbD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", Code: "USDC"}, Asset{Issuer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5", Code: "USDC"}, true},
119120
{Asset{Issuer: "Issuer1", Code: "ABC"}, Asset{Issuer: "Issuer2", Code: "ABC"}, false},
120121
{Asset{Issuer: "Issuer1", Code: "ABC"}, Asset{Issuer: "Issuer1", Code: "XYZ"}, false},
121122
}
@@ -138,16 +139,16 @@ func Test_Asset_EqualsHorizonAsset(t *testing.T) {
138139
expectedResult bool
139140
}{
140141
{
141-
name: "🟢 native assets",
142+
name: "🟢 XLM alias is equal to native type",
142143
localAsset: Asset{Code: "XLM"},
143144
horizonAsset: base.Asset{Type: "native"},
144145
expectedResult: true,
145146
},
146147
{
147-
name: "🟢 native asset 2",
148-
localAsset: Asset{Code: "NATIVE"},
148+
name: "🔴 xlm alias is not equal to native type",
149+
localAsset: Asset{Code: "xlm"},
149150
horizonAsset: base.Asset{Type: "native"},
150-
expectedResult: true,
151+
expectedResult: false,
151152
},
152153
{
153154
name: "🟢 issued assets are equal",
@@ -156,31 +157,43 @@ func Test_Asset_EqualsHorizonAsset(t *testing.T) {
156157
expectedResult: true,
157158
},
158159
{
159-
name: "🟢 issued assets are equal2",
160+
name: "🟢 issued assets with different case in issuer are equal",
161+
localAsset: Asset{Code: "USDC", Issuer: "gbbD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"},
162+
horizonAsset: base.Asset{Type: "credit_alphanum4", Code: "USDC", Issuer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"},
163+
expectedResult: true,
164+
},
165+
{
166+
name: "🔴 issued assets with different case in code are not equal",
160167
localAsset: Asset{Code: "usdc", Issuer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"},
161168
horizonAsset: base.Asset{Type: "credit_alphanum4", Code: "USdc", Issuer: "gbbD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"},
169+
expectedResult: false,
170+
},
171+
{
172+
name: "🟢 NATIVE asset alias is equal to native type",
173+
localAsset: Asset{Code: "NATIVE"},
174+
horizonAsset: base.Asset{Type: "native"},
162175
expectedResult: true,
163176
},
164177
{
165-
name: "🔴 native asset != issued asset",
166-
localAsset: Asset{Code: "XLM"},
167-
horizonAsset: base.Asset{Type: "credit_alphanum4", Code: "NATIVE", Issuer: "issuer"},
178+
name: "🔴 native asset alias is not equal to native type",
179+
localAsset: Asset{Code: "native"},
180+
horizonAsset: base.Asset{Type: "native"},
168181
expectedResult: false,
169182
},
170183
{
171-
name: "🔴 issued asset != native asset",
184+
name: "🔴 issued asset is not equal to native asset",
172185
localAsset: Asset{Code: "USDC", Issuer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"},
173186
horizonAsset: base.Asset{Type: "native"},
174187
expectedResult: false,
175188
},
176189
{
177-
name: "🔴 issued asset != issued asset",
190+
name: "🔴 issued asset is not equal to issued asset with different code",
178191
localAsset: Asset{Code: "USDC", Issuer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"},
179192
horizonAsset: base.Asset{Type: "credit_alphanum4", Code: "EUROC", Issuer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"},
180193
expectedResult: false,
181194
},
182195
{
183-
name: "🔴 issued asset != issued asset 2",
196+
name: "🔴 issued asset is not equal to issued asset with different issuer",
184197
localAsset: Asset{Code: "USDC", Issuer: "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"},
185198
horizonAsset: base.Asset{Type: "credit_alphanum4", Code: "USDC", Issuer: "another-issuer"},
186199
expectedResult: false,

internal/data/fixtures.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import (
99
"image"
1010
"image/color"
1111
"math/big"
12-
"strings"
1312
"testing"
1413
"time"
1514

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

31-
if issuerAddress == "" && strings.ToUpper(code) != "XLM" {
30+
if issuerAddress == "" && code != "XLM" && code != "NATIVE" {
3231
issuer, err := utils.RandomString(56)
3332
require.NoError(t, err)
3433
issuerAddress = issuer

internal/serve/httphandler/assets_handler.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,16 @@ import (
2323
"github.com/stellar/stellar-disbursement-platform-backend/internal/serve/httperror"
2424
"github.com/stellar/stellar-disbursement-platform-backend/internal/serve/validators"
2525
"github.com/stellar/stellar-disbursement-platform-backend/internal/services"
26+
"github.com/stellar/stellar-disbursement-platform-backend/internal/services/assets"
2627
"github.com/stellar/stellar-disbursement-platform-backend/internal/transactionsubmission/engine"
2728
tssUtils "github.com/stellar/stellar-disbursement-platform-backend/internal/transactionsubmission/utils"
2829
"github.com/stellar/stellar-disbursement-platform-backend/internal/utils"
2930
"github.com/stellar/stellar-disbursement-platform-backend/pkg/schema"
3031
)
3132

32-
const stellarNativeAssetCode = "XLM"
33+
func isNativeAssetCode(code string) bool {
34+
return code == assets.XLMAssetCode || code == assets.XLMAssetCodeAlias
35+
}
3336

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

@@ -144,12 +147,12 @@ func (c AssetsHandler) CreateAsset(w http.ResponseWriter, r *http.Request) {
144147
return
145148
}
146149

147-
assetCode := strings.TrimSpace(strings.ToUpper(assetRequest.Code))
150+
assetCode := strings.TrimSpace(assetRequest.Code)
148151
assetIssuer := strings.TrimSpace(assetRequest.Issuer)
149152

150153
v := validators.NewValidator()
151154
v.Check(assetCode != "", "code", "code is required")
152-
if assetCode != stellarNativeAssetCode {
155+
if !isNativeAssetCode(assetCode) {
153156
v.Check(strkey.IsValidEd25519PublicKey(assetIssuer), "issuer", "issuer is invalid")
154157
}
155158

@@ -267,7 +270,7 @@ func (c AssetsHandler) handleUpdateAssetTrustlineForDistributionAccount(
267270

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

307310
// add asset
308-
if assetToAddTrustline != nil && strings.ToUpper(assetToAddTrustline.Code) != stellarNativeAssetCode {
311+
if assetToAddTrustline != nil && !isNativeAssetCode(assetToAddTrustline.Code) {
309312
var assetToAddTrustlineFound bool
310313
for _, balance := range acc.Balances {
311314
if balance.Asset.Code == assetToAddTrustline.Code && balance.Asset.Issuer == assetToAddTrustline.Issuer {

internal/serve/validators/wallet_validator.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ func (wv *WalletValidator) inferAssetType(asset AssetReference) AssetReference {
288288
// Inference logic for backward compatibility
289289
result := asset
290290

291-
if strings.ToUpper(asset.Code) == assets.XLMAssetCode && asset.Issuer == "" {
291+
if (asset.Code == assets.XLMAssetCode || asset.Code == "NATIVE") && asset.Issuer == "" {
292292
result.Type = string(AssetReferenceTypeNative)
293293
result.Code = ""
294294
return result

internal/serve/validators/wallet_validator_test.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -635,8 +635,7 @@ func TestWalletValidator_inferAssetType(t *testing.T) {
635635
Issuer: "",
636636
},
637637
expected: AssetReference{
638-
Type: "native",
639-
Code: "",
638+
Code: "xlm",
640639
Issuer: "",
641640
},
642641
},
@@ -693,8 +692,7 @@ func TestWalletValidator_inferAssetType(t *testing.T) {
693692
Code: "XLm",
694693
},
695694
expected: AssetReference{
696-
Type: "native",
697-
Code: "",
695+
Code: "XLm",
698696
},
699697
},
700698
}

internal/services/assets/assets_pubnet.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ var EURCAssetPubnet = data.Asset{
3333
// XLM
3434

3535
const XLMAssetCode = "XLM"
36+
const XLMAssetCodeAlias = "NATIVE"
3637

3738
var XLMAsset = data.Asset{
3839
Code: XLMAssetCode,

internal/services/payment_to_submitter_service.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/stellar/stellar-disbursement-platform-backend/internal/circle"
1212
"github.com/stellar/stellar-disbursement-platform-backend/internal/data"
1313
"github.com/stellar/stellar-disbursement-platform-backend/internal/sdpcontext"
14+
"github.com/stellar/stellar-disbursement-platform-backend/internal/services/assets"
1415
"github.com/stellar/stellar-disbursement-platform-backend/internal/services/paymentdispatchers"
1516
"github.com/stellar/stellar-disbursement-platform-backend/internal/transactionsubmission/engine/signing"
1617
txSubStore "github.com/stellar/stellar-disbursement-platform-backend/internal/transactionsubmission/store"
@@ -167,7 +168,10 @@ func validatePaymentReadyForSending(p *data.Payment) error {
167168
return fmt.Errorf("payment asset code is empty for payment %s", p.ID)
168169
}
169170
// 3. payment.asset.Issuer is used as transaction.AssetIssuer
170-
if strings.TrimSpace(p.Asset.Issuer) == "" && strings.TrimSpace(strings.ToUpper(p.Asset.Code)) != "XLM" {
171+
codeTrimmed := strings.TrimSpace(p.Asset.Code)
172+
if strings.TrimSpace(p.Asset.Issuer) == "" &&
173+
codeTrimmed != assets.XLMAssetCode &&
174+
codeTrimmed != assets.XLMAssetCodeAlias {
171175
return fmt.Errorf("payment asset issuer is empty for payment %s", p.ID)
172176
}
173177
// 4. payment.Amount is used as transaction.Amount

internal/services/send_receiver_wallets_invite_service.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"html/template"
77
"net/url"
88
"path"
9-
"slices"
109
"strings"
1110
"time"
1211

@@ -18,6 +17,7 @@ import (
1817
"github.com/stellar/stellar-disbursement-platform-backend/internal/data"
1918
"github.com/stellar/stellar-disbursement-platform-backend/internal/message"
2019
"github.com/stellar/stellar-disbursement-platform-backend/internal/sdpcontext"
20+
"github.com/stellar/stellar-disbursement-platform-backend/internal/services/assets"
2121
"github.com/stellar/stellar-disbursement-platform-backend/internal/utils"
2222
)
2323

@@ -329,7 +329,7 @@ type WalletDeepLink struct {
329329

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

335335
func (wdl WalletDeepLink) assetName() string {

internal/services/send_receiver_wallets_invite_service_test.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1213,10 +1213,10 @@ func Test_WalletDeepLink_isNativeAsset(t *testing.T) {
12131213
wantResult: true,
12141214
},
12151215
{
1216-
name: "🟢 xLm without issuer should be native asset (case insensitive)",
1217-
assetCode: "XLM",
1216+
name: "🔴 xLm without issuer should NOT be native asset (case sensitive)",
1217+
assetCode: "xLm",
12181218
assetIssuer: "",
1219-
wantResult: true,
1219+
wantResult: false,
12201220
},
12211221
{
12221222
name: "🔴 XLM with issuer should NOT be native asset",
@@ -1225,16 +1225,16 @@ func Test_WalletDeepLink_isNativeAsset(t *testing.T) {
12251225
wantResult: false,
12261226
},
12271227
{
1228-
name: "🟢 native without issuer should be native asset",
1229-
assetCode: "native",
1228+
name: "🟢 NATIVE without issuer should be native asset",
1229+
assetCode: "NATIVE",
12301230
assetIssuer: "",
12311231
wantResult: true,
12321232
},
12331233
{
1234-
name: "🟢 NaTiVe without issuer should be native asset (case insensitive)",
1234+
name: "🔴 NaTiVe without issuer should NOT be native asset (case sensitive)",
12351235
assetCode: "NaTiVe",
12361236
assetIssuer: "",
1237-
wantResult: true,
1237+
wantResult: false,
12381238
},
12391239
{
12401240
name: "🔴 native with issuer should NOT be native asset",
@@ -1286,7 +1286,7 @@ func Test_WalletDeepLink_assetName(t *testing.T) {
12861286
name: "'native' native asset",
12871287
assetCode: "native",
12881288
assetIssuer: "",
1289-
wantResult: "native",
1289+
wantResult: "native-",
12901290
},
12911291
{
12921292
name: "'native' with an issuer",

0 commit comments

Comments
 (0)