Make a cross-chain swap on MAYAChain in less than 5 minutes.
MAYAChain allows native L1 Swaps. On-chain Memos are used instruct MAYAChain how to swap, with the option to add price limits and affiliate fees. MAYAChain nodes observe the inbound transactions and when the majority have observed the transactions, the transaction is processed by threshold-signature transactions from MAYAChain vaults.
Let's demonstrate decentralized, non-custodial cross-chain swaps. In this example, we will build a transaction that instructs MAYAChain to swap native Bitcoin to native Ethereum in one transaction.
MAYAChain uses a specific Available assets are at: .
BTC => BTC.BTC
ETH => ETH.ETH
Request: Swap 1 BTC to ETH and send the ETH to 0x3021c479f7f8c9f1d5c7d8523ba5e22c0bcb5430.
​​Response:
If you send 1 BTC to bc1qlccxv985m20qvd8g5yp6g9lc0wlc70v6zlalz8 with the memo =:ETH.ETH:0x3021c479f7f8c9f1d5c7d8523ba5e22c0bcb5430, you can expect to receive 18.55545107 ETH.
For security reasons, your inbound transaction will be delayed by 600 seconds (1 BTC Block) and 2685 seconds (or 179 native MAYAChain blocks) for the outbound transaction, 3285 seconds all up. You will pay an outbound gas fee of 0.0085 ETH and will incur 168 basis points (1.68%) of slippage.
​If you'd prefer to calculate the swap yourself, see the section to understand what fees need to be accounted for in the output amount. Also, review the section to understand how to create the swap memos.
Construct, sign and broadcast a transaction on the BTC network with the following parameters:
Amount => 1.0
Recipient => bc1qlccxv985m20qvd8g5yp6g9lc0wlc70v6zlalz8
Memo => =:ETH.ETH:0x3021c479f7f8c9f1d5c7d8523ba5e22c0bcb5430
Never cache inbound addresses! Quotes should only be considered valid for 10 minutes. Sending funds to an old inbound address will result in loss of funds.
Once a majority of nodes have observed your inbound BTC transaction, they will sign the Ethereum funds out of the network and send them to the address specified in your transaction. You have just completed a non-custodial, cross-chain swap by simply sending a native L1 transaction.
There is a rate limit of 1 request per second per IP address on /quote endpoints. It is advised to put a timeout on frontend components input fields, so that a request for quote only fires at most once per second. If not implemented correctly, you will receive 503 errors.
For best results, request a new quote right before the user submits a transaction. This will tell you whether the expected_amount_out has changed or if the inbound_address has changed. Ensuring that the expected_amount_out is still valid will lead to better user experience and less frequent failed transactions.
MAYAChain offers multiple mechanisms to protect users from excessive slippage during swaps. Without price limits, users could experience unbounded slippage and receive significantly less than expected.
Recommended: liquidity_tolerance_bps
This is the recommended parameter for controlling maximum acceptable slippage. It calculates the minimum output amount after accounting for outbound fees, providing accurate protection.
Key characteristics:
Measured in basis points (bps): 100 bps = 1%, 500 bps = 5%
Range: 0-9,999 basis points
Calculated relative to the expected_amount_out (after fees)
If slippage exceeds this threshold, the transaction reverts
Example Request:
The resulting memo will include a minimum output amount appended to the end:
This tells MAYAChain to revert the transaction if the final output amount is less than the calculated limit (expected_amount_out minus 5% tolerance).
Alternative: tolerance_bps (Not Recommended)
This older parameter exists but has a significant limitation: it calculates the price limit based on a feeless swap price and does not account for outbound fees. This often results in failed transactions when the actual output (after fees) falls below the limit.
Why it's not recommended:
Does not consider outbound gas fees in the calculation
Can cause legitimate swaps to fail unexpectedly
Less accurate protection for users
Important Notes:
You can only use one tolerance parameter per swap (not both)
Using both will result in an error: "must only include one of: tolerance_bps or liquidity_tolerance_bps"
Tolerance values must be less than 10,000 basis points (100%)
Memo Format with Price Limits
When price limits are applied, the memo structure includes the minimum output amount:
For streaming swaps with price limits:
Error Handling
Common errors you might encounter:
Price Limit Exceeded: "emit asset 2651686248 less than price limit 2719908600" - The output fell below your tolerance threshold
Invalid Range: "liquidity tolerance basis points must be less than 10000" - Tolerance value exceeds maximum
Conflicting Parameters: "must only include one of: tolerance_bps or liquidity_tolerance_bps" - Both parameters specified
Best Practices
Always use liquidity_tolerance_bps instead of tolerance_bps for accurate protection
Request fresh quotes immediately before transaction submission
Set reasonable tolerance based on pool depth and market conditions (typical range: 100-500 bps)
Specify affiliate_address and affiliate_bps to skim a percentage of the expected_amount_out.​​
Notice how wr:10 has been appended to the end of the memo. This instructs MAYAChain to skim 10 basis points from the swap. The user should still expect to receive the expected_amount_out, meaning the affiliate fee has already been subtracted from this number.
For more information on affiliate fees:
can be used to break up trades to reduce slip fees. Streaming swaps are currently enabled with a minimum basis point fee of 5 (0.05%).
Specify streaming_interval and streaming_quantity in your swap memo to use streaming swaps. For example:
/10/0 - Let the protocol determine optimal quantity, swap every 10 blocks
/5/3 - Execute 3 sub-swaps, one every 5 blocks
The protocol will automatically calculate the optimal swap quantity if you set it to 0. This feature helps large trades achieve better price execution by allowing arbitrageurs to rebalance pools between sub-swaps.
TBA
Developers experiencing issues with these APIs can go to the Maya Protocol Discord server (LINK) for assistance. Interface developers should subscribe to the #interface-alerts channel for information pertinent to the endpoints and functionality discussed here.
Monitor both expected_amount_out and inbound_address between quotes
{
"expected_amount_out": "1855545107",
"fees": {
"affiliate": "0",
"asset": "ETH.ETH",
"outbound": "840000"
},
"inbound_address": "bc1qqtemwlu9ju3ts3da5l82qejnzdl3xfs3lcl4wg",
"inbound_confirmation_blocks": 1,
"inbound_confirmation_seconds": 600,
"memo": "=:ETH.ETH:0x86d526d6624AbC0178cF7296cD538Ecc080A95F1",
"outbound_delay_blocks": 179,
"outbound_delay_seconds": 2685,
"slippage_bps": 168
}=:ETH.ETH:0x3021c479f7f8c9f1d5c7d8523ba5e22c0bcb5430:1762972381=:TO_ASSET:DESTINATION:MINIMUM_OUTPUT=:TO_ASSET:DESTINATION:MINIMUM_OUTPUT/STREAMING_INTERVAL/STREAMING_QUANTITY{
"expected_amount_out": "1851200268",
"fees": {
"affiliate": "1854014",
"asset": "ETH.ETH",
"outbound": "960000"
},
"inbound_address": "bc1qqtemwlu9ju3ts3da5l82qejnzdl3xfs3lcl4wg",
"inbound_confirmation_blocks": 1,
"inbound_confirmation_seconds": 600,
"memo": "=:ETH.ETH:0x3021c479f7f8c9f1d5c7d8523ba5e22c0bcb5430::wr:10",
"outbound_delay_blocks": 178,
"outbound_delay_seconds": 2670,
"slippage_bps": 168
}Streaming Swaps is a means for a swapper to get better price execution if they are patient. This ensures Capital Efficiency while still keeping with the philosophy "impatient people pay more".
There are two important parts to streaming swaps:
The interval part of the stream allows arbs enough time to rebalance intra-swap - this means the capital demands of swaps are met throughout, instead of after.
The quantity part of the stream allows the swapper to reduce the size of their sub-swap so each is executed with less slip (so the total swap will be executed with less slip) without losing capital to on-chain L1 fees.
If a swapper is willing to be patient, they can execute the swap with a better price, by allowing arbs to rebalance the pool between the streaming swaps.
Once all swaps are executed and the streaming swap is completed, the target token is sent to the user (minus outbound fees).
Streaming Swaps is similar to a Time Weighted Average Price (TWAP) trade however it is restricted to 24 hours (Mimir STREAMINGSWAPMAXLENGTH = 14400 blocks).
To utilise a streaming swap, use the following within a :
Trade Target or Limit / Swap Interval / Swap Quantity.
Limit or Trade Target: Uses the trade limit to set the maximum asset ratio at which a mini-swap can occur; otherwise, a refund is issued.
Interval: Block separation of each swap. For example, a value of 10 means a mini-swap is performed every 10 blocks.
Quantity: The number of swaps to be conducted. If set to 0, the network will determine the appropriate quantity.
Using the values Limit/10/5 would conduct five mini-swaps with a block separation of 10. Only swaps that achieve the specified asset ratio (defined by Limit) will be performed, while others will result in a refund.
On each swap attempt, the network will track how much (in funds) failed to swap and how much was successful. After all swap attempts are made (specified by "swap quantity"), the network will send out all successfully swapped value, and the remaining source asset via refund (that failed to swap for some reason, most likely due to the trade target).
If the first swap attempt fails for some reason, the entire streaming swap is refunded and no further attempts will be made. If the swap quantity is set to zero, the network will determine the number of swaps on its own with a focus on the lowest fees and maximize the number of trades.
A min swap size is placed on the network for streaming swaps (Mimir StreamingSwapMinBPFee = 5Basis Points). This is the minimum slip for each individual swap within a streaming swap allowed. This also puts a cap on the number of swaps in a streaming swap. This allows the network to be more friendly to large trades, while also keeping revenues up for small or medium-sized trades.
The network works out the optimal streaming swap solution based on the Mimumn Swap Size and the swapAmount.
Single Swap: To calculate the minimum swap size for a single swap, you take 2.5 basis points (bps) of the depth of the pool. The formula is as follows:
Example using BTC Pool:
BTC Cacao Depth = 20,007,476 CACAO
StreamingSwapMinBPFee = 5 bp
MinimumSwapSize = 0.0005 * 20,007,476 = 10,003. CACAO
Double Swap: When dealing with two pools of arbitrary depths and aiming for a precise 5 bps swap fee (set by StreamingSwapMinBPFee), you need to create a virtual pool size called cacaoDepth using the following formula:
r1 represents the cacao depth of pool1, and r2 represents the cacao depth of pool2.
The cacaoDepth is then used with 1.25 bps (half of 2.5 bps since there are two swaps), which gives you the minimum swap size that results in a 5 bps swap fee.
The larger the difference between the pools, the more the virtual pool skews towards the smaller pool. This results in less rewards given to the larger pool, and more rewards given to the smaller pool.
Example using BTC and ETH Pool
BTC Cacao Depth = 20,007,476 CACAO
ETH Cacao Depth = 8,870,648 CACAO
StreamingSwapMinBPFee = 5 bp
virtualCacaoDepth = (2*20,007,476*8,870,648) / (20,007,476 + 8,870,648) = 12,291,607 CACAO
MinimumSwapSize = (0.0005/4) * 12,291,607 = 1536.45 CACAO
The number of swaps required is determined by dividing the swap Amount by the minimum swap size calculated in the previous step.
The swapAmount represents the total amount to be swapped.
Example: swap 20,000 CACAO worth of BTC to ETH. (approx 0.653 BTC).
20,000 / 3,072.90 = 6.5 = 7 Swaps.
The difference between streaming swaps and non-streaming swaps can be calculated using the swap count with the following formula:
The differencevalue represents the percentage of the swap fee saved compared to doing the same swap with a regular fee structure. There higher the swapCount, the bigger the difference.
Example:
(7-1)/7 = 6/7 = 85% better price execution by being patient.
Swap Fees and Delay
Users pay up to four kinds of fees when conducting a swap.
Layer1 Network Fees (gas): paid by the user when sending the asset to MAYAChain to be swapped. This is controlled by the user's wallet.
Slip Fee: protects the pool from being manipulated by large swaps. Calculated as a function of transaction size and current pool depth. The slip fee formula is explained here(LINK) and an example implementation is .
Affiliate Fee - (optional) a percentage skimmed from the inbound amount that can be paid to exchanges or wallet providers. Wallets can now accept fees in any MAYAChain-supported asset (USDC, BTC, etc). Check the "Preferred Asset for Affiliate Fees" section in for more details and setup information.
Outbound Fee - the fee the Network pays on behalf of the user to send the outbound transaction. See Outbound Fee (LINK).
See the section for full details.
If a transaction fails, it is refunded, thus it will pay the outboundFee for the SourceChain not the DestinationChain. Thus devs should always swap an amount that is a maximum of the following, multiplied by at least a 4x buffer to allow for gas spikes:
The Destination Chain outboundFee, or
The Source Chain outboundFee, or
$1.00 (the minimum outboundFee).
For convenience, a recommended_min_amount_in is included on the endpoint, which is the value described above. This value is priced in the inbound asset of the quote request (in 1e8). This should be the minimum-allowed swap amount for the requested quote.
There are four phases of a transaction sent to MAYAChain each taking time to complete.
Layer1 Inbound Confirmation - assuming the inboundTx will be confirmed in the next block, it is the source blockchain block time.
Observation Counting - time for 67% MAYAChain Nodes to observe and agree on the inboundTx.
Confirmation Counting - for non-instant finality blockchains, the amount of time MAYAChain will wait before processing to protect against double spends and re-org attacks.
Wait times can be between a few seconds up to an hour. The assets being swapped, the size of the swap and the current network traffic within MAYAChain will determine the wait time.
See the section for full details.
Layer1 Outbound Confirmation - Outbound blockchain block time.