use bobcat_cd::{leftpad_u8, leftpad_u16, leftpad_u32, leftpad_usize};
use bobcat_maths::U;
use array_concat::concat_arrays;
use crate::selectors;
selectors! {
SEL_ESTIMATE_REQUEST_PRICE_NATIVE = b"estimateRequestPriceNative(uint32,uint32,uint256)",
SEL_REQUEST_RANDOM_WORDS_IN_NATIVE = b"requestRandomWordsInNative(uint32,uint16,uint32,bytes)",
SEL_LINK = b"link()",
SEL_LINK_NATIVE_FEED = b"linkNativeFeed()"
}
pub const fn make_fn_estimate_request_price_native(
callback_gas_limit: u32,
num_words: u32,
request_gas_price_wei: U,
) -> [u8; 32 * 3 + 4] {
concat_arrays!(
SEL_ESTIMATE_REQUEST_PRICE_NATIVE,
leftpad_u32(callback_gas_limit),
leftpad_u32(num_words),
request_gas_price_wei.0
)
}
pub const REQUEST_WORDS_NATIVE_SLICE_BASE: usize = 32 * 5 + 4;
pub const fn make_fn_request_words_in_native_slice<
const BASE_LEN: usize,
const PADDING: usize,
const ALL_LEN: usize,
>(
callback_gas_limit: u32,
request_confirmations: u16,
num_words: u32,
extra_args: [u8; BASE_LEN],
) -> [u8; ALL_LEN] {
assert!(
ALL_LEN >= BASE_LEN + PADDING + REQUEST_WORDS_NATIVE_SLICE_BASE,
"make_fn_request_words_in_native_slice inconsistent length"
);
assert!(
BASE_LEN % 32 == 0 || PADDING + BASE_LEN == (BASE_LEN + 31) & !31,
"padding inconsistent"
);
assert!(
(ALL_LEN - 4) % 32 == 0,
"length needs extra word to be % 32 = 0"
);
concat_arrays!(
SEL_REQUEST_RANDOM_WORDS_IN_NATIVE,
leftpad_u32(callback_gas_limit),
leftpad_u16(request_confirmations),
leftpad_u32(num_words),
leftpad_u8(32 * 4),
leftpad_usize(BASE_LEN),
extra_args,
[0u8; PADDING]
)
}
pub fn make_fn_request_words_in_native_no_bytes(
callback_gas_limit: u32,
request_confirmations: u16,
num_words: u32,
) -> [u8; REQUEST_WORDS_NATIVE_SLICE_BASE] {
make_fn_request_words_in_native_slice::<0, 0, REQUEST_WORDS_NATIVE_SLICE_BASE>(
callback_gas_limit,
request_confirmations,
num_words,
[],
)
}
pub const fn make_fn_link() -> [u8; 4] {
SEL_LINK
}
pub const fn make_fn_link_native_feed() -> [u8; 4] {
SEL_LINK_NATIVE_FEED
}
#[cfg(test)]
mod test {
use super::*;
use proptest::prelude::*;
use alloy_sol_macro::sol;
use alloy_sol_types::SolCall;
use alloy_primitives::Bytes;
sol! {
function requestRandomWordsInNative(
uint32 callbackGasLimit,
uint16 requestConfirmations,
uint32 numWords,
bytes calldata extraArgs
) external payable returns (uint256 requestId);
}
proptest! {
#[test]
fn test_make_fn_request_words_in_native_no_bytes(
callback_gas_limit in any::<u32>(),
request_confirmations in any::<u16>(),
num_words in any::<u32>()
) {
let e = requestRandomWordsInNativeCall {
callbackGasLimit: callback_gas_limit,
requestConfirmations: request_confirmations,
numWords: num_words,
extraArgs: Bytes::new()
}
.abi_encode();
let v = make_fn_request_words_in_native_no_bytes(
callback_gas_limit,
request_confirmations,
num_words
);
assert_eq!(
e,
v,
"{} != {}",
const_hex::encode(&e),
const_hex::encode(&v)
);
}
#[test]
fn test_make_fn_request_words_in_native_slice_tiny(
callback_gas_limit in any::<u32>(),
request_confirmations in any::<u16>(),
num_words in any::<u32>(),
extra_args in any::<[u8; 2]>()
) {
let e = requestRandomWordsInNativeCall {
callbackGasLimit: callback_gas_limit,
requestConfirmations: request_confirmations,
numWords: num_words,
extraArgs: Bytes::copy_from_slice(&extra_args)
}
.abi_encode();
let v = make_fn_request_words_in_native_slice::<
2,
30,
{ 32 + REQUEST_WORDS_NATIVE_SLICE_BASE },
> (
callback_gas_limit,
request_confirmations,
num_words,
extra_args
);
assert_eq!(
e,
v,
"{} != {}",
const_hex::encode(&e),
const_hex::encode(&v)
);
}
#[test]
fn test_make_fn_request_words_in_native_slice_even(
callback_gas_limit in any::<u32>(),
request_confirmations in any::<u16>(),
num_words in any::<u32>(),
extra_args in any::<[u8; 32]>()
) {
let e = requestRandomWordsInNativeCall {
callbackGasLimit: callback_gas_limit,
requestConfirmations: request_confirmations,
numWords: num_words,
extraArgs: Bytes::copy_from_slice(&extra_args)
}
.abi_encode();
let v = make_fn_request_words_in_native_slice::<
32,
0,
{ 32 + REQUEST_WORDS_NATIVE_SLICE_BASE },
> (
callback_gas_limit,
request_confirmations,
num_words,
extra_args
);
assert_eq!(
e,
v,
"{} != {}",
const_hex::encode(&e),
const_hex::encode(&v)
);
}
#[test]
fn test_make_fn_request_words_in_native_slice_odd(
callback_gas_limit in any::<u32>(),
request_confirmations in any::<u16>(),
num_words in any::<u32>(),
extra_args in any::<[u8; 100]>()
) {
let e = requestRandomWordsInNativeCall {
callbackGasLimit: callback_gas_limit,
requestConfirmations: request_confirmations,
numWords: num_words,
extraArgs: Bytes::copy_from_slice(&extra_args)
}
.abi_encode();
let v = make_fn_request_words_in_native_slice::<
100,
28,
{ 100 + 28 + REQUEST_WORDS_NATIVE_SLICE_BASE },
> (
callback_gas_limit,
request_confirmations,
num_words,
extra_args
);
assert_eq!(
e,
v,
"{} != {}",
const_hex::encode(&e),
const_hex::encode(&v)
);
}
#[test]
fn test_make_fn_request_words_in_native_slice_huge(
callback_gas_limit in any::<u32>(),
request_confirmations in any::<u16>(),
num_words in any::<u32>(),
extra_args in any::<[u8; 1000]>()
) {
let e = requestRandomWordsInNativeCall {
callbackGasLimit: callback_gas_limit,
requestConfirmations: request_confirmations,
numWords: num_words,
extraArgs: Bytes::copy_from_slice(&extra_args)
}
.abi_encode();
let v = make_fn_request_words_in_native_slice::<
1000,
24,
{ 1000 + 24 + REQUEST_WORDS_NATIVE_SLICE_BASE },
> (
callback_gas_limit,
request_confirmations,
num_words,
extra_args
);
assert_eq!(
e,
v,
"{} != {}",
const_hex::encode(&e),
const_hex::encode(&v)
);
}
}
}