sui_move_natives_v0/
transfer.rs1use super::object_runtime::{ObjectRuntime, TransferResult};
5use crate::NativesCostTable;
6use move_binary_format::errors::{PartialVMError, PartialVMResult};
7use move_core_types::{
8 account_address::AccountAddress, gas_algebra::InternalGas, language_storage::TypeTag,
9 vm_status::StatusCode,
10};
11use move_vm_runtime::{native_charge_gas_early_exit, native_functions::NativeContext};
12use move_vm_types::{
13 loaded_data::runtime_types::Type, natives::function::NativeResult, pop_arg, values::Value,
14};
15use smallvec::smallvec;
16use std::collections::VecDeque;
17use sui_types::{base_types::SequenceNumber, object::Owner};
18
19const E_SHARED_NON_NEW_OBJECT: u64 = 0;
20
21#[derive(Clone, Debug)]
22pub struct TransferInternalCostParams {
23 pub transfer_transfer_internal_cost_base: InternalGas,
24}
25pub fn transfer_internal(
31 context: &mut NativeContext,
32 mut ty_args: Vec<Type>,
33 mut args: VecDeque<Value>,
34) -> PartialVMResult<NativeResult> {
35 debug_assert!(ty_args.len() == 1);
36 debug_assert!(args.len() == 2);
37
38 let transfer_transfer_internal_cost_params = context
39 .extensions_mut()
40 .get::<NativesCostTable>()
41 .transfer_transfer_internal_cost_params
42 .clone();
43
44 native_charge_gas_early_exit!(
45 context,
46 transfer_transfer_internal_cost_params.transfer_transfer_internal_cost_base
47 );
48
49 let ty = ty_args.pop().unwrap();
50 let recipient = pop_arg!(args, AccountAddress);
51 let obj = args.pop_back().unwrap();
52 let owner = Owner::AddressOwner(recipient.into());
53 object_runtime_transfer(context, owner, ty, obj)?;
54
55 Ok(NativeResult::ok(context.gas_used(), smallvec![]))
56}
57
58#[derive(Clone, Debug)]
59pub struct TransferFreezeObjectCostParams {
60 pub transfer_freeze_object_cost_base: InternalGas,
61}
62pub fn freeze_object(
68 context: &mut NativeContext,
69 mut ty_args: Vec<Type>,
70 mut args: VecDeque<Value>,
71) -> PartialVMResult<NativeResult> {
72 debug_assert!(ty_args.len() == 1);
73 debug_assert!(args.len() == 1);
74
75 let transfer_freeze_object_cost_params = context
76 .extensions_mut()
77 .get::<NativesCostTable>()
78 .transfer_freeze_object_cost_params
79 .clone();
80
81 native_charge_gas_early_exit!(
82 context,
83 transfer_freeze_object_cost_params.transfer_freeze_object_cost_base
84 );
85
86 let ty = ty_args.pop().unwrap();
87 let obj = args.pop_back().unwrap();
88 object_runtime_transfer(context, Owner::Immutable, ty, obj)?;
89
90 Ok(NativeResult::ok(context.gas_used(), smallvec![]))
91}
92
93#[derive(Clone, Debug)]
94pub struct TransferShareObjectCostParams {
95 pub transfer_share_object_cost_base: InternalGas,
96}
97pub fn share_object(
103 context: &mut NativeContext,
104 mut ty_args: Vec<Type>,
105 mut args: VecDeque<Value>,
106) -> PartialVMResult<NativeResult> {
107 debug_assert!(ty_args.len() == 1);
108 debug_assert!(args.len() == 1);
109
110 let transfer_share_object_cost_params = context
111 .extensions_mut()
112 .get::<NativesCostTable>()
113 .transfer_share_object_cost_params
114 .clone();
115
116 native_charge_gas_early_exit!(
117 context,
118 transfer_share_object_cost_params.transfer_share_object_cost_base
119 );
120
121 let ty = ty_args.pop().unwrap();
122 let obj = args.pop_back().unwrap();
123 let transfer_result = object_runtime_transfer(
124 context,
125 Owner::Shared {
128 initial_shared_version: SequenceNumber::new(),
129 },
130 ty,
131 obj,
132 )?;
133 let cost = context.gas_used();
134 Ok(match transfer_result {
135 TransferResult::New | TransferResult::SameOwner => NativeResult::ok(cost, smallvec![]),
140 TransferResult::OwnerChanged => NativeResult::err(cost, E_SHARED_NON_NEW_OBJECT),
141 })
142}
143
144fn object_runtime_transfer(
145 context: &mut NativeContext,
146 owner: Owner,
147 ty: Type,
148 obj: Value,
149) -> PartialVMResult<TransferResult> {
150 if !matches!(context.type_to_type_tag(&ty)?, TypeTag::Struct(_)) {
151 return Err(
152 PartialVMError::new(StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR)
153 .with_message("Sui verifier guarantees this is a struct".to_string()),
154 );
155 }
156
157 let obj_runtime: &mut ObjectRuntime = context.extensions_mut().get_mut();
158 obj_runtime.transfer(owner, ty, obj)
159}