Unit ID
v0d0vhEyxgiQctS0kdHOQIVqdWjC4+sqgfEBW7R9LOY=
Received
29.08.2025 15:05:01
Confirmation delay (full node)
8 minutes 57 seconds
Confirmation delay (light node)
10 minutes 53 seconds
Messages
Definition
Definition: [ "autonomous agent", { "doc_url": "https://friends.obyte.org/friends.json", "getters": "{ /* nonce: 645324 */ $matching_timeout = 600; $year = 31536000; // 365 * 24 * 3600; $day = 86400; // 24 * 3600; $ghost_admin = 'WMFLGI2GLAB2MDF2KQAH37VNRRMK7A5N'; $get_deposited_supply = () => var['total_locked']; $get_variables = () => { var['variables'] OTHERWISE { rewards_aa: 'TQNNRLADHTUPTJ7KEWCYS5XRSILFEKBG', messaging_attestors: 'WMFLGI2GLAB2MDF2KQAH37VNRRMK7A5N:JBW7HT5CRBSF7J7RD26AYLQG6GZDPFPS:5KM36CFPBD2QJLVD65PHZG34WEM4RPY2', real_name_attestors: 'FSJVTTCHUIWALPN7Y6GYEKZACXMEXIG3', referrer_deposit_reward_share: 0.01, followup_reward_share: 0.1, min_balance_instead_of_real_name: 1e8, } }; $get_followup_reward_days = () => { '60': true, // +2 months '150': true, // +3 months '270': true, // +4 months '450': true, // +6 months '720': true, // +9 months '1080': true, // +12 months '1620': true, // +18 months }; $get_ceiling_price = () => { $constants = var['constants']; 2^((timestamp - $constants.launch_ts)/$year) }; $is_eligible_for_infriends = ($address) => { $get_variables().rewards_aa#5.$is_eligible_for_infriends($address, var['user_'||$address], $get_ceiling_price(), $get_followup_reward_days()) }; $get_rewards_description = ($rewards, $address) => { $res = { desc: "liquid " || $rewards.user1.liquid/1e9 || " FRD, locked " || $rewards.user1.locked/1e9 || " FRD" }; if ($rewards.user1.new_user_reward) $res.desc = $res.desc || ", including new user reward " || $rewards.user1.new_user_reward/1e9 || " FRD"; if ($rewards.user1.referred_user_reward) // someone referred me and this is my first friendship $res.desc = $res.desc || ", including referred user reward " || $rewards.user1.referred_user_reward/1e9 || " FRD"; if ($rewards.referrers[$address]) // referrer reward is not included in .locked, that's why "plus" $res.desc = $res.desc || ", plus referrer reward " || $rewards.referrers[$address]/1e9 || " FRD"; $res.desc }; $get_deposit_asset_exchange_rates_on_aa = ($deposit_asset, $aa) => { $params = definition[$aa][1].params; $bX = $params.x_asset == $deposit_asset AND $params.y_asset == 'base'; $bY = $params.x_asset == 'base' AND $params.y_asset == $deposit_asset; require($bX OR $bY, "deposit asset must be one of the pool's assets and the other asset must be GBYTE"); $recent = var[$aa]['recent']; require($recent AND $recent.current AND $recent.prev, "no recent state of the pool"); $pmax = max($recent.current.pmax, $recent.prev.pmax); $pmin = min($recent.current.pmin, $recent.prev.pmin); require($pmin > 0 AND $pmax > 0, "pmin and pmax must be > 0"); {min: ($bX ? $pmin : 1/$pmax) * 0.9, max: ($bX ? $pmax : 1/$pmin) * 1.1} }; $get_deposit_asset_exchange_rates = ($deposit_asset) => { $aa = var['deposit_asset_'||$deposit_asset]; require($aa, "unknown deposit asset"); $get_deposit_asset_exchange_rates_on_aa($deposit_asset, $aa) }; }", "init": "{ $followup_claim_term = 10; // days $constants = var['constants'] OTHERWISE {}; // FRD token $asset = $constants.asset; $governance_aa = $constants.governance_aa; $variables = $get_variables(); $ceiling_price = 2^((timestamp - $constants.launch_ts)/$year); if ($asset) $received_amount = trigger.output[[asset=$asset]]; $received_bytes_amount = max(trigger.output[[asset=base]] - 10000, 0); $deposit_asset = trigger.data.deposit_asset; if ($deposit_asset AND trigger.address != $governance_aa){ $received_deposit_asset_amount = trigger.output[[asset=$deposit_asset]]; $exchange_rates = $get_deposit_asset_exchange_rates($deposit_asset); } $governance_base_aa = 'T32TTXO7TCPN3U4S2YX6K6KTE2CY54WM'; }", "messages": { "cases": [ { "if": "{ trigger.data.define AND !$asset }", "messages": [ { "app": "asset", "payload": { "is_private": false, "is_transferrable": true, "auto_destroy": false, "fixed_denominations": false, "issued_by_definer_only": true, "cosigned_by_definer": false, "spender_attested": false } }, { "app": "definition", "payload": { "definition": [ "autonomous agent", { "base_aa": "{$governance_base_aa}", "params": { "friend_aa": "{this_address}" } } ] } }, { "app": "state", "state": "{ $constants.asset = response_unit; $constants.governance_aa = unit[response_unit].messages[[.app='definition']].payload.address; $constants.launch_ts = timestamp; var['constants'] = $constants; response['asset'] = response_unit; }" } ] }, { "if": "{ trigger.address == $governance_aa AND trigger.data.name }", "init": "{ $name = trigger.data.name; $value = trigger.data.value; }", "messages": [ { "app": "state", "state": "{ if ($name == 'deposit_asset'){ require(length(trigger.data.deposit_asset) == 44, "invalid deposit asset"); var['deposit_asset_'||trigger.data.deposit_asset] = $value; } else { $variables[$name] = $value; var['variables'] = $variables; } }" } ] }, { "if": "{ $ghost_name = trigger.data.ghost_name; trigger.address == $ghost_admin AND trigger.data.add_ghost AND $ghost_name }", "init": "{ require(!is_valid_address($ghost_name), "ghost_name must not be a valid address"); require(!var['user_'||$ghost_name], "this ghost already exists"); }", "messages": [ { "app": "state", "state": "{ var['user_'||$ghost_name] = { balances: {frd: 100e9}, // not included in total_locked unlock_date: false, reg_ts: timestamp, ghost: true, last_date: timestamp_to_string(timestamp, 'date'), // to make sure nobody gets new user rewards }; response['message'] = "Added the new ghost account"; }" } ] }, { "if": "{ ($received_amount OR $received_bytes_amount OR $received_deposit_asset_amount OR trigger.data.term) AND trigger.data.deposit }", "init": "{ $username = attestation[[attestors=$variables.messaging_attestors, address=trigger.address, ifnone=false]].username; require($username, "your address must be attested on a messaging service"); $messagingUserId = attestation[[attestors=$variables.messaging_attestors, address=trigger.address, ifnone=false]].userId OTHERWISE $username; $m_addr = var['m_address_'||$messagingUserId]; require(!$m_addr OR $m_addr == trigger.address, "only one account per messaging user is allowed"); require(!is_aa(trigger.address), "AAs not allowed to participate"); $user = var['user_'||trigger.address] OTHERWISE {balances: {}, unlock_date: false, reg_ts: timestamp, current_ghost_num: 1}; $bNewUser = !$user.unlock_date; $total_balance = $user.balances.frd + $received_amount + ($user.balances.base + $received_bytes_amount + ($deposit_asset ? ($user.balances[$deposit_asset] + $received_deposit_asset_amount) * $exchange_rates.min : 0))/$ceiling_price; $bBigDeposit = $total_balance >= $variables.min_balance_instead_of_real_name; if (!$bBigDeposit) $user_id = attestation[[attestors=$variables.real_name_attestors, address=trigger.address, ifnone=false]].user_id; require($user_id OR $bBigDeposit, "your address must be real-name attested or you should deposit at least "||($variables.min_balance_instead_of_real_name/1e9)||" FRD"); if ($user_id){ $addr = var['rn_address_'||$user_id]; require(!$addr OR $addr == trigger.address, "only one account per real user is allowed"); } if (exists(trigger.data.ref)){ require(is_valid_address(trigger.data.ref), "referrer address not valid"); require(var['user_'||trigger.data.ref], "referrer doesn't exist"); if ($bNewUser){ $user.ref = trigger.data.ref; if (trigger.data.no_referrer_deposit_reward) $user.no_referrer_deposit_reward = true; } else response['ref_ignored'] = "Referrer can be set only with the first deposit"; } if ($user.ref){ $referrer = var['user_'||$user.ref]; $min_unlock_date = timestamp_to_string(timestamp + $day, 'date'); $bReferrerEligible = $referrer.unlock_date >= $min_unlock_date; if (!$bReferrerEligible) response['warning'] = "Referrer's unlock date is less than 1 day in the future and they are not eligible to receive the deposit reward"; } $term = trigger.data.term OTHERWISE 1; require($term >= 1, "minimum term is 1 day"); $new_unlock_date = timestamp_to_string(timestamp + $term * 24 * 3600, 'date'); if (!$bNewUser) require($new_unlock_date >= $user.unlock_date, "new unlock date must not go back"); }", "messages": [ { "if": "{$user.ref AND !$user.no_referrer_deposit_reward AND $bReferrerEligible}", "app": "payment", "payload": { "asset": "{$asset}", "outputs": [ { "address": "{$user.ref}", "amount": "{floor(($received_amount + ($received_bytes_amount + $received_deposit_asset_amount * $exchange_rates.min)/$ceiling_price) * $variables.referrer_deposit_reward_share)}" } ] } }, { "app": "state", "state": "{ $user.balances.frd = $user.balances.frd + $received_amount; $user.balances.base = $user.balances.base + $received_bytes_amount; if ($deposit_asset){ $user.balances[$deposit_asset] = $user.balances[$deposit_asset] + $received_deposit_asset_amount; require(length($user.balances) <= 3, "maximum 3 deposit assets allowed, remove some old ones before adding new assets"); } $user.unlock_date = $new_unlock_date; var['user_'||trigger.address] = $user; if ($bNewUser AND $user_id) var['rn_address_'||$user_id] = trigger.address; var['m_address_'||$messagingUserId] = trigger.address; var['total_locked'] += $received_amount; var['total_locked_bytes'] += $received_bytes_amount; if ($received_amount OR $received_bytes_amount OR $received_deposit_asset_amount) response['message'] = "Deposited"; response['unlock_date'] = $new_unlock_date; response['event'] = json_stringify({type: 'deposit', owner: trigger.address, amount: $received_amount, bytes_amount: $received_bytes_amount, asset_amount: $received_deposit_asset_amount, deposit_asset: $deposit_asset}); }" } ] }, { "if": "{ $friend = trigger.data.friend; $days = trigger.data.days; (trigger.data.connect OR trigger.data.followup AND $days) AND $friend }", "init": "{ $today = timestamp_to_string(timestamp, 'date'); $yesterday = timestamp_to_string(timestamp - 24 * 3600, 'date'); $min_unlock_date = timestamp_to_string(timestamp + $day, 'date'); $user1 = var['user_'||trigger.address]; require($user1, "please make a deposit first"); require($user1.unlock_date >= $min_unlock_date, "your unlock date must be "||$min_unlock_date||" or later"); require($friend != trigger.address, "you cannot become friends with yourself"); $user2 = var['user_'||$friend]; require($user2, "your friend must make a deposit first"); if ($user2.ghost){ $required_streak = ($user1.current_ghost_num + 1)^2; require($user1.current_streak >= $required_streak, "you need a "||$required_streak||"-day streak to befriend the next ghost, your current streak length is only "||$user1.current_streak); } else require($user2.unlock_date >= $min_unlock_date, "your friend's unlock date must be "||$min_unlock_date||" or later"); if (trigger.data.connect){ require(!$days, "don't send days for the initial connect"); require(!var['friend_'||trigger.address||'_'||$today], "you already made a friend today, try tomorrow"); if (!$user2.ghost){ require(!var['friend_'||$friend||'_'||$today], "your friend already made a friend today, try tomorrow"); $eligibility = $variables.rewards_aa#5.$are_eligible(trigger.address, $friend, $user1, $user2, $ceiling_price, $get_followup_reward_days()); require($eligibility.user1_eligible, "you are not eligible to make in-friends today"); require($eligibility.user2_eligible, "your friend is not eligible to make in-friends today"); } } else{ require($get_followup_reward_days()[$days], "no such follow-up"); } $isAB = trigger.address < $friend AND !$user2.ghost; // alphabetically sorted, or the ghost comes first $pair = $isAB ? trigger.address||'_'||$friend : $friend||'_'||trigger.address; $key = 'friendship_'||$pair; $friendship = var[$key] OTHERWISE {followup_reward_share: $variables.followup_reward_share}; // the share is fixed for all future followups if (!trigger.data.connect){ // followup require($friendship.initial.accept_ts, "you are not friends"); $elapsed_days = (timestamp - $friendship.initial.accept_ts)/24/3600; require($elapsed_days >= +$days, "too early"); require($elapsed_days <= $days + $followup_claim_term, "too late"); } $rewards = $variables.rewards_aa#20.$get_rewards(trigger.address, $friend, $user1, $user2, $ceiling_price, this_address, !trigger.data.connect); if (!trigger.data.connect){ // followup, multiply all rewards by followup_reward_share $rewards.user1.locked = floor($rewards.user1.locked * $friendship.followup_reward_share); $rewards.user1.liquid = floor($rewards.user1.liquid * $friendship.followup_reward_share); $rewards.user2.locked = floor($rewards.user2.locked * $friendship.followup_reward_share); $rewards.user2.liquid = floor($rewards.user2.liquid * $friendship.followup_reward_share); } $rewards_description = $get_rewards_description($rewards, trigger.address); $index = trigger.data.connect ? 'initial' : 'followup_'||$days; if ($user2.ghost) $friendship[$index] = {first: $friend, ts: timestamp}; if (!$friendship[$index]){ $friendship[$index] = {first: trigger.address, ts: timestamp}; response['message'] = "Registered your request. Your friend must send their request within 10 minutes, otherwise you both will have to start over. Expected rewards: "||$rewards_description||"."; } else{ require(!$friendship[$index].accept_ts, trigger.data.connect ? "you are already friends" : "already paid"); if ($friendship[$index].first == trigger.address){ $friendship[$index].ts = timestamp; response['message'] = "Refreshed your request. Your friend must send their request within 10 minutes, otherwise you both will have to start over. Expected rewards: "||$rewards_description||"."; } else{ $bInTime = timestamp < $friendship[$index].ts + $matching_timeout; if (!$bInTime){ $friendship[$index].ts = timestamp; $friendship[$index].first = trigger.address; response['message'] = "Unfortunately, you are too late. Your friend has to send their request again within 10 minutes, otherwise you both will have to start over. Expected rewards: "||$rewards_description||"."; } else{ // pay rewards $friendship[$index].accept_ts = timestamp; $user1.balances.frd = $user1.balances.frd + $rewards.user1.locked; $user2.balances.frd = $user2.balances.frd + $rewards.user2.locked; $user1.locked_rewards = $user1.locked_rewards + $rewards.user1.locked; $user2.locked_rewards = $user2.locked_rewards + $rewards.user2.locked; $user1.liquid_rewards = $user1.liquid_rewards + $rewards.user1.liquid; $user2.liquid_rewards = $user2.liquid_rewards + $rewards.user2.liquid; if (trigger.data.connect){ $bContinueStreak1 = $user1.last_date AND $user1.last_date == $yesterday; $bContinueStreak2 = $user2.last_date AND $user2.last_date == $yesterday; $user1.total_streak = $bContinueStreak1 ? $user1.total_streak + 1 : 1; $user2.total_streak = $bContinueStreak2 ? $user2.total_streak + 1 : 1; $user1.current_streak = $bContinueStreak1 ? $user1.current_streak + 1 : 1; $user2.current_streak = $bContinueStreak2 ? $user2.current_streak + 1 : 1; if ($user2.ghost){ $user1.current_streak = 0; // reset the streak $user1.current_ghost_num = $user1.current_ghost_num + 1; } $user1.last_date = $today; $user2.last_date = $today; if ($rewards.user1.is_new) // record a new user reward for the opposite user $user2.new_user_rewards = $user2.new_user_rewards + $rewards.user2.new_user_reward; if ($rewards.user2.is_new) // record a new user reward for the opposite user $user1.new_user_rewards = $user1.new_user_rewards + $rewards.user1.new_user_reward; } response['message'] = (trigger.data.connect ? "Now you've become friends and you've received the following rewards: " : "You've received followup rewards: ") || $rewards_description || "."; response['events'] = json_stringify({type: 'rewards', user1: trigger.address, user2: $friend, rewards: $rewards, followup: !trigger.data.connect, days: $days, ghost: $user2.ghost}); } } } }", "messages": [ { "if": "{$friendship[$index].accept_ts}", "app": "payment", "payload": { "asset": "{$asset}", "outputs": [ { "address": "{trigger.address}", "amount": "{$rewards.user1.liquid}" }, { "address": "{$friend}", "amount": "{$rewards.user2.liquid}", "if": "{!$user2.ghost}" } ] } }, { "app": "state", "state": "{ if ($friendship[$index].accept_ts){ var['user_'||trigger.address] = $user1; var['user_'||$friend] = $user2; if (trigger.data.connect){ var['friend_'||trigger.address||'_'||$today] = $friend; var['friend_'||$friend||'_'||$today] = trigger.address; var['total_new_user_rewards'] += $rewards.user1.new_user_reward + $rewards.user2.new_user_reward; if ($rewards.referrers){ $referrer_totals = {total: 0}; foreach($rewards.referrers, 2, ($addr, $reward) => { $user = var['user_'||$addr]; // it can be one of the connecting users whose var has already been updated $user.balances.frd = $user.balances.frd + $reward; $user.referral_rewards = $user.referral_rewards + $reward; $user.locked_rewards = $user.locked_rewards + $reward; var['user_'||$addr] = $user; $referrer_totals.total = $referrer_totals.total + $reward; }); var['total_referral_rewards'] += 2 * $referrer_totals.total; // the same reward goes to the referred user } } // users' locked rewards include the referred rewards but not the referrer rewards var['total_locked'] += $rewards.user1.locked + ($user2.ghost ? 0 : $rewards.user2.locked) + $referrer_totals.total; // replace user1 and user2 with alphabetically sorted a and b $rewards.a = $isAB ? $rewards.user1 : $rewards.user2; $rewards.b = $isAB ? $rewards.user2 : $rewards.user1; delete($rewards, 'user1'); delete($rewards, 'user2'); $friendship[$index].rewards = $rewards; delete($friendship[$index], 'first'); // save storage space to make sure we don't exceed 1024 bytes delete($friendship[$index], 'ts'); } var[$key] = $friendship; }" } ] }, { "if": "{trigger.data.withdraw}", "init": "{ $user = var['user_'||trigger.address]; require($user, "you are not a user"); require(timestamp_to_string(timestamp, 'date') >= $user.unlock_date, "your balance unlocks on "||$user.unlock_date); require($user.balances.frd > 0 OR $user.balances.base > 0 OR $deposit_asset AND $user.balances[$deposit_asset] > 0, "you have no balance"); }", "messages": [ { "app": "payment", "payload": { "asset": "base", "outputs": [ { "address": "{trigger.address}", "amount": "{$user.balances.base}" }, { "address": "{$governance_aa}", "amount": 1000 } ] } }, { "app": "payment", "payload": { "asset": "{$asset}", "outputs": [ { "address": "{trigger.address}", "amount": "{$user.balances.frd}" } ] } }, { "if": "{$deposit_asset}", "app": "payment", "payload": { "asset": "{$deposit_asset}", "outputs": [ { "address": "{trigger.address}", "amount": "{$user.balances[$deposit_asset]}" } ] } }, { "app": "data", "payload": { "update_user_balance": 1, "address": "{trigger.address}" } }, { "app": "state", "state": "{ response['message'] = 'Withdrawn'; response['event'] = json_stringify({type: 'withdrawal', address: trigger.address, balance: $user.balances.frd, bytes_balance: $user.balances.base, deposit_asset_balance: $deposit_asset ? $user.balances[$deposit_asset] : 0, deposit_asset: $deposit_asset}); var['total_locked'] -= $user.balances.frd; var['total_locked_bytes'] -= $user.balances.base; $user.balances.frd = 0; $user.balances.base = 0; if ($deposit_asset) $user.balances[$deposit_asset] = 0; var['user_'||trigger.address] = $user; }" } ] }, { "if": "{trigger.data.replace AND ($received_amount OR $received_bytes_amount OR $received_deposit_asset_amount)}", "init": "{ require(($received_amount?1:0) + ($received_bytes_amount?1:0) + ($received_deposit_asset_amount?1:0) == 1, "don't send more than one token"); $user = var['user_'||trigger.address]; require($user, "you are not a user"); $out_amounts = {base: 0, frd: 0, deposit_asset: 0}; if ($deposit_asset){ if ($received_deposit_asset_amount){ $out_amounts.frd = floor($received_deposit_asset_amount * $exchange_rates.min / $ceiling_price); } else if ($received_amount){ $out_amounts.deposit_asset = floor($received_amount * $ceiling_price / $exchange_rates.max); require($user.balances[$deposit_asset] >= $out_amounts.deposit_asset, "not enough deposit asset locked"); } else bounce("bytes are not swapped for deposit assets"); } else if ($received_amount){ $out_amounts.base = floor($received_amount * $ceiling_price); require($user.balances.base >= $out_amounts.base, "not enough bytes locked"); } else if ($received_bytes_amount){ // received bytes $out_amounts.frd = floor($received_bytes_amount / $ceiling_price); } if ($out_amounts.frd) require($user.balances.frd >= $out_amounts.frd, "not enough FRD locked"); }", "messages": [ { "app": "payment", "payload": { "asset": "base", "outputs": [ { "address": "{trigger.address}", "amount": "{$out_amounts.base}" } ] } }, { "app": "payment", "payload": { "asset": "{$asset}", "outputs": [ { "address": "{trigger.address}", "amount": "{$out_amounts.frd}" } ] } }, { "if": "{$out_amounts.deposit_asset}", "app": "payment", "payload": { "asset": "{$deposit_asset}", "outputs": [ { "address": "{trigger.address}", "amount": "{$out_amounts.deposit_asset}" } ] } }, { "app": "state", "state": "{ response['message'] = 'Replaced'; response['event'] = json_stringify({type: 'replace', address: trigger.address, received_amount: $received_amount, received_bytes_amount: $received_bytes_amount, received_deposit_asset_amount: $received_deposit_asset_amount, out_amount: $out_amounts.frd, out_bytes_amount: $out_amounts.base, out_deposit_asset_amount: $out_amounts.deposit_asset, deposit_asset: $deposit_asset}); var['total_locked'] += $received_amount - $out_amounts.frd; var['total_locked_bytes'] += $received_bytes_amount - $out_amounts.base; $user.balances.frd = $user.balances.frd + $received_amount - $out_amounts.frd; $user.balances.base = $user.balances.base + $received_bytes_amount - $out_amounts.base; if ($deposit_asset){ $user.balances[$deposit_asset] = $user.balances[$deposit_asset] + $received_deposit_asset_amount - $out_amounts.deposit_asset; if ($user.balances[$deposit_asset] == 0) delete($user.balances, $deposit_asset); require(length($user.balances) <= 3, "maximum 3 deposit assets allowed, remove some old ones before adding new assets"); } var['user_'||trigger.address] = $user; }" } ] } ] } } ]
Technical information
Fees:
23,844 bytes
(406 headers, 23438 payload)
TPS fee:
0 bytes
Actual TPS fee:
0 bytes
Oversize fee:
71,352 bytes
Level:3769375
Witnessed level:3769367
Main chain index:3742511
Latest included mc index:3742510
Status:stable/confirmed/final