SDEX Components
Buysell

Buy and Sell

The "BuySell" component allows a user to place a limit order to the SDEX orderbook.

Features

  • Collects source secret key, asset, and asset quantity and price.
  • Upon submission, an order is placed on the SDEX orderbook.
  • Assets included with this component are XLM, BTC, ETH, AQUA, VELO and USDC.
  • Provides a straightforward way to place a limit order on the SDEX.

Additional Resources

An account can create orders to buy or sell assets using the Manage Buy Offer, Manage Sell Offer, or Passive Order operations. The account must hold the asset it wants to exchange, and it must trust the issuer of the asset it is trying to buy.

⚠️

All sell orders are filled to USDC and not swapped between assets in this component. For more information on buy, sell, and management of orders on Stellar review the documentation below

C#

Install the PakanaRazorSDEX NuGet package via the NuGet Package Manager Console.

.Net8.0 or greater is required.

dotnet add package PakanaRazorSDEX --version 0.0.4
??

Stellar Horizon Dependency will install automatically

NuGet Package Implementation
<PakanaRazorSDEX.Component.BuySell/>
C#
@page "/RemoveSigner"
@rendermode InteractiveAuto
 
@using Microsoft.JSInterop
 
<div class="container">
    <h2>Buy | Sell</h2>
    <form id="offerForm">
        <label for="asset">Select Asset:</label>
        <select id="asset" name="asset" required>
            <option value="XLM">XLM</option>
            <option value="BTC">Bitcoin</option>
            <option value="AQUA">Aqua</option>
            <option value="ETH">Ethereum</option>
            <option value="VELO">Velo</option>
        </select>
 
        <label for="offerType">Offer Type:</label>
        <select id="offerType" name="offerType" required>
            <option value="sell">Sell Asset for USDC</option>
            <option value="buy">Buy Asset with USDC</option>
        </select>
 
        <label for="amount">Amount:</label>
        <input type="number"
               id="amount"
               name="amount"
               placeholder="Amount to trade"
               step="0.000001"
               required>
 
        <label for="price">Price:</label>
        <input type="number"
               id="price"
               name="price"
               placeholder="Price per asset (USDC/Asset)"
               step="0.000001"
               min="0.000001"
               required>
        <small>Up to 6 decimal places allowed.</small>
 
        <label for="secretKey">Your Secret Key:</label>
        <input type="password" id="secretKey" name="secretKey" placeholder="Your Stellar secret key" required>
 
        <button type="submit">Submit Offer</button>
    </form>
    <p id="message"></p>
</div>
 
@code {
    [Inject] IJSRuntime JS { get; set; }
 
    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            // Call the initializeChart function in the external JavaScript file
            await JS.InvokeVoidAsync("offerForm");
        }
    }
}
 
<script src="https://cdnjs.cloudflare.com/ajax/libs/stellar-sdk/13.0.0/stellar-sdk.min.js"></script>
<script src="./_content/PakanaRazorSDEX/js/buySell.js"></script>
<script src="./_content/PakanaRazorSDEX/js/global.js"></script>

Javascript

We've provided simple HTML and JavaScript that can be used in your project as partial-components or be customized and integrated into your existing codebase.

Stellar CDN
*Current Version as of 2024-24-12*
<script src="https://cdnjs.cloudflare.com/ajax/libs/stellar-sdk/13.0.0/stellar-sdk.min.js"></script>
JavaScript
 
