Skip to main content

Module 0xdee9::custodian_v2

use 0x2::balance;
use 0x2::coin;
use 0x2::object;
use 0x2::table;
use 0x2::tx_context;

Struct Account

struct Account<T> has store
Fields
available_balance: balance::Balance<T>
locked_balance: balance::Balance<T>

Resource AccountCap

Capability granting permission to access an entry in Custodian.account_balances. Calling mint_account_cap creates an "admin account cap" such that id == owner with the permission to both access funds and create new AccountCaps. Calling create_child_account_cap creates a "child account cap" such that id != owner that can access funds, but cannot create new AccountCaps.

struct AccountCap has store, key
Fields
id: object::UID
owner: address
The owner of this AccountCap. Note: this is derived from an object ID, not a user address

Resource Custodian

struct Custodian<T> has store, key
Fields
id: object::UID
account_balances: table::Table<address, custodian_v2::Account<T>>
Map from the owner address of AccountCap object to an Account object

Constants

const EAdminAccountCapRequired: u64 = 2;

Function mint_account_cap

Create an admin AccountCap that can be used across all DeepBook pools, and has the permission to create new AccountCaps that can access the same source of funds

public(friend) fun mint_account_cap(ctx: &mut tx_context::TxContext): custodian_v2::AccountCap
Implementation
public(package) fun mint_account_cap(ctx: &mut TxContext): AccountCap {
    let id = object::new(ctx);
    let owner = object::uid_to_address(&id);
    AccountCap { id, owner }
}

Function create_child_account_cap

Create a "child account cap" such that id != owner that can access funds, but cannot create new AccountCaps.

public fun create_child_account_cap(admin_account_cap: &custodian_v2::AccountCap, ctx: &mut tx_context::TxContext): custodian_v2::AccountCap
Implementation
public fun create_child_account_cap(admin_account_cap: &AccountCap, ctx: &mut TxContext): AccountCap {
    // Only the admin account cap can create new account caps
    assert!(object::uid_to_address(&admin_account_cap.id) == admin_account_cap.owner, EAdminAccountCapRequired);

    AccountCap {
        id: object::new(ctx),
        owner: admin_account_cap.owner
    }
}

Function delete_account_cap

Destroy the given account_cap object

public fun delete_account_cap(account_cap: custodian_v2::AccountCap)
Implementation
public fun delete_account_cap(account_cap: AccountCap) {
    let AccountCap { id, owner: _ } = account_cap;
    object::delete(id)
}

Function account_owner

Return the owner of an AccountCap

public fun account_owner(account_cap: &custodian_v2::AccountCap): address
Implementation
public fun account_owner(account_cap: &AccountCap): address {
    account_cap.owner
}

Function account_balance

public(friend) fun account_balance<Asset>(custodian: &custodian_v2::Custodian<Asset>, owner: address): (u64, u64)
Implementation
public(package) fun account_balance<Asset>(
    custodian: &Custodian<Asset>,
    owner: address
): (u64, u64) {
    // if custodian account is not created yet, directly return (0, 0) rather than abort
    if (!table::contains(&custodian.account_balances, owner)) {
        return (0, 0)
    };
    let account_balances = table::borrow(&custodian.account_balances, owner);
    let avail_balance = balance::value(&account_balances.available_balance);
    let locked_balance = balance::value(&account_balances.locked_balance);
    (avail_balance, locked_balance)
}

Function new

public(friend) fun new<T>(ctx: &mut tx_context::TxContext): custodian_v2::Custodian<T>
Implementation
public(package) fun new<T>(ctx: &mut TxContext): Custodian<T> {
    Custodian<T> {
        id: object::new(ctx),
        account_balances: table::new(ctx),
    }
}

Function withdraw_asset

public(friend) fun withdraw_asset<Asset>(custodian: &mut custodian_v2::Custodian<Asset>, quantity: u64, account_cap: &custodian_v2::AccountCap, ctx: &mut tx_context::TxContext): coin::Coin<Asset>
Implementation
public(package) fun withdraw_asset<Asset>(
    custodian: &mut Custodian<Asset>,
    quantity: u64,
    account_cap: &AccountCap,
    ctx: &mut TxContext
): Coin<Asset> {
    coin::from_balance(decrease_user_available_balance<Asset>(custodian, account_cap, quantity), ctx)
}

Function increase_user_available_balance

