Copy
use std::string;
use sui::clock;
use sui::coin;
use sui::event;
use sui::sui;
use sage_admin::admin;
use sage_admin::admin_access;
use sage_admin::apps;
use sage_admin::fees;
use sage_analytics::analytics_actions;
use sage_post::post;
use sage_post::post_actions;
use sage_post::post_fees;
use sage_reward::reward_actions;
use sage_reward::reward_registry;
use sage_shared::membership;
use sage_trust::trust;
use sage_trust::trust_access;
use sage_user::user_fees;
use sage_user::user_invite;
use sage_user::user_owned;
use sage_user::user_registry;
use sage_user::user_shared;
use sage_user::user_witness;
use sage_utils::string_helpers;
Explore this module further in the Mover Registry: @sage/user
Events
ChannelFavoritesUpdate
Emitted when a User
favorites or unfavorites a Channel
.
Copy
public struct ChannelFavoritesUpdate has copy, drop
Show Fields
Show Fields
Copy
app_id: address,
favorited_channel_id: address,
message: u8,
updated_at: u64,
user_id: address
InviteCreated
Emitted when a new Invite
is created.
Copy
public struct InviteCreated has copy, drop
Show Fields
Show Fields
Copy
invite_code: std::string::String,
invite_key: std::string::String,
user_id: address
PostFavoritesUpdate
Emitted when a User
favorites or unfavorites a Post
.
Copy
public struct PostFavoritesUpdate has copy, drop
Show Fields
Show Fields
Copy
app_id: address,
favorited_post_id: address,
message: u8,
updated_at: u64,
user_id: address
UserCreated
Emitted when a new User
is created.
Copy
public struct UserCreated has copy, drop
Show Fields
Show Fields
Copy
avatar: std::string::String,
banner: std::string::String,
created_at: u64,
description: std::string::String,
invited_by: Option<address>,
user_id: address,
user_owned_id: address,
user_shared_id: address,
user_key: std::string::String,
user_name: std::string::String
UserFavoritesUpdate
Emitted when a User
favorites or unfavorites a User
.
Copy
public struct UserFavoritesUpdate has copy, drop
Show Fields
Show Fields
Copy
app_id: address,
favorited_user_id: address,
message: u8,
updated_at: u64,
user_id: address
UserFollowsUpdate
Emitted when a User
follows or unfollows another User
.
Copy
public struct UserFollowsUpdate has copy, drop
Show Fields
Show Fields
Copy
account_type: u8,
app_id: address,
followed_user_id: address,
message: u8,
updated_at: u64,
user_id: address
UserFriendUpdate
Emitted when a User
confirms friendship or unfriends another User
.
Copy
public struct UserFriendUpdate has copy, drop
Show Fields
Show Fields
Copy
account_type: u8,
app_id: address,
friended_user_id: address,
message: u8,
updated_at: u64,
user_id: address
UserFriendRequestUpdate
Emitted when a User
requests friendship with another User
.
Copy
public struct UserFriendRequestUpdate has copy, drop
Show Fields
Show Fields
Copy
account_type: u8,
app_id: address,
friended_user_id: address,
message: u8,
updated_at: u64,
user_id: address
UserPostCreated
Emitted when a new Post
is created for a User
.
Copy
public struct UserPostCreated has copy, drop
Show Fields
Show Fields
Copy
app_id: address,
created_at: u64,
created_by: address,
data: std::string::String,
description: std::string::String,
post_id: address,
title: std::string::String,
user_id: address
UserUpdated
Emitted when a User
is updated.
Copy
public struct UserUpdated has copy, drop
Show Fields
Show Fields
Copy
avatar: std::string::String,
banner: std::string::String,
description: std::string::String,
updated_at: u64,
user_id: address,
user_name: std::string::String
Constants
Maximum number of characters forUser
description.
Copy
const DESCRIPTION_MAX_LENGTH: u64 = 370;
User
name.
Copy
const USERNAME_MIN_LENGTH: u64 = 3;
User
name.
Copy
const USERNAME_MAX_LENGTH: u64 = 20;
User
actions that are tracked by Analytics
that result in $TRUST rewards.
Copy
const METRIC_COMMENT_GIVEN: vector<u8> = b"comment-given";
const METRIC_COMMENT_RECEIVED: vector<u8> = b"comment-received";
const METRIC_FAVORITED_POST: vector<u8> = b"favorited-post";
const METRIC_FOLLOWED_USER: vector<u8> = b"followed-user";
const METRIC_LIKED_POST: vector<u8> = b"liked-post";
const METRIC_POST_FAVORITED: vector<u8> = b"post-favorited";
const METRIC_POST_LIKED: vector<u8> = b"post-liked";
const METRIC_USER_FOLLOWED: vector<u8> = b"user-followed";
const METRIC_USER_FRIENDS: vector<u8> = b"user-friends";
const METRIC_USER_TEXT_POST: vector<u8> = b"user-text-posts";
User
description.
Copy
const EInvalidUserDescription: u64 = 370;
User
name.
Copy
const EInvalidUsername: u64 = 371;
User
without a (required) Invite
.
Copy
const EInviteRequired: u64 = 372;
User
’s own User
.
Copy
const ENoSelfJoin: u64 = 373;
User
.
Copy
const ENotSelf: u64 = 374;
User
who is not the author of a Post
.
Copy
const ESuppliedAuthorMismatch: u64 = 375;
User
. Only the casing may be changed (e.g. “user” to “USER”)
Copy
const EUserNameMismatch: u64 = 376;
Functions
add_favorite_channel
Allows a User
to add a favorite Channel
within an App
. Aborts with ETypeMismatch
if ChannelType
is not a Channel
.
Copy
public fun add_favorite_channel<ChannelType: key> (app: &App, clock: &Clock, channel: &ChannelType, channel_config: &ChannelConfig, owned_user: &mut UserOwned, ctx: &mut TxContext)
Show Implementation
Show Implementation
Copy
public fun add_favorite_channel<ChannelType: key> (
app: &App,
clock: &Clock,
channel: &ChannelType,
channel_config: &ChannelConfig,
owned_user: &mut UserOwned,
ctx: &mut TxContext
) {
admin_access::assert_channel(
channel_config,
channel
);
let app_address = object::id_address(app);
let timestamp = clock.timestamp_ms();
let (
message,
self,
favorited_channel_id,
_count
) = user_owned::add_favorite_channel(
channel,
owned_user,
app_address,
timestamp,
ctx
);
event::emit(ChannelFavoritesUpdate {
app_id: app_address,
favorited_channel_id,
message,
updated_at: timestamp,
user_id: self
});
}
add_favorite_post
Allows a User
to add a favorite Post
within an App
. Aborts with ESuppliedAuthorMismatch
if the supplied SharedUser
is not the author of the Post
.
Copy
public fun add_favorite_post(app: &App, clock: &Clock, owned_user: &mut UserOwned, post: &Post, reward_weights_registry: &RewardWeightsRegistry, user: &mut UserShared, user_witness_config: &UserWitnessConfig, ctx: &mut TxContext)
Show Implementation
Show Implementation
Copy
public fun add_favorite_post(
app: &App,
clock: &Clock,
owned_user: &mut UserOwned,
post: &Post,
reward_weights_registry: &RewardWeightsRegistry,
user: &mut UserShared,
user_witness_config: &UserWitnessConfig,
ctx: &mut TxContext
) {
let favorite_post_author = post.get_author();
let supplied_author_address = user.get_owner();
assert!(favorite_post_author == supplied_author_address, ESuppliedAuthorMismatch);
let app_address = object::id_address(app);
let timestamp = clock.timestamp_ms();
let (
message,
self,
favorited_post_id,
count
) = user_owned::add_favorite_post(
post,
owned_user,
app_address,
timestamp,
ctx
);
let has_rewards_enabled = app.has_rewards_enabled();
if (
has_rewards_enabled &&
favorite_post_author != self &&
count == 1
) {
let current_epoch = reward_registry::get_current(
reward_weights_registry
);
let analytics_self = user_owned::borrow_or_create_analytics_mut(
owned_user,
user_witness_config,
app_address,
current_epoch,
ctx
);
let reward_weights = reward_weights_registry.borrow_current();
let metric_author = utf8(METRIC_POST_FAVORITED);
let metric_self = utf8(METRIC_FAVORITED_POST);
let claim_author = reward_weights.get_weight(metric_author);
let claim_self = reward_weights.get_weight(metric_self);
let user_witness = user_witness::create_witness();
analytics_actions::increment_analytics_for_user<UserWitness>(
analytics_self,
app,
&user_witness,
user_witness_config,
claim_self,
metric_self
);
let analytics_author = user_shared::borrow_or_create_analytics_mut(
user,
user_witness_config,
app_address,
current_epoch,
ctx
);
analytics_actions::increment_analytics_for_user<UserWitness>(
analytics_author,
app,
&user_witness,
user_witness_config,
claim_author,
metric_author
);
};
event::emit(PostFavoritesUpdate {
app_id: app_address,
favorited_post_id,
message,
updated_at: timestamp,
user_id: self
});
}
add_favorite_user
Allows a User
to add a favorite User
within an App
.
Copy
public fun add_favorite_user(app: &App, clock: &Clock, owned_user: &mut UserOwned, user: &UserShared, ctx: &mut TxContext)
Show Implementation
Show Implementation
Copy
public fun add_favorite_user(
app: &App,
clock: &Clock,
owned_user: &mut UserOwned,
user: &UserShared,
ctx: &mut TxContext
) {
let app_address = object::id_address(app);
let timestamp = clock.timestamp_ms();
let (
message,
self,
favorited_user_id,
_count
) = user_owned::add_favorite_user(
owned_user,
user,
app_address,
timestamp,
ctx
);
event::emit(UserFavoritesUpdate {
app_id: app_address,
favorited_user_id,
message,
updated_at: timestamp,
user_id: self
});
}
assert_user_description
Aborts with EInvalidUserDescription
if the description is invalid.
Copy
public fun assert_user_description(description: &String)
Show Implementation
Show Implementation
Copy
public fun assert_user_description(
description: &String
) {
let is_valid_description = is_valid_description(description);
assert!(is_valid_description, EInvalidUserDescription);
}
assert_user_name
Aborts with EInvalidUsername
if the name is invalid.
Copy
public fun assert_user_name(name: &String)
Show Implementation
Show Implementation
Copy
public fun assert_user_name(
name: &String
) {
let is_valid_name = string_helpers::is_valid_name(
name,
USERNAME_MIN_LENGTH,
USERNAME_MAX_LENGTH
);
assert!(is_valid_name, EInvalidUsername);
}
claim_reward
If User
has an available claim on the App
and for the specified epoch, then mints $TRUST and transfers it to the User
’s wallet. Aborts with ENotSelf
if the SharedUser
does not belong to the wallet address.
Copy
public fun claim_reward(app: &App, mint_config: &MintConfig, reward_witness_config: &RewardWitnessConfig, treasury: &mut ProtectedTreasury, owned_user: &mut UserOwned, shared_user: &mut UserShared, user_witness_config: &UserWitnessConfig, epoch: u64, ctx: &mut TxContext)
Show Implementation
Show Implementation
Copy
public fun claim_reward(
app: &App,
mint_config: &MintConfig,
reward_witness_config: &RewardWitnessConfig,
treasury: &mut ProtectedTreasury,
owned_user: &mut UserOwned,
shared_user: &mut UserShared,
user_witness_config: &UserWitnessConfig,
epoch: u64,
ctx: &mut TxContext
) {
let self = tx_context::sender(ctx);
let owner = shared_user.get_owner();
assert!(owner == self, ENotSelf);
let app_address = object::id_address(app);
let user_witness = user_witness::create_witness();
let mut total_coin_option: Option<Coin<TRUST>> = option::none();
let has_owned_analytics = owned_user.has_analytics(
app_address,
epoch
);
if (has_owned_analytics) {
let analytics = owned_user.borrow_analytics_mut(
app_address,
epoch
);
let (
_amount,
coin_option
) = reward_actions::claim_value_for_user<UserWitness>(
analytics,
app,
mint_config,
reward_witness_config,
treasury,
&user_witness,
user_witness_config,
ctx
);
if (coin_option.is_some()) {
total_coin_option.destroy_none();
total_coin_option = coin_option;
} else {
coin_option.destroy_none();
};
};
let has_shared_analytics = shared_user.has_analytics(
app_address,
epoch
);
if (has_shared_analytics) {
let analytics = shared_user.borrow_analytics_mut(
app_address,
epoch
);
let (
_amount,
coin_option
) = reward_actions::claim_value_for_user<UserWitness>(
analytics,
app,
mint_config,
reward_witness_config,
treasury,
&user_witness,
user_witness_config,
ctx
);
if (coin_option.is_some()) {
let coin = coin_option.destroy_some();
if (total_coin_option.is_some()) {
let mut total_coin = total_coin_option.destroy_some();
total_coin.join(coin);
total_coin_option = option::some(total_coin);
} else {
total_coin_option.destroy_none();
total_coin_option = option::some(coin);
};
} else {
coin_option.destroy_none();
};
};
if (total_coin_option.is_some()) {
let total_coin = total_coin_option.destroy_some();
let balance = total_coin.balance();
let amount = balance.value();
owned_user.add_to_total_rewards(amount);
transfer::public_transfer(total_coin, self);
} else {
total_coin_option.destroy_none();
};
}
comment
Create a comment on a Post
. Aborts with ESuppliedAuthorMismatch
if the supplied SharedUser
is not the author of the parent Post
.
Copy
public fun comment<CoinType> (app: &App, clock: &Clock, owned_user: &mut UserOwned, parent_post: &mut Post, post_fees: &PostFees, reward_weights_registry: &RewardWeightsRegistry, shared_user: &mut UserShared, user_witness_config: &UserWitnessConfig, data: String, description: String, title: String, custom_payment: Coin<CoinType>, sui_payment: Coin<SUI>, ctx: &mut TxContext): (address, address, u64)
Show Implementation
Show Implementation
Copy
public fun comment<CoinType> (
app: &App,
clock: &Clock,
owned_user: &mut UserOwned,
parent_post: &mut Post,
post_fees: &PostFees,
reward_weights_registry: &RewardWeightsRegistry,
shared_user: &mut UserShared,
user_witness_config: &UserWitnessConfig,
data: String,
description: String,
title: String,
custom_payment: Coin<CoinType>,
sui_payment: Coin<SUI>,
ctx: &mut TxContext
): (
address,
address,
u64
) {
let has_rewards_enabled = app.has_rewards_enabled();
let parent_author = parent_post.get_author();
let self = tx_context::sender(ctx);
let user_witness = user_witness::create_witness();
if (
has_rewards_enabled &&
parent_author != self
) {
let supplied_author = shared_user.get_owner();
assert!(parent_author == supplied_author, ESuppliedAuthorMismatch);
let app_address = object::id_address(app);
let current_epoch = reward_registry::get_current(
reward_weights_registry
);
let reward_weights = reward_weights_registry.borrow_current();
let metric_parent = utf8(METRIC_COMMENT_RECEIVED);
let metric_self = utf8(METRIC_COMMENT_GIVEN);
let claim_parent = reward_weights.get_weight(metric_parent);
let claim_self = reward_weights.get_weight(metric_self);
let analytics_self = user_owned::borrow_or_create_analytics_mut(
owned_user,
user_witness_config,
app_address,
current_epoch,
ctx
);
analytics_actions::increment_analytics_for_user<UserWitness>(
analytics_self,
app,
&user_witness,
user_witness_config,
claim_self,
metric_self
);
let analytics_parent = user_shared::borrow_or_create_analytics_mut(
shared_user,
user_witness_config,
app_address,
current_epoch,
ctx
);
analytics_actions::increment_analytics_for_user<UserWitness>(
analytics_parent,
app,
&user_witness,
user_witness_config,
claim_parent,
metric_parent
);
};
post_actions::comment_for_user<CoinType, UserWitness>(
app,
clock,
parent_post,
post_fees,
&user_witness,
user_witness_config,
data,
description,
title,
custom_payment,
sui_payment,
ctx
)
}
create
Create a new User
. Aborts with EInvalidUserDescription
or EInvalidUsername
if the description or name is invalid, EInviteRequired
if an Invite
is required and not supplied, EInviteDoesNotExist
if invite info was supplied but does not exist in the registry, EInviteInvalid
if invite info was supplied but is not valid, or EIncorrectCoinType
, EIncorrectCustomPayment
, or EIncorrectSuiPayment
if the payment was incorrect.
Copy
public fun create<CoinType> (clock: &Clock, invite_config: &InviteConfig, user_registry: &mut UserRegistry, user_invite_registry: &mut UserInviteRegistry, user_fees: &UserFees, invite_code_option: Option<String>, invite_key_option: Option<String>, avatar: String, banner: String, description: String, name: String, custom_payment: Coin<CoinType>, sui_payment: Coin<SUI>, ctx: &mut TxContext): (address, address)
Show Implementation
Show Implementation
Copy
public fun create<CoinType> (
clock: &Clock,
invite_config: &InviteConfig,
user_registry: &mut UserRegistry,
user_invite_registry: &mut UserInviteRegistry,
user_fees: &UserFees,
invite_code_option: Option<String>,
invite_key_option: Option<String>,
avatar: String,
banner: String,
description: String,
name: String,
custom_payment: Coin<CoinType>,
sui_payment: Coin<SUI>,
ctx: &mut TxContext
): (address, address) {
assert_user_name(&name);
assert_user_description(&description);
let (
custom_payment,
sui_payment
) = user_fees::assert_create_user_payment<CoinType>(
user_fees,
custom_payment,
sui_payment
);
let is_invite_included =
option::is_some(&invite_code_option) &&
option::is_some(&invite_key_option);
let is_invite_required = user_invite::is_invite_required(
invite_config
);
assert!(
!is_invite_required || is_invite_included,
EInviteRequired
);
let invited_by = if (is_invite_included) {
let invite_code = option::destroy_some(invite_code_option);
let invite_key = option::destroy_some(invite_key_option);
user_invite::assert_invite_exists(
user_invite_registry,
invite_key
);
let (hash, user_address) = user_invite::get_destructured_invite(
user_invite_registry,
invite_key
);
user_invite::assert_invite_is_valid(
invite_code,
invite_key,
hash
);
user_invite::delete_invite(
user_invite_registry,
invite_key
);
option::some(user_address)
} else {
option::none()
};
let created_at = clock.timestamp_ms();
let self = tx_context::sender(ctx);
let user_key = string_helpers::to_lowercase(
&name
);
let (
owned_user,
owned_user_address
) = user_owned::create(
avatar,
banner,
created_at,
description,
user_key,
name,
self,
ctx
);
let shared_user_address = user_shared::create(
created_at,
user_key,
owned_user_address,
self,
ctx
);
user_owned::set_shared_user(
owned_user,
self,
shared_user_address
);
user_registry::add(
user_registry,
user_key,
self,
owned_user_address,
shared_user_address
);
fees::collect_payment<CoinType>(
custom_payment,
sui_payment
);
event::emit(UserCreated {
avatar,
banner,
created_at,
description,
invited_by,
user_owned_id: owned_user_address,
user_shared_id: shared_user_address,
user_id: self,
user_key,
user_name: name
});
(
owned_user_address,
shared_user_address
)
}
create_invite
Create an invite for another wallet address. Aborts with EInviteNotAllowed
if invites are required, or EIncorrectCoinType
, EIncorrectCustomPayment
, or EIncorrectSuiPayment
if the payment was incorrect.
Copy
public fun create_invite<CoinType> (invite_config: &InviteConfig, user_fees: &UserFees, user_invite_registry: &mut UserInviteRegistry, _: &UserOwned, invite_code: String, invite_hash: vector<u8>, invite_key: String, custom_payment: Coin<CoinType>, sui_payment: Coin<SUI>, ctx: &mut TxContext)
Show Implementation
Show Implementation
Copy
public fun create_invite<CoinType> (
invite_config: &InviteConfig,
user_fees: &UserFees,
user_invite_registry: &mut UserInviteRegistry,
_: &UserOwned,
invite_code: String,
invite_hash: vector<u8>,
invite_key: String,
custom_payment: Coin<CoinType>,
sui_payment: Coin<SUI>,
ctx: &mut TxContext
) {
user_invite::assert_invite_not_required(invite_config);
let (
custom_payment,
sui_payment
) = user_fees::assert_create_invite_payment<CoinType>(
user_fees,
custom_payment,
sui_payment
);
let self = tx_context::sender(ctx);
user_invite::create_invite(
user_invite_registry,
invite_hash,
invite_key,
self
);
fees::collect_payment<CoinType>(
custom_payment,
sui_payment
);
event::emit(InviteCreated {
invite_code,
invite_key,
user_id: self
});
}
follow
User
follows another User
within an App
. Aborts with ENoSelfJoin
if attempting to follow one’s self, EIncorrectCoinType
, EIncorrectCustomPayment
, or EIncorrectSuiPayment
if the payment was incorrect.
Copy
public fun follow<CoinType> (app: &App, clock: &Clock, owned_user: &mut UserOwned, reward_weights_registry: &RewardWeightsRegistry, shared_user: &mut UserShared, user_fees: &UserFees, user_witness_config: &UserWitnessConfig, custom_payment: Coin<CoinType>, sui_payment: Coin<SUI>, ctx: &mut TxContext)
Show Implementation
Show Implementation
Copy
public fun follow<CoinType> (
app: &App,
clock: &Clock,
owned_user: &mut UserOwned,
reward_weights_registry: &RewardWeightsRegistry,
shared_user: &mut UserShared,
user_fees: &UserFees,
user_witness_config: &UserWitnessConfig,
custom_payment: Coin<CoinType>,
sui_payment: Coin<SUI>,
ctx: &mut TxContext
) {
let (
custom_payment,
sui_payment
) = user_fees::assert_follow_user_payment<CoinType>(
user_fees,
custom_payment,
sui_payment
);
let self = tx_context::sender(ctx);
let user_address = user_shared::get_owner(shared_user);
assert!(self != user_address, ENoSelfJoin);
let app_address = object::id_address(app);
let follows = user_shared::borrow_follows_mut(
shared_user,
app_address,
ctx
);
let timestamp = clock.timestamp_ms();
let (
membership_message,
membership_type,
membership_count
) = membership::wallet_join(
follows,
self,
timestamp
);
fees::collect_payment<CoinType>(
custom_payment,
sui_payment
);
let has_rewards_enabled = apps::has_rewards_enabled(
app
);
if (has_rewards_enabled && membership_count == 1) {
let current_epoch = reward_registry::get_current(
reward_weights_registry
);
let reward_weights = reward_weights_registry.borrow_current();
let metric_followed = utf8(METRIC_USER_FOLLOWED);
let metric_self = utf8(METRIC_FOLLOWED_USER);
let claim_followed = reward_weights.get_weight(metric_followed);
let claim_self = reward_weights.get_weight(metric_self);
let analytics_self = user_owned::borrow_or_create_analytics_mut(
owned_user,
user_witness_config,
app_address,
current_epoch,
ctx
);
let user_witness = user_witness::create_witness();
analytics_actions::increment_analytics_for_user<UserWitness>(
analytics_self,
app,
&user_witness,
user_witness_config,
claim_self,
metric_self
);
let analytics_followed = user_shared::borrow_or_create_analytics_mut(
shared_user,
user_witness_config,
app_address,
current_epoch,
ctx
);
analytics_actions::increment_analytics_for_user<UserWitness>(
analytics_followed,
app,
&user_witness,
user_witness_config,
claim_followed,
metric_followed
);
};
event::emit(UserFollowsUpdate {
account_type: membership_type,
app_id: app_address,
followed_user_id: user_address,
message: membership_message,
updated_at: timestamp,
user_id: self
});
}
friend_user
Creates a friend request between two User
s if one does not exist, or creates a friendship if the other User
had already requested to be friends. Aborts with ENotSelf
if attempting to friend one’s self, or EIncorrectCoinType
, EIncorrectCustomPayment
, or EIncorrectSuiPayment
if the payment was incorrect.
Copy
public fun friend_user<CoinType> (app: &App, clock: &Clock, reward_weights_registry: &RewardWeightsRegistry, user_fees: &UserFees, user_friend: &mut UserShared, user_shared: &mut UserShared, user_witness_config: &UserWitnessConfig, custom_payment: Coin<CoinType>, sui_payment: Coin<SUI>, ctx: &mut TxContext)
Show Implementation
Show Implementation
Copy
public fun friend_user<CoinType> (
app: &App,
clock: &Clock,
reward_weights_registry: &RewardWeightsRegistry,
user_fees: &UserFees,
user_friend: &mut UserShared,
user_shared: &mut UserShared,
user_witness_config: &UserWitnessConfig,
custom_payment: Coin<CoinType>,
sui_payment: Coin<SUI>,
ctx: &mut TxContext
) {
let (
custom_payment,
sui_payment
) = user_fees::assert_friend_user_payment<CoinType>(
user_fees,
custom_payment,
sui_payment
);
let friend_address = user_shared::get_owner(user_friend);
let user_address = user_shared::get_owner(user_shared);
let self = tx_context::sender(ctx);
assert!(self == user_address, ENotSelf);
let app_address = object::id_address(app);
let friend_requests = user_shared::borrow_friend_requests_mut(
user_shared,
app_address,
ctx
);
let already_requested = membership::is_member(
friend_requests,
friend_address
);
let timestamp = clock.timestamp_ms();
if (already_requested) {
membership::wallet_leave(
friend_requests,
friend_address,
timestamp
);
let friends = user_shared::borrow_friends_mut(
user_shared,
app_address,
ctx
);
membership::wallet_join(
friends,
friend_address,
timestamp
);
let friends_friends = user_shared::borrow_friends_mut(
user_friend,
app_address,
ctx
);
let (
membership_message,
membership_type,
membership_count
) = membership::wallet_join(
friends_friends,
user_address,
timestamp
);
let has_rewards_enabled = apps::has_rewards_enabled(
app
);
if (has_rewards_enabled && membership_count == 1) {
let current_epoch = reward_registry::get_current(
reward_weights_registry
);
let reward_weights = reward_weights_registry.borrow_current();
let metric = utf8(METRIC_USER_FRIENDS);
let claim = reward_weights.get_weight(metric);
let analytics = user_shared::borrow_or_create_analytics_mut(
user_shared,
user_witness_config,
app_address,
current_epoch,
ctx
);
let user_witness = user_witness::create_witness();
analytics_actions::increment_analytics_for_user<UserWitness>(
analytics,
app,
&user_witness,
user_witness_config,
claim,
metric
);
let friend_analytics = user_shared::borrow_or_create_analytics_mut(
user_friend,
user_witness_config,
app_address,
current_epoch,
ctx
);
analytics_actions::increment_analytics_for_user<UserWitness>(
friend_analytics,
app,
&user_witness,
user_witness_config,
claim,
metric
);
};
event::emit(UserFriendUpdate {
account_type: membership_type,
app_id: app_address,
friended_user_id: friend_address,
message: membership_message,
updated_at: timestamp,
user_id: user_address
});
} else {
let friends_friend_requests = user_shared::borrow_friend_requests_mut(
user_friend,
app_address,
ctx
);
let (
membership_message,
membership_type,
_membership_count
) = membership::wallet_join(
friends_friend_requests,
user_address,
timestamp
);
event::emit(UserFriendRequestUpdate {
account_type: membership_type,
app_id: app_address,
friended_user_id: friend_address,
message: membership_message,
updated_at: timestamp,
user_id: user_address
});
};
fees::collect_payment<CoinType>(
custom_payment,
sui_payment
);
}
like_post
User
likes a Post
. Aborts with ESuppliedAuthorMismatch
if the SharedUser
is not the author of the Post
, or EIncorrectCoinType
, EIncorrectCustomPayment
, or EIncorrectSuiPayment
if the payment was incorrect.
Copy
public fun like_post<CoinType> (app: &App, clock: &Clock, owned_user: &mut UserOwned, post: &mut Post, post_fees: &PostFees, reward_weights_registry: &RewardWeightsRegistry, royalties: &Royalties, shared_user: &mut UserShared, user_witness_config: &UserWitnessConfig, custom_payment: Coin<CoinType>, sui_payment: Coin<SUI>, ctx: &mut TxContext)
Show Implementation
Show Implementation
Copy
public fun like_post<CoinType> (
app: &App,
clock: &Clock,
owned_user: &mut UserOwned,
post: &mut Post,
post_fees: &PostFees,
reward_weights_registry: &RewardWeightsRegistry,
royalties: &Royalties,
shared_user: &mut UserShared,
user_witness_config: &UserWitnessConfig,
custom_payment: Coin<CoinType>,
sui_payment: Coin<SUI>,
ctx: &mut TxContext
) {
let author_address = post.get_author();
let shared_user_address = shared_user.get_owner();
assert!(author_address == shared_user_address, ESuppliedAuthorMismatch);
let user_witness = user_witness::create_witness();
post_actions::like_for_user<CoinType, UserWitness>(
clock,
post,
post_fees,
royalties,
&user_witness,
user_witness_config,
custom_payment,
sui_payment,
ctx
);
let has_rewards_enabled = app.has_rewards_enabled();
let self = tx_context::sender(ctx);
if (
has_rewards_enabled &&
author_address != self
) {
let app_address = object::id_address(app);
let current_epoch = reward_registry::get_current(
reward_weights_registry
);
let analytics_self = user_owned::borrow_or_create_analytics_mut(
owned_user,
user_witness_config,
app_address,
current_epoch,
ctx
);
let reward_weights = reward_weights_registry.borrow_current();
let metric_author = utf8(METRIC_POST_LIKED);
let metric_self = utf8(METRIC_LIKED_POST);
let claim_author = reward_weights.get_weight(metric_author);
let claim_self = reward_weights.get_weight(metric_self);
let user_witness = user_witness::create_witness();
analytics_actions::increment_analytics_for_user<UserWitness>(
analytics_self,
app,
&user_witness,
user_witness_config,
claim_self,
metric_self
);
let analytics_author = user_shared::borrow_or_create_analytics_mut(
shared_user,
user_witness_config,
app_address,
current_epoch,
ctx
);
analytics_actions::increment_analytics_for_user<UserWitness>(
analytics_author,
app,
&user_witness,
user_witness_config,
claim_author,
metric_author
);
};
}
post
Creates a Post
on the User
and returns the Post
address and timestamp that it was made. Aborts with EIncorrectCoinType
, EIncorrectCustomPayment
, or EIncorrectSuiPayment
if the payment was incorrect.
Copy
public fun post<CoinType> (app: &App, clock: &Clock, owned_user: &mut UserOwned, reward_weights_registry: &RewardWeightsRegistry, shared_user: &mut UserShared, user_fees: &UserFees, user_witness_config: &UserWitnessConfig, data: String, description: String, title: String, custom_payment: Coin<CoinType>, sui_payment: Coin<SUI>, ctx: &mut TxContext): (address, u64)
Show Implementation
Show Implementation
Copy
public fun post<CoinType> (
app: &App,
clock: &Clock,
owned_user: &mut UserOwned,
reward_weights_registry: &RewardWeightsRegistry,
shared_user: &mut UserShared,
user_fees: &UserFees,
user_witness_config: &UserWitnessConfig,
data: String,
description: String,
title: String,
custom_payment: Coin<CoinType>,
sui_payment: Coin<SUI>,
ctx: &mut TxContext
): (address, u64) {
let (
custom_payment,
sui_payment
) = user_fees::assert_post_from_user_payment<CoinType>(
user_fees,
custom_payment,
sui_payment
);
let app_address = object::id_address(app);
let mut posts = user_shared::take_posts(
shared_user,
app_address,
ctx
);
let user_witness = user_witness::create_witness();
let (
post_address,
self,
timestamp
) = post_actions::create_for_user<UserWitness>(
app,
clock,
&mut posts,
&user_witness,
user_witness_config,
data,
description,
title,
ctx
);
user_shared::return_posts(
shared_user,
app_address,
posts
);
fees::collect_payment<CoinType>(
custom_payment,
sui_payment
);
let has_rewards_enabled = apps::has_rewards_enabled(
app
);
if (has_rewards_enabled) {
let current_epoch = reward_registry::get_current(
reward_weights_registry
);
let reward_weights = reward_weights_registry.borrow_current();
let metric = utf8(METRIC_USER_TEXT_POST);
let claim = reward_weights.get_weight(metric);
let analytics = user_owned::borrow_or_create_analytics_mut(
owned_user,
user_witness_config,
app_address,
current_epoch,
ctx
);
let user_witness = user_witness::create_witness();
analytics_actions::increment_analytics_for_user<UserWitness>(
analytics,
app,
&user_witness,
user_witness_config,
claim,
metric
);
};
let user_id = shared_user.get_owner();
event::emit(UserPostCreated {
app_id: app_address,
created_at: timestamp,
created_by: self,
data,
description,
post_id: post_address,
title,
user_id
});
(post_address, timestamp)
}
remove_favorite_channel
Removes a Channel
from being a favorite within an App
.
Copy
public fun remove_favorite_channel<ChannelType: key> (app: &App, clock: &Clock, channel: &ChannelType, owned_user: &mut UserOwned, ctx: &mut TxContext)
Show Implementation
Show Implementation
Copy
public fun remove_favorite_channel<ChannelType: key> (
app: &App,
clock: &Clock,
channel: &ChannelType,
owned_user: &mut UserOwned,
ctx: &mut TxContext
) {
let app_address = object::id_address(app);
let timestamp = clock.timestamp_ms();
let (
message,
self,
favorited_channel_id,
_count
) = user_owned::remove_favorite_channel(
channel,
owned_user,
app_address,
timestamp,
ctx
);
event::emit(ChannelFavoritesUpdate {
app_id: app_address,
favorited_channel_id,
message,
updated_at: timestamp,
user_id: self
});
}
remove_favorite_post
Removes a Post
from being a favorite within an App
.
Copy
public fun remove_favorite_post(app: &App, clock: &Clock, owned_user: &mut UserOwned, post: &Post, ctx: &mut TxContext)
Show Implementation
Show Implementation
Copy
public fun remove_favorite_post(
app: &App,
clock: &Clock,
owned_user: &mut UserOwned,
post: &Post,
ctx: &mut TxContext
) {
let app_address = object::id_address(app);
let timestamp = clock.timestamp_ms();
let (
message,
self,
favorited_post_id,
_count
) = user_owned::remove_favorite_post(
post,
owned_user,
app_address,
timestamp,
ctx
);
event::emit(PostFavoritesUpdate {
app_id: app_address,
favorited_post_id,
message,
updated_at: timestamp,
user_id: self
});
}
remove_favorite_user
Removes a User
from being a favorite within an App
.
Copy
public fun remove_favorite_user(app: &App, clock: &Clock, owned_user: &mut UserOwned, user: &UserShared, ctx: &mut TxContext)
Show Implementation
Show Implementation
Copy
public fun remove_favorite_user(
app: &App,
clock: &Clock,
owned_user: &mut UserOwned,
user: &UserShared,
ctx: &mut TxContext
) {
let app_address = object::id_address(app);
let timestamp = clock.timestamp_ms();
let (
message,
self,
favorited_user_id,
_count
) = user_owned::remove_favorite_user(
owned_user,
user,
app_address,
timestamp,
ctx
);
event::emit(UserFavoritesUpdate {
app_id: app_address,
favorited_user_id,
message,
updated_at: timestamp,
user_id: self
});
}
remove_friend_request
Removes a friend request to the User
if they do not wish to connect to the requester. Aborts with ENotSelf
if the SharedUser
does not belong to the wallet address or if the request is not affiliated with the provided SharedUser
.
Copy
public fun remove_friend_request(app: &App, clock: &Clock, shared_user: &mut UserShared, removed_request: address, ctx: &mut TxContext)
Show Implementation
Show Implementation
Copy
public fun remove_friend_request(
app: &App,
clock: &Clock,
shared_user: &mut UserShared,
removed_request: address,
ctx: &mut TxContext
) {
let self = tx_context::sender(ctx);
let user_address = user_shared::get_owner(shared_user);
assert!(self == user_address || self == removed_request, ENotSelf);
let app_address = object::id_address(app);
let friend_requests = user_shared::borrow_friend_requests_mut(
shared_user,
app_address,
ctx
);
let timestamp = clock.timestamp_ms();
let (
membership_message,
membership_type,
_membership_count
) = membership::wallet_leave(
friend_requests,
removed_request,
timestamp
);
event::emit(UserFriendRequestUpdate {
account_type: membership_type,
app_id: app_address,
friended_user_id: removed_request,
message: membership_message,
updated_at: timestamp,
user_id: user_address
});
}
unfollow
Unfollow a User
. Aborts with EIncorrectCoinType
, EIncorrectCustomPayment
, or EIncorrectSuiPayment
if the payment was incorrect.
Copy
public fun unfollow<CoinType> (app: &App, clock: &Clock, shared_user: &mut UserShared, user_fees: &UserFees, custom_payment: Coin<CoinType>, sui_payment: Coin<SUI>, ctx: &mut TxContext)
Show Implementation
Show Implementation
Copy
public fun unfollow<CoinType> (
app: &App,
clock: &Clock,
shared_user: &mut UserShared,
user_fees: &UserFees,
custom_payment: Coin<CoinType>,
sui_payment: Coin<SUI>,
ctx: &mut TxContext
) {
let (
custom_payment,
sui_payment
) = user_fees::assert_unfollow_user_payment<CoinType>(
user_fees,
custom_payment,
sui_payment
);
let self = tx_context::sender(ctx);
let user_address = user_shared::get_owner(shared_user);
let app_address = object::id_address(app);
let follows = user_shared::borrow_follows_mut(
shared_user,
app_address,
ctx
);
let timestamp = clock.timestamp_ms();
let (
membership_message,
membership_type,
_membership_count
) = membership::wallet_leave(
follows,
self,
timestamp
);
fees::collect_payment<CoinType>(
custom_payment,
sui_payment
);
event::emit(UserFollowsUpdate {
account_type: membership_type,
app_id: app_address,
followed_user_id: user_address,
message: membership_message,
updated_at: timestamp,
user_id: self
});
}
unfriend_user
Removes friendship between User
s. Aborts with ENotSelf
if the wallet does not own the OwnedUser
or SharedUser
, or EIncorrectCoinType
, EIncorrectCustomPayment
, or EIncorrectSuiPayment
if the payment was incorrect.
Copy
public fun unfriend_user<CoinType> (app: &App, clock: &Clock, user_fees: &UserFees, user_friend: &mut UserShared, user_shared: &mut UserShared, custom_payment: Coin<CoinType>, sui_payment: Coin<SUI>, ctx: &mut TxContext)
Show Implementation
Show Implementation
Copy
public fun unfriend_user<CoinType> (
app: &App,
clock: &Clock,
user_fees: &UserFees,
user_friend: &mut UserShared,
user_shared: &mut UserShared,
custom_payment: Coin<CoinType>,
sui_payment: Coin<SUI>,
ctx: &mut TxContext
) {
let (
custom_payment,
sui_payment
) = user_fees::assert_unfriend_user_payment<CoinType>(
user_fees,
custom_payment,
sui_payment
);
let friend_address = user_shared::get_owner(user_friend);
let user_address = user_shared::get_owner(user_shared);
let self = tx_context::sender(ctx);
assert!(self == friend_address || self == user_address, ENotSelf);
let app_address = object::id_address(app);
let timestamp = clock.timestamp_ms();
let friends = user_shared::borrow_friends_mut(
user_shared,
app_address,
ctx
);
membership::wallet_leave(
friends,
friend_address,
timestamp
);
let friends_friends = user_shared::borrow_friends_mut(
user_friend,
app_address,
ctx
);
let (
membership_message,
membership_type,
_membership_count
) = membership::wallet_leave(
friends_friends,
user_address,
timestamp
);
fees::collect_payment<CoinType>(
custom_payment,
sui_payment
);
event::emit(UserFriendUpdate {
account_type: membership_type,
app_id: app_address,
friended_user_id: friend_address,
message: membership_message,
updated_at: timestamp,
user_id: user_address
});
}
update
Updates metadata on the OwnedUser
. Aborts with EUserNameMismatch
if attempting to change the name, or EIncorrectCoinType
, EIncorrectCustomPayment
, or EIncorrectSuiPayment
if the payment was incorrect.
Copy
public fun update<CoinType> (clock: &Clock, user_registry: &UserRegistry, user_fees: &UserFees, owned_user: &mut UserOwned, avatar: String, banner: String, description: String, name: String, custom_payment: Coin<CoinType>, sui_payment: Coin<SUI>, ctx: &mut TxContext)
Show Implementation
Show Implementation
Copy
public fun update<CoinType> (
clock: &Clock,
user_registry: &UserRegistry,
user_fees: &UserFees,
owned_user: &mut UserOwned,
avatar: String,
banner: String,
description: String,
name: String,
custom_payment: Coin<CoinType>,
sui_payment: Coin<SUI>,
ctx: &mut TxContext
) {
let (
custom_payment,
sui_payment
) = user_fees::assert_update_user_payment<CoinType>(
user_fees,
custom_payment,
sui_payment
);
let self = tx_context::sender(ctx);
let owned_user_key = user_registry::get_key_from_owner_address(
user_registry,
self
);
let lowercase_user_name = string_helpers::to_lowercase(
&name
);
assert!(lowercase_user_name == owned_user_key, EUserNameMismatch);
let updated_at = clock.timestamp_ms();
user_owned::update(
owned_user,
avatar,
banner,
description,
name,
updated_at
);
fees::collect_payment<CoinType>(
custom_payment,
sui_payment
);
event::emit(UserUpdated {
avatar,
banner,
user_id: self,
user_name: name,
description,
updated_at
});
}