<script>
        const assetMap = {
            XLM: { isNative: true }, // Mark as native
            BTC: { code: 'BTC', issuer: 'GDPJALI4AZKUU2W426U5WKMAT6CN3AJRPIIRYR2YM54TL2GDWO5O2MZM' },//mainnet only
            AQUA: { code: 'AQUA', issuer: 'GBNZILSTVQZ4R7IKQDGHYGY2QXL5QOFJYQMXPKWRRM5PAV7Y4M67AQUA' },//mainnet only
            ETH: { code: 'ETH', issuer: 'GBFXOHVAS43OIWNIO7XLRJAHT3BICFEIKOJLZVXNT572MISM4CMGSOCC' },//mainnet only
            VELO: { code: 'VELO', issuer: 'GDM4RQUQQUVSKQA7S6EM7XBZP3FCGH4Q7CL6TABQ7B2BEJ5ERARM2M5M' },//mainnet only
            USDC: { code: 'USDC', issuer: 'GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN' }//mainnet only
        };
 
        document.getElementById('offerForm').addEventListener('submit', async (event) => {
            event.preventDefault();
 
            const selectedAsset = document.getElementById('asset').value;
            const offerType = document.getElementById('offerType').value;
            const amount = parseFloat(document.getElementById('amount').value.trim());
            const price = parseFloat(document.getElementById('price').value.trim());
            const secretKey = document.getElementById('secretKey').value.trim();
 
            const message = document.getElementById('message');
            message.textContent = "Processing...";
            message.style.color = "black";
 
            try {
                const { Asset, Operation, Keypair, Account, TransactionBuilder, BASE_FEE } = window.StellarSdk;
 
                const keypair = Keypair.fromSecret(secretKey);
                const publicKey = keypair.publicKey();
 
                const NETWORK_PASSPHRASE = "Public Global Stellar Network ; September 2015";
 
                // Fetch account sequence
                const accountResponse = await server.accounts().accountId(publicKey).call();
                const account = new Account(publicKey, accountResponse.sequence);
 
                // Select the trading asset
                const assetDetails = assetMap[selectedAsset];
                const tradeAsset = assetDetails.isNative
                    ? Asset.native()
                    : new Asset(assetDetails.code, assetDetails.issuer);
 
                // USDC asset definition with issuer
                const usdcAsset = new Asset('USDC', 'GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN');  // Replace with the correct issuer
 
                // Ensure amount and price are valid
                if (isNaN(amount) || amount <= 0) {
                    message.style.color = 'red';
                    message.textContent = "Invalid amount.";
                    return;
                }
 
                if (isNaN(price) || price <= 0) {
                    message.style.color = 'red';
                    message.textContent = "Invalid price.";
                    return;
                }
 
                // Build the transaction
                const transaction = new TransactionBuilder(account, {
                    fee: BASE_FEE,
                    networkPassphrase: NETWORK_PASSPHRASE
                });
 
                // Add operation based on offer type
                if (offerType === 'sell') {
                    transaction.addOperation(Operation.manageSellOffer({
                        selling: tradeAsset,
                        buying: usdcAsset,
                        amount: amount.toFixed(7).toString(),  // Ensure correct precision
                        price: price.toFixed(7).toString(),   // Ensure correct precision
                        offerId: undefined // Omit offerId, let network assign
                    }));
                } else {
                    transaction.addOperation(Operation.manageBuyOffer({
                        selling: usdcAsset,
                        buying: tradeAsset,
                        buyAmount: amount.toFixed(7).toString(),
                        price: price.toFixed(7).toString(),
                        offerId: undefined // Omit offerId, let network assign
                    }));
                }
 
                const builtTransaction = transaction.setTimeout(30).build();
                builtTransaction.sign(keypair);
 
                // Submit transaction
                const result = await server.submitTransaction(builtTransaction);
 
                message.style.color = 'green';
                message.textContent = "Offer submitted successfully!";
            } catch (error) {
                message.style.color = 'red';
                message.textContent = `Error: ${error.message}`;
            }
        });
    </script>
 
 
HTML
 
<body>
    <div class="container">
        <h2>Buy | Sell</h2>
        <form id="offerForm">
            <label for="asset">Select Asset:</label>
            <select id="asset" name="asset" required>
                <option value="XLM">XLM</option>
                <option value="BTC">Bitcoin</option>
                <option value="AQUA">Aqua</option>
                <option value="ETH">Ethereum</option>
                <option value="VELO">Velo</option>
            </select>
 
            <label for="offerType">Offer Type:</label>
            <select id="offerType" name="offerType" required>
                <option value="sell">Sell Asset for USDC</option>
                <option value="buy">Buy Asset with USDC</option>
            </select>
 
            <label for="amount">Amount:</label>
            <input type="number"
                   id="amount"
                   name="amount"
                   placeholder="Amount to trade"
                   step="0.000001"
                   required>
 
            <label for="price">Price:</label>
            <input type="number"
                   id="price"
                   name="price"
                   placeholder="Price per asset (USDC/Asset)"
                   step="0.000001"
                   min="0.000001"
                   required>
            <small>Up to 6 decimal places allowed.</small>
 
            <label for="secretKey">Your Secret Key:</label>
            <input type="password" id="secretKey" name="secretKey" placeholder="Your Stellar secret key" required>
 
            <button type="submit">Submit Offer</button>
        </form>
        <p id="message"></p>
    </div>
</body>