1use crate::ethereum::abi::{self, AbiValue};
22
23pub const IMPLEMENTATION_SLOT: [u8; 32] = {
29 let mut s = [0u8; 32];
32 s[0] = 0x36;
33 s[1] = 0x08;
34 s[2] = 0x94;
35 s[3] = 0xa1;
36 s[4] = 0x3b;
37 s[5] = 0xa1;
38 s[6] = 0xa3;
39 s[7] = 0x21;
40 s[8] = 0x06;
41 s[9] = 0x67;
42 s[10] = 0xc8;
43 s[11] = 0x28;
44 s[12] = 0x49;
45 s[13] = 0x2d;
46 s[14] = 0xb9;
47 s[15] = 0x8d;
48 s[16] = 0xca;
49 s[17] = 0x3e;
50 s[18] = 0x20;
51 s[19] = 0x76;
52 s[20] = 0xcc;
53 s[21] = 0x37;
54 s[22] = 0x35;
55 s[23] = 0xa9;
56 s[24] = 0x20;
57 s[25] = 0xa3;
58 s[26] = 0xca;
59 s[27] = 0x50;
60 s[28] = 0x5d;
61 s[29] = 0x38;
62 s[30] = 0x2b;
63 s[31] = 0xbc;
64 s
65};
66
67pub const ADMIN_SLOT: [u8; 32] = {
71 let mut s = [0u8; 32];
73 s[0] = 0xb5;
74 s[1] = 0x31;
75 s[2] = 0x27;
76 s[3] = 0x68;
77 s[4] = 0x4a;
78 s[5] = 0x56;
79 s[6] = 0x8b;
80 s[7] = 0x31;
81 s[8] = 0x73;
82 s[9] = 0xae;
83 s[10] = 0x13;
84 s[11] = 0xb9;
85 s[12] = 0xf8;
86 s[13] = 0xa6;
87 s[14] = 0x01;
88 s[15] = 0x6e;
89 s[16] = 0x24;
90 s[17] = 0x3e;
91 s[18] = 0x63;
92 s[19] = 0xb6;
93 s[20] = 0xe8;
94 s[21] = 0xee;
95 s[22] = 0x11;
96 s[23] = 0x78;
97 s[24] = 0xd6;
98 s[25] = 0xa7;
99 s[26] = 0x17;
100 s[27] = 0x85;
101 s[28] = 0x0b;
102 s[29] = 0x5d;
103 s[30] = 0x61;
104 s[31] = 0x03;
105 s
106};
107
108pub const BEACON_SLOT: [u8; 32] = {
112 let mut s = [0u8; 32];
114 s[0] = 0xa3;
115 s[1] = 0xf0;
116 s[2] = 0xad;
117 s[3] = 0x74;
118 s[4] = 0xe5;
119 s[5] = 0x42;
120 s[6] = 0x3a;
121 s[7] = 0xeb;
122 s[8] = 0xfd;
123 s[9] = 0x80;
124 s[10] = 0xd3;
125 s[11] = 0xef;
126 s[12] = 0x43;
127 s[13] = 0x46;
128 s[14] = 0x57;
129 s[15] = 0x83;
130 s[16] = 0x35;
131 s[17] = 0xa9;
132 s[18] = 0xa7;
133 s[19] = 0x2a;
134 s[20] = 0xea;
135 s[21] = 0xee;
136 s[22] = 0x59;
137 s[23] = 0xff;
138 s[24] = 0x6c;
139 s[25] = 0xb3;
140 s[26] = 0x58;
141 s[27] = 0x2b;
142 s[28] = 0x35;
143 s[29] = 0x13;
144 s[30] = 0x3d;
145 s[31] = 0x50;
146 s
147};
148
149#[must_use]
155pub fn eip1967_slot(label: &str) -> [u8; 32] {
156 let hash = keccak256(label.as_bytes());
157 let mut slot = hash;
159 let mut borrow = true;
160 for byte in slot.iter_mut().rev() {
161 if borrow {
162 if *byte == 0 {
163 *byte = 0xFF;
164 } else {
165 *byte -= 1;
166 borrow = false;
167 }
168 }
169 }
170 slot
171}
172
173#[must_use]
179pub fn encode_upgrade_to(new_implementation: [u8; 20]) -> Vec<u8> {
180 let func = abi::Function::new("upgradeTo(address)");
181 func.encode(&[AbiValue::Address(new_implementation)])
182}
183
184#[must_use]
188pub fn encode_upgrade_to_and_call(new_implementation: [u8; 20], data: &[u8]) -> Vec<u8> {
189 let func = abi::Function::new("upgradeToAndCall(address,bytes)");
190 func.encode(&[
191 AbiValue::Address(new_implementation),
192 AbiValue::Bytes(data.to_vec()),
193 ])
194}
195
196#[must_use]
200pub fn encode_proxiable_uuid() -> Vec<u8> {
201 let func = abi::Function::new("proxiableUUID()");
202 func.encode(&[])
203}
204
205#[must_use]
207pub fn encode_implementation() -> Vec<u8> {
208 let func = abi::Function::new("implementation()");
209 func.encode(&[])
210}
211
212#[must_use]
216pub fn encode_change_admin(new_admin: [u8; 20]) -> Vec<u8> {
217 let func = abi::Function::new("changeAdmin(address)");
218 func.encode(&[AbiValue::Address(new_admin)])
219}
220
221#[must_use]
223pub fn encode_admin() -> Vec<u8> {
224 let func = abi::Function::new("admin()");
225 func.encode(&[])
226}
227
228#[must_use]
234pub fn encode_upgrade_beacon(new_beacon: [u8; 20]) -> Vec<u8> {
235 encode_upgrade_to(new_beacon)
236}
237
238#[must_use]
244pub fn encode_initialize(args: &[AbiValue]) -> Vec<u8> {
245 let func = abi::Function::new("initialize()");
248 func.encode(args)
249}
250
251#[must_use]
253pub fn encode_initializer(signature: &str, args: &[AbiValue]) -> Vec<u8> {
254 let func = abi::Function::new(signature);
255 func.encode(args)
256}
257
258#[derive(Debug, Clone)]
262pub struct Multicall3Call {
263 pub target: [u8; 20],
265 pub allow_failure: bool,
267 pub call_data: Vec<u8>,
269}
270
271#[must_use]
276pub fn encode_multicall(calls: &[Multicall3Call]) -> Vec<u8> {
277 let func = abi::Function::new("aggregate3((address,bool,bytes)[])");
278 let call_tuples: Vec<AbiValue> = calls
279 .iter()
280 .map(|c| {
281 AbiValue::Tuple(vec![
282 AbiValue::Address(c.target),
283 AbiValue::Bool(c.allow_failure),
284 AbiValue::Bytes(c.call_data.clone()),
285 ])
286 })
287 .collect();
288 func.encode(&[AbiValue::Array(call_tuples)])
289}
290
291pub const MULTICALL3_ADDRESS: [u8; 20] = [
293 0xca, 0x11, 0xbd, 0xe0, 0x59, 0x77, 0xb3, 0x63, 0x11, 0x67, 0x02, 0x88, 0x62, 0xbe, 0x2a, 0x17,
294 0x39, 0x76, 0xca, 0x11,
295];
296
297#[must_use]
299pub fn encode_multicall_legacy(calls: &[([u8; 20], Vec<u8>)]) -> Vec<u8> {
300 let func = abi::Function::new("aggregate((address,bytes)[])");
301 let call_tuples: Vec<AbiValue> = calls
302 .iter()
303 .map(|(target, data)| {
304 AbiValue::Tuple(vec![
305 AbiValue::Address(*target),
306 AbiValue::Bytes(data.clone()),
307 ])
308 })
309 .collect();
310 func.encode(&[AbiValue::Array(call_tuples)])
311}
312
313fn keccak256(data: &[u8]) -> [u8; 32] {
316 super::keccak256(data)
317}
318
319#[cfg(test)]
322#[allow(clippy::unwrap_used, clippy::expect_used)]
323mod tests {
324 use super::*;
325
326 #[test]
329 fn test_implementation_slot_matches_eip1967() {
330 let computed = eip1967_slot("eip1967.proxy.implementation");
331 assert_eq!(computed, IMPLEMENTATION_SLOT);
332 }
333
334 #[test]
335 fn test_admin_slot_matches_eip1967() {
336 let computed = eip1967_slot("eip1967.proxy.admin");
337 assert_eq!(computed, ADMIN_SLOT);
338 }
339
340 #[test]
341 fn test_beacon_slot_matches_eip1967() {
342 let computed = eip1967_slot("eip1967.proxy.beacon");
343 assert_eq!(computed, BEACON_SLOT);
344 }
345
346 #[test]
347 fn test_implementation_slot_hex() {
348 assert_eq!(
349 hex::encode(IMPLEMENTATION_SLOT),
350 "360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc"
351 );
352 }
353
354 #[test]
355 fn test_admin_slot_hex() {
356 assert_eq!(
357 hex::encode(ADMIN_SLOT),
358 "b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103"
359 );
360 }
361
362 #[test]
363 fn test_beacon_slot_hex() {
364 assert_eq!(
365 hex::encode(BEACON_SLOT),
366 "a3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50"
367 );
368 }
369
370 #[test]
373 fn test_eip1967_slot_deterministic() {
374 let s1 = eip1967_slot("eip1967.proxy.implementation");
375 let s2 = eip1967_slot("eip1967.proxy.implementation");
376 assert_eq!(s1, s2);
377 }
378
379 #[test]
380 fn test_eip1967_slot_different_labels() {
381 let s1 = eip1967_slot("eip1967.proxy.implementation");
382 let s2 = eip1967_slot("eip1967.proxy.admin");
383 assert_ne!(s1, s2);
384 }
385
386 #[test]
389 fn test_encode_upgrade_to_selector() {
390 let calldata = encode_upgrade_to([0xBB; 20]);
391 let expected = abi::function_selector("upgradeTo(address)");
392 assert_eq!(&calldata[..4], &expected);
393 assert_eq!(calldata.len(), 4 + 32);
394 }
395
396 #[test]
397 fn test_encode_upgrade_to_contains_address() {
398 let addr = [0xBB; 20];
399 let calldata = encode_upgrade_to(addr);
400 assert_eq!(&calldata[4 + 12..4 + 32], &addr);
402 }
403
404 #[test]
405 fn test_encode_upgrade_to_and_call_selector() {
406 let calldata = encode_upgrade_to_and_call([0xBB; 20], &[0xDE, 0xAD]);
407 let expected = abi::function_selector("upgradeToAndCall(address,bytes)");
408 assert_eq!(&calldata[..4], &expected);
409 }
410
411 #[test]
412 fn test_encode_upgrade_to_and_call_with_empty_data() {
413 let calldata = encode_upgrade_to_and_call([0xBB; 20], &[]);
414 let expected = abi::function_selector("upgradeToAndCall(address,bytes)");
415 assert_eq!(&calldata[..4], &expected);
416 }
417
418 #[test]
419 fn test_encode_proxiable_uuid_selector() {
420 let calldata = encode_proxiable_uuid();
421 let expected = abi::function_selector("proxiableUUID()");
422 assert_eq!(&calldata[..4], &expected);
423 }
424
425 #[test]
426 fn test_encode_implementation_selector() {
427 let calldata = encode_implementation();
428 let expected = abi::function_selector("implementation()");
429 assert_eq!(&calldata[..4], &expected);
430 }
431
432 #[test]
435 fn test_encode_change_admin_selector() {
436 let calldata = encode_change_admin([0xCC; 20]);
437 let expected = abi::function_selector("changeAdmin(address)");
438 assert_eq!(&calldata[..4], &expected);
439 }
440
441 #[test]
442 fn test_encode_admin_selector() {
443 let calldata = encode_admin();
444 let expected = abi::function_selector("admin()");
445 assert_eq!(&calldata[..4], &expected);
446 }
447
448 #[test]
451 fn test_encode_upgrade_beacon_selector() {
452 let calldata = encode_upgrade_beacon([0xDD; 20]);
453 let expected = abi::function_selector("upgradeTo(address)");
454 assert_eq!(&calldata[..4], &expected);
455 }
456
457 #[test]
460 fn test_encode_initialize_selector() {
461 let calldata = encode_initialize(&[]);
462 let expected = abi::function_selector("initialize()");
463 assert_eq!(&calldata[..4], &expected);
464 }
465
466 #[test]
467 fn test_encode_initializer_custom() {
468 let calldata = encode_initializer(
469 "initialize(address,uint256)",
470 &[AbiValue::Address([0xAA; 20]), AbiValue::from_u64(42)],
471 );
472 let expected = abi::function_selector("initialize(address,uint256)");
473 assert_eq!(&calldata[..4], &expected);
474 }
475
476 #[test]
479 fn test_encode_multicall_selector() {
480 let calls = vec![Multicall3Call {
481 target: [0xAA; 20],
482 allow_failure: false,
483 call_data: vec![0x01],
484 }];
485 let calldata = encode_multicall(&calls);
486 let expected = abi::function_selector("aggregate3((address,bool,bytes)[])");
487 assert_eq!(&calldata[..4], &expected);
488 }
489
490 #[test]
491 fn test_encode_multicall_empty() {
492 let calldata = encode_multicall(&[]);
493 let expected = abi::function_selector("aggregate3((address,bool,bytes)[])");
494 assert_eq!(&calldata[..4], &expected);
495 }
496
497 #[test]
498 fn test_encode_multicall_multiple_calls() {
499 let calls = vec![
500 Multicall3Call {
501 target: [0xAA; 20],
502 allow_failure: false,
503 call_data: vec![0x01, 0x02],
504 },
505 Multicall3Call {
506 target: [0xBB; 20],
507 allow_failure: true,
508 call_data: vec![0x03],
509 },
510 ];
511 let calldata = encode_multicall(&calls);
512 assert!(calldata.len() > 4); }
514
515 #[test]
516 fn test_encode_multicall_deterministic() {
517 let calls = vec![Multicall3Call {
518 target: [0xAA; 20],
519 allow_failure: false,
520 call_data: vec![0x01],
521 }];
522 let c1 = encode_multicall(&calls);
523 let c2 = encode_multicall(&calls);
524 assert_eq!(c1, c2);
525 }
526
527 #[test]
528 fn test_encode_multicall_legacy_selector() {
529 let calls = vec![([0xAA; 20], vec![0x01u8])];
530 let calldata = encode_multicall_legacy(&calls);
531 let expected = abi::function_selector("aggregate((address,bytes)[])");
532 assert_eq!(&calldata[..4], &expected);
533 }
534
535 #[test]
538 fn test_multicall3_address() {
539 assert_eq!(
540 hex::encode(MULTICALL3_ADDRESS).to_lowercase(),
541 "ca11bde05977b3631167028862be2a173976ca11"
542 );
543 }
544}