1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
// Re-export
pub use radix_engine_interface::types::{Buffer, BufferId, Slice};

use sbor::rust::vec::Vec;

pub fn copy_buffer(buffer: Buffer) -> Vec<u8> {
    let len = buffer.len() as usize;
    let mut vec = Vec::<u8>::with_capacity(len);
    unsafe {
        buffer::buffer_consume(buffer.id(), vec.as_mut_ptr());
        vec.set_len(len);
    };
    vec
}

pub fn forget_vec(vec: Vec<u8>) -> Slice {
    let ptr = vec.as_ptr() as usize;
    let len = vec.len();
    assert!(ptr <= 0xffffffff && len <= 0xffffffff);

    // Note that the memory used by the Vec is forever leaked.
    // However, it's not an issue since the wasm instance will be destroyed after engine
    // consuming the data.
    sbor::rust::mem::forget(vec);

    Slice::new(ptr as u32, len as u32)
}

/// Api make blueprint function calls
pub mod blueprint {
    pub use radix_engine_interface::types::{Buffer, BufferId, Slice};

    super::wasm_extern_c! {
        /// Invokes a blueprint function
        pub fn blueprint_call(
            package_address_ptr: *const u8,
            package_address_len: usize,
            blueprint_name_ptr: *const u8,
            blueprint_name_len: usize,
            ident_ptr: *const u8,
            ident_len: usize,
            args_ptr: *const u8,
            args_len: usize,
        ) -> Buffer;
    }
}

/// API to allocate/reserve global address
pub mod addr {
    pub use radix_engine_interface::types::{Buffer, BufferId, Slice};

    super::wasm_extern_c! {
        /// Reserves a global address for a given blueprint
        pub fn address_allocate(
            package_address_ptr: *const u8,
            package_address_len: usize,
            blueprint_name_ptr: *const u8,
            blueprint_name_len: usize,
        ) -> Buffer;

        /// Get the address associated with an address reservation
        pub fn address_get_reservation_address(
            address_id_ptr: *const u8,
            address_id_len: usize,
        ) -> Buffer;
    }
}

/// API to manipulate or get information about visible objects
pub mod object {
    pub use radix_engine_interface::types::{Buffer, BufferId, Slice};

    super::wasm_extern_c! {
        /// Creates a new object of a given blueprint defined in the same
        /// package as the current actor
        pub fn object_new(
            blueprint_name_ptr: *const u8,
            blueprint_name_len: usize,
            obj_fields_ptr: *const u8,
            obj_fields_len: usize,
        ) -> Buffer;

        /// Globalizes an object with given modules
        pub fn object_globalize(
            obj_id_ptr: *const u8,
            obj_id_len: usize,
            modules_ptr: *const u8,
            modules_len: usize,
            address_id_ptr: *const u8,
            address_id_len: usize,
        ) -> Buffer;

        /// Check if an object is an instance of blueprint
        pub fn object_instance_of(
            obj_id_ptr: *const u8,
            obj_id_len: usize,
            package_address_ptr: *const u8,
            package_address_len: usize,
            blueprint_name_ptr: *const u8,
            blueprint_name_len: usize,
        ) -> u32;

         /// Get the Blueprint Identifier of a given object
         pub fn object_get_blueprint_id(
            obj_id_ptr: *const u8,
            obj_id_len: usize,
        ) -> Buffer;

        /// Get the address of the outer object of a given object
        pub fn object_get_outer_object(obj_id_ptr: *const u8, obj_id_len: usize) -> Buffer;

        /// Invokes a method on a visible object
        pub fn object_call(
            obj_id_ptr: *const u8,
            obj_id_len: usize,
            ident_ptr: *const u8,
            ident_len: usize,
            args_ptr: *const u8,
            args_len: usize,
        ) -> Buffer;

        /// Invokes a direct method on a visible object
        pub fn object_call_direct(
            obj_id_ptr: *const u8,
            obj_id_len: usize,
            ident_ptr: *const u8,
            ident_len: usize,
            args_ptr: *const u8,
            args_len: usize,
        ) -> Buffer;

        /// Invokes a module method on a visible object
        pub fn object_call_module(
            obj_id_ptr: *const u8,
            obj_id_len: usize,
            module_id: u32,
            ident_ptr: *const u8,
            ident_len: usize,
            args_ptr: *const u8,
            args_len: usize,
        ) -> Buffer;
    }
}

/// API to manipulate or get information about the current actor
pub mod actor {
    use radix_engine_interface::api::field_api::FieldHandle;
    use radix_engine_interface::api::{ActorRefHandle, ActorStateHandle};
    pub use radix_engine_interface::types::{Buffer, BufferId, Slice};

    super::wasm_extern_c! {
        /// Get the package address of the current actor
        pub fn actor_get_package_address() -> Buffer;

        /// Get the blueprint name of the current actor
        pub fn actor_get_blueprint_name() -> Buffer;

        /// Get the object id of a reference of the current actor
        pub fn actor_get_object_id(actor_ref_handle: ActorRefHandle) -> Buffer;

        /// Open a field of the current actor
        pub fn actor_open_field(
            actor_state_handle: ActorStateHandle,
            field_index: u32,
            flags: u32,
        ) -> FieldHandle;

        /// Emit an event
        pub fn actor_emit_event(
            event_name_ptr: *const u8,
            event_name_len: usize,
            event_data_ptr: *const u8,
            event_data_len: usize,
            event_flags: u32,
        );
    }
}

pub mod kv_store {
    pub use radix_engine_interface::types::{Buffer, BufferId, Slice};

