MagicSpend++ Architecture
Overview
MagicSpend++ is a protocol that allows users to spend their funds on any chain they need. It consists of two main components: MagicSpendStakeManager
and MagicSpendWithdrawalManager
. The first one is responsible for managing user stakes, while the second one is responsible for managing the liquidity of the protocol. Each supported chain has deployed instances of these contracts.
MagicSpendStakeManager
MagicSpendStakeManager
is a contract that manages user stakes. The stake can be in native tokens (ETH, Matic, etc) or any ERC20 token. Users can add, unlock, and remove their staked balances. Pimlico has no control over the staked balances, and the user can remove them at any time. These funds are not used in fullfilling the user's requests. These stakes can only be claimed by Pimlico if the user explicitly provides a signed Allowance
message to authorize Pimlico to do so.
Allowance
message
/// @notice Helper struct that represents an allowance for a specific asset.
struct AssetAllowance {
/// @dev Token that can be claimed.
address token;
/// @dev The amount to claim.
uint128 amount;
/// @dev The chain id of the network, where the claim will be made.
uint128 chainId;
}
/// @notice Helper struct that represents an allowance.
/// @dev signed by the user it allows Pimlico to claim part of user's stake from the `MagicSpendStakeManager` contract
/// @dev on one or many chains.
struct Allowance {
/// @dev Address which stake is allowed to be claimed.
address account;
/// @dev List of assets, allowed to be claimed.
/// @dev One allowance per asset, where asset is the combination of (token,chainId)
AssetAllowance[] assets;
/// @dev The time in which the allowance is valid until.
uint48 validUntil;
/// @dev The time in which the allowance is valid after.
uint48 validAfter;
/// @dev The salt of the allowance.
uint48 salt;
/// @dev Signer which is allowed to request withdrawals on behalf of this allowance.
address operator;
}
Allowance
is a message that user signs and sends to Pimlico. It contains the details of the stake, such as the asset, amount, chain id, etc. Pimlico can claim the user's stake only if the user provided a signed Allowance
message.
Each Allowance
can have many AssetAllowance
, where each AssetAllowance
represents a unique combination of (AssetAllowance.token,AssetAllowance.chainId)
. It allows users to provide parts of their stakes on different chains and tokens in a single request.
Upgradability
Pimlico can upgrade the contracts to add new features or fix bugs. However, the upgradability is only available with a timelock equal to one week, so users have enough time to withdraw their funds if they don't agree with the changes. There is no timelock on testnets, so the contracts can be upgraded instantly.
MagicSpendWithdrawalManager
MagicSpendWithdrawalManager
is a contract that manages the liquidity of the MagicSpend++ protocol. It allows users to request withdrawals on any chain they need. This contract has no user's funds and stores only liquidity, added by Pimlico. Users can request withdrawals of their funds, if they provide a Withdrawal
message, signed by Pimlico.
Withdrawal
message
/// @notice Helper struct that represents a call to make.
struct Call {
address to;
uint256 value;
bytes data;
}
/// @notice This struct represents a withdrawal request.
/// @dev signed by the signer it allows to withdraw funds from the `MagicSpendWithdrawalManager` contract
struct Withdrawal {
/// @dev Token that will be withdrawn.
address token;
/// @dev The requested amount to withdraw.
uint128 amount;
/// @dev Chain id of the network, where the withdrawal will be executed.
uint128 chainId;
/// @dev Address that will receive the funds.
address recipient;
/// @dev Calls that will be made before the funds are sent to the user.
Call[] preCalls;
/// @dev Calls that will be made after the funds are sent to the user.
Call[] postCalls;
/// @dev The time in which the withdrawal is valid until.
uint48 validUntil;
/// @dev The time in which this withdrawal is valid after.
uint48 validAfter;
/// @dev The salt of the withdrawal.
uint48 salt;
}
Withdrawal
is a message that Pimlico signs and sends to user. It contains the details of the withdrawal, such as the asset, amount, recipient, chain id, etc.
MagicSpend++ Flow
This section describes the flow of the MagicSpend++ protocol. In order to start using MagicSpend++, users have to stake their funds. Read how to do that in the Staking section.
- User stakes their funds in the
MagicSpendStakeManager
contract, on one or many networks. - User sends a
pimlico_prepareMagicSpendAllowance
call, which returns theAllowance
. - User signs the
Allowance
and sends it withpimlico_grantMagicSpendAllowance
call. - Pimlico validates the
Allowance
and returns it's hash. - User sends a
pimlico_sponsorMagicSpendWithdrawal
call, where they specify the asset, amount, recipient, chain id, etc. - Pimlico signs the corresponding
Withdrawal
and returns it with a signature to user - User sends a transaction, which contains
MagicSpendWithdrawalManager.withdraw(Withdrawal withdrawal, bytes signature)
call and receives the funds. - Once
Withdrawal
is executed, Pimlico can claim the user's stake by callingMagicSpendStakeManager.claim(Allowance allowance, bytes signature)
.