The properties of vToken, such as homogeneity, liquidity, and yield bearing, determine that it can satisfy a variety of DeFi usage scenarios. Therefore, vToken’s cross-chain DeFi interaction scenarios will be the core of expanding XCM use cases. SLPx needs to achieve the following goals:

  1. Support users to mint/redeem vToken on the target chain;

  2. Expand the application of vToken liquidity on the Bifrost chain, support cross-chain Swap and liquidation.

SLPx Pallet will be launched in two versions:

Technical Realization

SLPx mainly consists of two parts, one is the pallet module deployed on Bifrost, and the other is the Solidity contract deployed on the EVM-compatible parachain, which currently supports Astar/Moonbeam/Moonriver.

Logical operation, take Moonbeam vDOT minting as an example:

  1. For cross-chain asset transfer, DOT is sent to the account on the Bifrost chain. This account is used as an asset transfer and logical processing address. Each EVM address corresponds to a Substrate account one by one. For specific conversion logic, refer to Frontier Account Mapping Rules.

  2. Remotely execute the Bifrost SLPx pallet. Here, the address of msg.sender, which is the EVM user, will be hard-coded into the calldata of the remote execution of the Bifrost SLPx pallet. At the same time, the address will be obtained when the pallet is executed, so that the Bifrost chain will know Which EVM user is calling,

  3. After the Bifrost SLPx pallet logic is processed, the minted vDOT will be sent to the EVM contract caller on Moonbeam


It can be found that there is no mention of who is paying the transaction fee for the remote execution of the Bifrost SLPx pallet. In fact, it has been paid by the derivative address of the SLPx solidity contract in Bifrost. This is mainly for user experience. As long as the user address has DOT and Moonbeam's native Token as the gas fee, vDOT can be minted. In Bifrost, a little DOT will be deducted to make up for the transaction fee of remote execution. As for what Token is charged as the transaction fee depends on what Token is sent.

a. SLPx pallet

The pallet mainly uses token-minting, zenlink swap pallet module interface to complete VToken minting, redemption, swap and other functions on Bifrost.

b. SLPx solidity contract

The contract mainly uses the precompiled contract of the parachain to transfer assets to Bifrost and remotely call the SLPx pallet

SLPx solidity interface: https://github.com/bifrost-finance/slpx-contracts/blob/main/contracts/interfaces/ISlpx.sol

  • mintVNativeAsset() payable external: Mint the native Token on the parachain into VToken

  • mintVAsset(address assetAddress,uint256 amount) external: Mint the non-native Token on the parachain into VToken, such as DOT->vDOT that exists on Moonbeam

  • redeemAsset(address vAssetAddress, uint256 amount) external: Redeem your own VToken into Token. The redemption period varies according to the Token. For example, vDOT redemption is 0-28 days

  • swapAssetsForExactAssets(address assetInAddress, address assetOutAddress,uint256 assetInAmount, uint128 assetOutMin) external: swap one kind of Token into another kind of Token, for example, swap BNC into DOT

  • swapAssetsForExactNativeAssets(address assetInAddress, uint256 assetInAmount, uint128 assetOutMin) external: Swap a Token into a parachain’s native Token, such as BNC Swap into GLMR

  • swapNativeAssetsForExactAssets(address assetOutAddress, uint128 assetOutMin) payable external: Swap the native Token of the parachain into other Tokens, such as GLMR Swap into BNC

SLPx solidity contract Integration

NetworkSLPx Address







Astar Rococo


Moonbase Alpha


If you want to integrate SLPx in your contract, please see a sample code.

Among them are calls to the mintVNativeAsset and mintVAsset methods

Because of the use of XCM technology, the result of the call is not real-time, you'd better put the SLPx call at the end of your contract logic.

// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.0;

import "./ISlpx.sol";
import "./IERC20.sol";

contract Test {

    address public constant SLPX = 0xc6bf0C5C78686f1D0E2E54b97D6de6e2cEFAe9fD;

    function test_native_mint (address to) public payable   {
        // your contract logic.
        // ...
        // call mint
        ISlpx(SLPX).mintVNativeAsset{value: msg.value}(to);

    function test_mint (address assetAddress, uint256 amount, address to) public  {
        IERC20(assetAddress).approve(address(SLPX), amount);
        // your contract logic.
        // ...

    function test_redeem (address assetAddress, uint256 amount, address to) public  {
        IERC20(assetAddress).approve(address(SLPX), amount);
    function test_swap(address assetInAddress, address assetOutAddress,uint256 amount, uint128 amountOutMin,address to) public  {
        IERC20(assetInAddress).approve(address(SLPX), amount);

Last updated