Module sui::accumulator
- Struct
AccumulatorRoot
- Struct
Key
- Struct
OwnerKey
- Struct
Owner
- Struct
MetadataKey
- Struct
Metadata
- Struct
U128
- Constants
- Function
create
- Function
accumulator_address
- Function
root_has_accumulator
- Function
root_add_accumulator
- Function
root_borrow_accumulator_mut
- Function
root_remove_accumulator
- Function
accumulator_root_owner_exists
- Function
accumulator_root_borrow_owner_mut
- Function
accumulator_root_attach_owner
- Function
accumulator_root_detach_owner
- Function
create_accumulator_metadata
- Function
accumulator_metadata_remove
- Function
accumulator_owner_attach_metadata
- Function
accumulator_owner_detach_metadata
- Function
accumulator_owner_destroy
- Function
settlement_prologue
- Function
settle_u128
- Function
emit_deposit_event
- Function
emit_withdraw_event
use std::ascii;
use std::bcs;
use std::option;
use std::string;
use std::vector;
use sui::address;
use sui::bag;
use sui::dynamic_field;
use sui::hex;
use sui::object;
use sui::party;
use sui::transfer;
use sui::tx_context;
use sui::vec_map;
Struct AccumulatorRoot
public struct AccumulatorRoot has key
Fields
- id: sui::object::UID
Struct Key
Key is used only for computing the field id of accumulator objects. T is the type of the accumulated value, e.g. Balance<SUI>
public struct Key<phantom T> has copy, drop, store
Fields
- address: address
Struct OwnerKey
=== Accumulator metadata ===
Accumulator metadata is organized as follows:
- Each address that holds at least one type of accumulator has an owner object attached to the accumulator root.
- For each type of accumulator held by that address, there is an AccumulatorMetadata object attached to the owner object.
- When the value of an accumulator drops to zero, the metadata object is removed.
- If the owner object has no more accumulator metadata objects attached to it, it is removed as well.
public struct OwnerKey has copy, drop, store
Fields
- owner: address
Struct Owner
An owner object, to which all AccumulatorMetadata objects for the owner are attached.
public struct Owner has store
Fields
- balances: sui::bag::Bag
- The individual balances owned by the owner.
- owner: address
Struct MetadataKey
public struct MetadataKey<phantom T> has copy, drop, store
Fields
Struct Metadata
A metadata object for a balance object with type T.
public struct Metadata<phantom T> has store
Fields
- fields: sui::bag::Bag
- Any per-balance fields we wish to add in the future.
Struct U128
Storage for 128-bit accumulator values.
Currently only used to represent the sum of 64 bit values (such as Balance<T>). The additional bits are necessary to prevent overflow, as it would take 2^64 deposits of U64_MAX to cause an overflow.
public struct U128 has store
Fields
- value: u128
Constants
const ENotSystemAddress: u64 = 0;
const EInvalidSplitAmount: u64 = 1;
const EInvariantViolation: u64 = 2;
Function create
fun create(ctx: &sui::tx_context::TxContext)
Implementation
fun create(ctx: &TxContext) {
assert!(ctx.sender() == @0x0, ENotSystemAddress);
transfer::share_object(AccumulatorRoot {
id: object::sui_accumulator_root_object_id(),
})
}
Function accumulator_address
public(package) fun accumulator_address<T>(address: address): address
Implementation
public(package) fun accumulator_address<T>(address: address): address {
let key = Key<T> { address };
dynamic_field::hash_type_and_key(sui_accumulator_root_address(), key)
}
Function root_has_accumulator
Balance object methods
fun root_has_accumulator<K, V: store>(accumulator_root: &sui::accumulator::AccumulatorRoot, name: sui::accumulator::Key<K>): bool
Implementation
fun root_has_accumulator<K, V: store>(accumulator_root: &AccumulatorRoot, name: Key<K>): bool {
dynamic_field::exists_with_type<Key<K>, V>(&accumulator_root.id, name)
}
Function root_add_accumulator
fun root_add_accumulator<K, V: store>(accumulator_root: &mut sui::accumulator::AccumulatorRoot, name: sui::accumulator::Key<K>, value: V)
Implementation
fun root_add_accumulator<K, V: store>(
accumulator_root: &mut AccumulatorRoot,
name: Key<K>,
value: V,
) {
dynamic_field::add(&mut accumulator_root.id, name, value);
}
Function root_borrow_accumulator_mut
fun root_borrow_accumulator_mut<K, V: store>(accumulator_root: &mut sui::accumulator::AccumulatorRoot, name: sui::accumulator::Key<K>): &mut V
Implementation
fun root_borrow_accumulator_mut<K, V: store>(
accumulator_root: &mut AccumulatorRoot,
name: Key<K>,
): &mut V {
dynamic_field::borrow_mut<Key<K>, V>(&mut accumulator_root.id, name)
}
Function root_remove_accumulator
fun root_remove_accumulator<K, V: store>(accumulator_root: &mut sui::accumulator::AccumulatorRoot, name: sui::accumulator::Key<K>): V
Implementation
fun root_remove_accumulator<K, V: store>(accumulator_root: &mut AccumulatorRoot, name: Key<K>): V {
dynamic_field::remove<Key<K>, V>(&mut accumulator_root.id, name)
}
Function accumulator_root_owner_exists
=== Owner functions === Check if there is an owner object attached to the accumulator root.
fun accumulator_root_owner_exists(accumulator_root: &sui::accumulator::AccumulatorRoot, owner: address): bool
Implementation
fun accumulator_root_owner_exists(accumulator_root: &AccumulatorRoot, owner: address): bool {
dynamic_field::exists_with_type<OwnerKey, Owner>(&accumulator_root.id, OwnerKey { owner })
}
Function accumulator_root_borrow_owner_mut
Borrow an owner object mutably.
fun accumulator_root_borrow_owner_mut(accumulator_root: &mut sui::accumulator::AccumulatorRoot, owner: address): &mut sui::accumulator::Owner
Implementation
fun accumulator_root_borrow_owner_mut(
accumulator_root: &mut AccumulatorRoot,
owner: address,
): &mut Owner {
dynamic_field::borrow_mut(&mut accumulator_root.id, OwnerKey { owner })
}
Function accumulator_root_attach_owner
Attach an owner object to the accumulator root.
fun accumulator_root_attach_owner(accumulator_root: &mut sui::accumulator::AccumulatorRoot, owner: sui::accumulator::Owner)
Implementation
fun accumulator_root_attach_owner(accumulator_root: &mut AccumulatorRoot, owner: Owner) {
dynamic_field::add(&mut accumulator_root.id, OwnerKey { owner: owner.owner }, owner);
}
Function accumulator_root_detach_owner
Detach an owner object from the accumulator root.
fun accumulator_root_detach_owner(accumulator_root: &mut sui::accumulator::AccumulatorRoot, owner: address): sui::accumulator::Owner
Implementation
fun accumulator_root_detach_owner(accumulator_root: &mut AccumulatorRoot, owner: address): Owner {
dynamic_field::remove(&mut accumulator_root.id, OwnerKey { owner })
}
Function create_accumulator_metadata
=== Metadata functions === Create a metadata object for a new balance object with type T. The metadata will be attached to the owner object owner. If the owner object does not exist, it will be created.
fun create_accumulator_metadata<T>(accumulator_root: &mut sui::accumulator::AccumulatorRoot, owner: address, ctx: &mut sui::tx_context::TxContext)
Implementation
fun create_accumulator_metadata<T>(
accumulator_root: &mut AccumulatorRoot,
owner: address,
ctx: &mut TxContext,
) {
let metadata = Metadata<T> {
fields: bag::new(ctx),
};
if (accumulator_root.owner_exists(owner)) {
let accumulator_owner = accumulator_root.borrow_owner_mut(owner);
assert!(accumulator_owner.owner == owner, EInvariantViolation);
accumulator_owner.attach_metadata(metadata);
} else {
let mut accumulator_owner = Owner {
balances: bag::new(ctx),
owner,
};
accumulator_owner.attach_metadata(metadata);
accumulator_root.attach_owner(accumulator_owner);
}
}
Function accumulator_metadata_remove
Remove the metadata object for a balance object with type T. The metadata will be detached from the owner object owner. If there are no more balance objects attached to the owner object, the owner object will be destroyed.
fun accumulator_metadata_remove<T>(accumulator_root: &mut sui::accumulator::AccumulatorRoot, owner: address)
Implementation
fun accumulator_metadata_remove<T>(accumulator_root: &mut AccumulatorRoot, owner: address) {
let is_empty = {
let accumulator_owner = accumulator_root.borrow_owner_mut(owner);
let Metadata { fields } = accumulator_owner.detach_metadata<T>();
fields.destroy_empty();
accumulator_owner.balances.is_empty()
};
if (is_empty) {
let owner = accumulator_root.detach_owner(owner);
owner.destroy();
}
}
Function accumulator_owner_attach_metadata
Attach a metadata object for type T to the owner object.
fun accumulator_owner_attach_metadata<T>(self: &mut sui::accumulator::Owner, metadata: sui::accumulator::Metadata<T>)
Implementation
fun accumulator_owner_attach_metadata<T>(self: &mut Owner, metadata: Metadata<T>) {
self.balances.add(MetadataKey<T> {}, metadata);
}
Function accumulator_owner_detach_metadata
Detach a metadata object for type T from the owner object.
fun accumulator_owner_detach_metadata<T>(self: &mut sui::accumulator::Owner): sui::accumulator::Metadata<T>
Implementation
fun accumulator_owner_detach_metadata<T>(self: &mut Owner): Metadata<T> {
self.balances.remove(MetadataKey<T> {})
}
Function accumulator_owner_destroy
Destroy an owner object.
fun accumulator_owner_destroy(this: sui::accumulator::Owner)
Implementation
fun accumulator_owner_destroy(this: Owner) {
let Owner { balances, .. } = this;
balances.destroy_empty();
}
Function settlement_prologue
Called by settlement transactions to ensure that the settlement transaction has a unique digest.
fun settlement_prologue(_epoch: u64, _checkpoint_height: u64, _idx: u64, ctx: &sui::tx_context::TxContext)
Implementation
fun settlement_prologue(_epoch: u64, _checkpoint_height: u64, _idx: u64, ctx: &TxContext) {
assert!(ctx.sender() == @0x0, ENotSystemAddress);
}
Function settle_u128
fun settle_u128<T>(accumulator_root: &mut sui::accumulator::AccumulatorRoot, owner: address, merge: u128, split: u128, ctx: &mut sui::tx_context::TxContext)
Implementation
fun settle_u128<T>(
accumulator_root: &mut AccumulatorRoot,
owner: address,
merge: u128,
split: u128,
ctx: &mut TxContext,
) {
assert!(ctx.sender() == @0x0, ENotSystemAddress);
// Merge and split should be netted out prior to calling this function.
assert!((merge == 0 ) != (split == 0), EInvalidSplitAmount);
let name = Key<T> { address: owner };
if (accumulator_root.has_accumulator<T, U128>(name)) {
let is_zero = {
let value: &mut U128 = accumulator_root.borrow_accumulator_mut(name);
value.value = value.value + merge - split;
value.value == 0
};
if (is_zero) {
let U128 { value: _ } = accumulator_root.remove_accumulator<T, U128>(
name,
);
accumulator_root.remove_metadata<T>(owner);
}
} else {
// cannot split if the field does not yet exist
assert!(split == 0, EInvalidSplitAmount);
let value = U128 {
value: merge,
};
accumulator_root.add_accumulator(name, value);
accumulator_root.create_metadata<T>(owner, ctx);
};
}
Function emit_deposit_event
public(package) fun emit_deposit_event<T>(accumulator: address, recipient: address, amount: u64)
Implementation
public(package) native fun emit_deposit_event<T>(
accumulator: address,
recipient: address,
amount: u64,
);
Function emit_withdraw_event
public(package) fun emit_withdraw_event<T>(accumulator: address, owner: address, amount: u64)
Implementation
public(package) native fun emit_withdraw_event<T>(
accumulator: address,
owner: address,
amount: u64,
);