diff --git a/src/utils/stellar.ts b/src/utils/stellar.ts index 8d4c4ec..86fa44b 100644 --- a/src/utils/stellar.ts +++ b/src/utils/stellar.ts @@ -119,7 +119,11 @@ export const StellarUtils = { ? Networks.FUTURENET : Networks.TESTNET; - const asset = assetCode === 'XLM' ? Asset.native() : new Asset(assetCode, issuer as string); + if (assetCode !== 'XLM' && (!issuer || !ValidationUtils.isValidStellarAddress(issuer))) { + throw new Error(`A valid issuer is required for non-native asset payments: ${assetCode}`); + } + + const asset = assetCode === 'XLM' ? Asset.native() : new Asset(assetCode, issuer); // We use a dummy sequence number because the actual submission will be handled later // or by a signer that manages sequence numbers. diff --git a/tests/utils/stellar.test.ts b/tests/utils/stellar.test.ts index f53ba87..95e1568 100644 --- a/tests/utils/stellar.test.ts +++ b/tests/utils/stellar.test.ts @@ -92,6 +92,31 @@ describe('StellarUtils', () => { expect(parseFloat(operation.amount)).toBe(parseFloat(params.amount)); }); + it('should throw a clear error when a non-native asset issuer is missing', async () => { + await expect( + StellarUtils.buildPaymentXdr({ + source: validAccountId, + destination: validAccountId, + amount: '1.5', + assetCode: 'USDC', + network: 'testnet', + }), + ).rejects.toThrow('A valid issuer is required for non-native asset payments: USDC'); + }); + + it('should throw a clear error when a non-native asset issuer is invalid', async () => { + await expect( + StellarUtils.buildPaymentXdr({ + source: validAccountId, + destination: validAccountId, + amount: '1.5', + assetCode: 'USDC', + issuer: invalidAccountId, + network: 'testnet', + }), + ).rejects.toThrow('A valid issuer is required for non-native asset payments: USDC'); + }); + it('should throw when parsing invalid XDR', () => { expect(() => StellarUtils.parseXdrTransaction('invalid-xdr')).toThrow(/Failed to parse XDR/); });