Skip to main content

Subaccount

Smart Contract as Subaccount

Users can create multiple wallets to achieve sub-account functionality, but private key management for different accounts may be cumbersome. So we use a specially designed contract as a trading account, and the user's wallet address is the owner of this contract. This design can free users from changing their wallet address, and also an easy way for other protocols to build on JOJO.

Subaccount Factory

The Subaccount factory is a factory with the newSubaccount() function inside. Once trigger the function, the factory will clone an exact copy of the subaccount's implementation contract, but with its own storage space, which means that each clone has the same logic, but the storage state is independent.

/// @notice https://eips.ethereum.org/EIPS/eip-1167[EIP 1167]
/// is a standard protocol for deploying minimal proxy contracts,
/// also known as "clones".

function newSubaccount() external returns (address subaccount) {
subaccount = Clones.clone(template);
Subaccount(subaccount).init(msg.sender, dealer);
subaccountRegistry[msg.sender].push(subaccount);
emit NewSubaccount(msg.sender, subaccountRegistry[msg.sender].length - 1, subaccount);
}

Subaccount

Subaccounts can help their owner manage risk and positions. Users can open orders with isolated positions via Subaccount, and can also let others trade for you by setting them as authorized operators.

Execute for subaccount

Users can flexibly call different methods of various contracts through the execute function, which adds extensibility to the Subaccount. Since only the account that created the Subaccount can trigger the calls, there is no need to worry about ownership issues. Users can effortlessly deposit or withdraw assets to and from the JOJODealer and open positions by using the execute method.

    function execute(address to, bytes calldata data, uint256 value) external onlyOwner returns (bytes memory){
require(to != address(0));
(bool success, bytes memory returnData) = to.call{value: value}(data);
if (!success) {
assembly {
let ptr := mload(0x40)
let size := returndatasize()
returndatacopy(ptr, 0, size)
revert(ptr, size)
}
}
emit ExecuteTransaction(owner, address(this), to, data, value);
return returnData;
}