    super::wasm_extern_c! {
        /// Creates a new key value store
        pub fn kv_store_new(schema_ptr: *const u8, schema_len: usize) -> Buffer;

        /// Opens an entry for a given key in a key value store
        pub fn kv_store_open_entry(
            key_value_store_id_ptr: *const u8,
            key_value_store_id_len: usize,
            key_ptr: *const u8,
            key_len: usize,
            flags: u32,
        ) -> u32;

        /// Removes a value from a key value store
        pub fn kv_store_remove_entry(
            key_value_store_id_ptr: *const u8,
            key_value_store_id_len: usize,
            key: *const u8,
            key_len: usize,
        ) -> Buffer;
    }
}

/// API to manipulate or get information about an open Key Value Entry
pub mod kv_entry {
    pub use radix_engine_interface::types::{Buffer, BufferId, Slice};

    super::wasm_extern_c! {
        /// Reads the value in a Key Value entry
        pub fn kv_entry_read(kv_entry_handle: u32) -> Buffer;

        /// Writes a value to Key Value entry
        pub fn kv_entry_write(kv_entry_handle: u32, buffer_ptr: *const u8, buffer_len: usize);

        /// Removes the value in an underlying Key Value entry
        pub fn kv_entry_remove(kv_entry_handle: u32) -> Buffer;

        /// Close a Key Value entry
        pub fn kv_entry_close(kv_entry_handle: u32);
    }
}

/// API to manipulate or get information about an open Field Entry
pub mod field_entry {
    pub use radix_engine_interface::types::{Buffer, BufferId, Slice};

    super::wasm_extern_c! {
        /// Reads the value in a field
        pub fn field_entry_read(handle: u32) -> Buffer;

        /// Writes a value to a field
        pub fn field_entry_write(handle: u32, data_ptr: *const u8, data_len: usize);

        /// Close a field entry
        pub fn field_entry_close(handle: u32);
    }
}

pub mod costing {
    pub use radix_engine_interface::types::{Buffer, BufferId, Slice};

    super::wasm_extern_c! {
        pub fn costing_get_execution_cost_unit_limit() -> u32;

        pub fn costing_get_execution_cost_unit_price() -> Buffer;

        pub fn costing_get_finalization_cost_unit_limit() -> u32;

        pub fn costing_get_finalization_cost_unit_price() -> Buffer;

        pub fn costing_get_usd_price() -> Buffer;

        pub fn costing_get_tip_percentage() -> u32;

        pub fn costing_get_fee_balance() -> Buffer;
    }
}

/// Various environment-based API calls
pub mod system {
    pub use radix_engine_interface::types::{Buffer, BufferId, Slice};

    super::wasm_extern_c! {
        /// Logs a string message
        pub fn sys_log(
            level_ptr: *const u8,
            level_len: usize,
            message_ptr: *const u8,
            message_len: usize,
        );

        /// Encode an address to bech32 encoding
        pub fn sys_bech32_encode_address(address_ptr: *const u8, address_len: usize) -> Buffer;

        /// Retrieves the current transaction hash
        pub fn sys_get_transaction_hash() -> Buffer;

        /// Generates a unique id
        pub fn sys_generate_ruid() -> Buffer;

        /// Panics and halts transaction execution
        pub fn sys_panic(message_ptr: *const u8, message_len: usize);
    }
}

/// Various environment-based API calls
pub mod crypto_utils {
    pub use radix_engine_interface::types::{Buffer, BufferId, Slice};

    super::wasm_extern_c! {
        pub fn crypto_utils_bls12381_v1_verify(
            message_ptr: *const u8,
            message_len: usize,
            public_key_ptr: *const u8,
            public_key_len: usize,
            signature_ptr: *const u8,
            signature_len: usize) -> u32;

        pub fn crypto_utils_bls12381_v1_aggregate_verify(
            pub_keys_and_msgs_ptr: *const u8,
            pub_keys_and_msgs_len: usize,
            signature_ptr: *const u8,
            signature_len: usize) -> u32;

        pub fn crypto_utils_bls12381_v1_fast_aggregate_verify(
            messages_ptr: *const u8,
            messages_len: usize,
            public_keys_ptr: *const u8,
            public_keys_len: usize,
            signature_ptr: *const u8,
            signature_len: usize) -> u32;

        pub fn crypto_utils_bls12381_g2_signature_aggregate(
            signatures_ptr: *const u8,
            signatures_len: usize) -> Buffer;

        pub fn crypto_utils_keccak256_hash(
            message_ptr: *const u8,
            message_len: usize) -> Buffer;
    }
}

pub mod buffer {
    pub use radix_engine_interface::types::{Buffer, BufferId, Slice};

    super::wasm_extern_c! {
        /// Consumes a buffer by copying the contents into the specified destination.
        pub fn buffer_consume(buffer_id: BufferId, destination_ptr: *mut u8);
    }
}

macro_rules! wasm_extern_c {
    (
        $(
            $(#[$meta:meta])*
            pub fn $fn_ident: ident ( $($arg_name: ident: $arg_type: ty),* $(,)? ) $(-> $rtn_type: ty)?;
        )*
    ) => {
        #[cfg(target_arch = "wasm32")]
        extern "C" {
            $(
                $(#[$meta])*
                pub fn $fn_ident ( $($arg_name: $arg_type),* ) $(-> $rtn_type)?;
            )*
        }

        $(
            #[cfg(not(target_arch = "wasm32"))]
            $(#[$meta])*
            pub unsafe fn $fn_ident ( $(_: $arg_type),* ) $(-> $rtn_type)? {
                unimplemented!("Not implemented for non-wasm targets")
            }
        )*
    };
}
use wasm_extern_c;