public(friend) fun increase_user_available_balance<T>(custodian: &mut custodian_v2::Custodian<T>, owner: address, quantity: balance::Balance<T>)
Implementation
public(package) fun increase_user_available_balance<T>(
    custodian: &mut Custodian<T>,
    owner: address,
    quantity: Balance<T>,
) {
    let account = borrow_mut_account_balance<T>(custodian, owner);
    balance::join(&mut account.available_balance, quantity);
}

Function decrease_user_available_balance

public(friend) fun decrease_user_available_balance<T>(custodian: &mut custodian_v2::Custodian<T>, account_cap: &custodian_v2::AccountCap, quantity: u64): balance::Balance<T>
Implementation
public(package) fun decrease_user_available_balance<T>(
    custodian: &mut Custodian<T>,
    account_cap: &AccountCap,
    quantity: u64,
): Balance<T> {
    let account = borrow_mut_account_balance<T>(custodian, account_cap.owner);
    balance::split(&mut account.available_balance, quantity)
}

Function increase_user_locked_balance

public(friend) fun increase_user_locked_balance<T>(custodian: &mut custodian_v2::Custodian<T>, account_cap: &custodian_v2::AccountCap, quantity: balance::Balance<T>)
Implementation
public(package) fun increase_user_locked_balance<T>(
    custodian: &mut Custodian<T>,
    account_cap: &AccountCap,
    quantity: Balance<T>,
) {
    let account = borrow_mut_account_balance<T>(custodian, account_cap.owner);
    balance::join(&mut account.locked_balance, quantity);
}

Function decrease_user_locked_balance

public(friend) fun decrease_user_locked_balance<T>(custodian: &mut custodian_v2::Custodian<T>, owner: address, quantity: u64): balance::Balance<T>
Implementation
public(package) fun decrease_user_locked_balance<T>(
    custodian: &mut Custodian<T>,
    owner: address,
    quantity: u64,
): Balance<T> {
    let account = borrow_mut_account_balance<T>(custodian, owner);
    split(&mut account.locked_balance, quantity)
}

Function lock_balance

Move quantity from the unlocked balance of user to the locked balance of user

public(friend) fun lock_balance<T>(custodian: &mut custodian_v2::Custodian<T>, account_cap: &custodian_v2::AccountCap, quantity: u64)
Implementation
public(package) fun lock_balance<T>(
    custodian: &mut Custodian<T>,
    account_cap: &AccountCap,
    quantity: u64,
) {
    let to_lock = decrease_user_available_balance(custodian, account_cap, quantity);
    increase_user_locked_balance(custodian, account_cap, to_lock);
}

Function unlock_balance

Move quantity from the locked balance of user to the unlocked balance of user

public(friend) fun unlock_balance<T>(custodian: &mut custodian_v2::Custodian<T>, owner: address, quantity: u64)
Implementation
public(package) fun unlock_balance<T>(
    custodian: &mut Custodian<T>,
    owner: address,
    quantity: u64,
) {
    let locked_balance = decrease_user_locked_balance<T>(custodian, owner, quantity);
    increase_user_available_balance<T>(custodian, owner, locked_balance)
}

Function account_available_balance

public(friend) fun account_available_balance<T>(custodian: &custodian_v2::Custodian<T>, owner: address): u64
Implementation
public(package) fun account_available_balance<T>(
    custodian: &Custodian<T>,
    owner: address,
): u64 {
    balance::value(&table::borrow(&custodian.account_balances, owner).available_balance)
}

Function account_locked_balance

public(friend) fun account_locked_balance<T>(custodian: &custodian_v2::Custodian<T>, owner: address): u64
Implementation
public(package) fun account_locked_balance<T>(
    custodian: &Custodian<T>,
    owner: address,
): u64 {
    balance::value(&table::borrow(&custodian.account_balances, owner).locked_balance)
}

Function borrow_mut_account_balance

fun borrow_mut_account_balance<T>(custodian: &mut custodian_v2::Custodian<T>, owner: address): &mut custodian_v2::Account<T>
Implementation
fun borrow_mut_account_balance<T>(
    custodian: &mut Custodian<T>,
    owner: address,
): &mut Account<T> {
    if (!table::contains(&custodian.account_balances, owner)) {
        table::add(
            &mut custodian.account_balances,
            owner,
            Account { available_balance: balance::zero(), locked_balance: balance::zero() }
        );
    };
    table::borrow_mut(&mut custodian.account_balances, owner)
}