-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Needed to use macros for a lot of things. The main problem is that we need to use separate namespaces for V2 and ERC20 ABI types, because we need to tweak the abi.json and change the names of some types. That's required for signatures to work correctly, but they can't both have the same names. Experimented with a generic based solution, but ultimately went for the macros because of that.
- Loading branch information
Showing
19 changed files
with
1,867 additions
and
377 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,2 @@ | ||
pub mod metadata; | ||
pub mod zora_premint_v2; | ||
pub mod zora_premint; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
use alloy::primitives::{address, Address}; | ||
use alloy::sol; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
pub static PREMINT_FACTORY_ADDR: Address = address!("7777773606e7e46C8Ba8B98C08f5cD218e31d340"); | ||
|
||
// we need to use separate namespaces for each premint version, | ||
// because they all need to have the type names for the signatures | ||
// to calculate correctly | ||
sol! { | ||
#[derive(Debug, Serialize, Deserialize, PartialEq)] | ||
IZoraPremintERC20V1, | ||
"src/premints/zora_premint/zora1155PremintExecutor_erc20_1.json" | ||
} | ||
|
||
sol! { | ||
#[derive(Debug, Serialize, Deserialize, PartialEq)] | ||
IZoraPremintV2, | ||
"src/premints/zora_premint/zora1155PremintExecutor_v2.json" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
use crate::{implement_zora_premint_traits, typed_rule}; | ||
use alloy::primitives::Address; | ||
|
||
use crate::premints::zora_premint::contract::IZoraPremintERC20V1; | ||
use crate::premints::zora_premint::contract::IZoraPremintV2::IZoraPremintV2Errors; | ||
|
||
use crate::rules::Rule; | ||
use crate::storage::Reader; | ||
use crate::types::PremintTypes; | ||
|
||
impl Default for IZoraPremintERC20V1::ContractCreationConfig { | ||
fn default() -> Self { | ||
Self { | ||
contractAdmin: Default::default(), | ||
contractURI: Default::default(), | ||
contractName: Default::default(), | ||
} | ||
} | ||
} | ||
|
||
impl Default for IZoraPremintERC20V1::TokenCreationConfig { | ||
fn default() -> Self { | ||
Self { | ||
tokenURI: Default::default(), | ||
maxSupply: Default::default(), | ||
maxTokensPerAddress: Default::default(), | ||
pricePerToken: Default::default(), | ||
mintStart: Default::default(), | ||
mintDuration: Default::default(), | ||
royaltyBPS: Default::default(), | ||
fixedPriceMinter: Default::default(), | ||
royaltyMintSchedule: Default::default(), | ||
royaltyRecipient: Default::default(), | ||
} | ||
} | ||
} | ||
|
||
impl Default for IZoraPremintERC20V1::CreatorAttribution { | ||
fn default() -> Self { | ||
Self { | ||
tokenConfig: Default::default(), | ||
uid: Default::default(), | ||
version: Default::default(), | ||
deleted: Default::default(), | ||
} | ||
} | ||
} | ||
|
||
implement_zora_premint_traits!( | ||
IZoraPremintERC20V1, | ||
ERC20V1, | ||
"zora_premint_erc20v1", | ||
"ERC20_1" | ||
); | ||
|
||
pub fn all_v2_rules<T: Reader>() -> Vec<Box<dyn Rule<T>>> { | ||
vec![ | ||
typed_rule!( | ||
PremintTypes::ZoraERC20V1, | ||
ERC20V1::is_authorized_to_create_premint | ||
), | ||
typed_rule!(PremintTypes::ZoraERC20V1, ERC20V1::is_valid_signature), | ||
typed_rule!(PremintTypes::ZoraERC20V1, ERC20V1::is_chain_supported), | ||
typed_rule!(PremintTypes::ZoraERC20V1, ERC20V1::not_minted), | ||
typed_rule!( | ||
PremintTypes::ZoraERC20V1, | ||
ERC20V1::premint_version_supported | ||
), | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
pub mod contract; | ||
pub mod erc20v1; | ||
pub mod rules; | ||
pub mod types; | ||
pub mod v2; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
use crate::premints::zora_premint::v2::V2; | ||
use crate::rules::Rule; | ||
use crate::storage::Reader; | ||
use crate::typed_rule; | ||
use crate::types::PremintTypes; | ||
#[macro_export] | ||
macro_rules! zora_premint_rules { | ||
($namespace:tt, $typ:ty, $version:literal) => { | ||
pub async fn is_authorized_to_create_premint<T: $crate::storage::Reader>( | ||
premint: &$typ, | ||
context: &$crate::rules::RuleContext<T>, | ||
) -> eyre::Result<$crate::rules::Evaluation> { | ||
let rpc = match context.rpc { | ||
None => return $crate::ignore!("Rule requires RPC call"), | ||
Some(ref rpc) => rpc, | ||
}; | ||
|
||
let call = $namespace::isAuthorizedToCreatePremintCall { | ||
contractAddress: premint.collection_address, | ||
signer: premint.collection.contractAdmin, | ||
premintContractConfigContractAdmin: premint.collection.contractAdmin, | ||
}; | ||
|
||
let result = $crate::chain::view_contract_call( | ||
call, | ||
rpc, | ||
$crate::premints::zora_premint::contract::PREMINT_FACTORY_ADDR, | ||
) | ||
.await?; | ||
|
||
match result.isAuthorized { | ||
true => Ok($crate::rules::Evaluation::Accept), | ||
false => $crate::reject!("Unauthorized to create premint"), | ||
} | ||
} | ||
|
||
pub async fn not_minted<T: $crate::storage::Reader>( | ||
premint: &$typ, | ||
context: &$crate::rules::RuleContext<T>, | ||
) -> eyre::Result<$crate::rules::Evaluation> { | ||
let rpc = match context.rpc { | ||
None => return $crate::ignore!("Rule requires RPC provider"), | ||
Some(ref rpc) => rpc, | ||
}; | ||
|
||
let call = $namespace::premintStatusCall { | ||
contractAddress: premint.collection_address, | ||
uid: premint.premint.uid, | ||
}; | ||
|
||
let result = $crate::chain::view_contract_call( | ||
call, | ||
rpc, | ||
$crate::premints::zora_premint::contract::PREMINT_FACTORY_ADDR, | ||
) | ||
.await?; | ||
|
||
match result.contractCreated && !result.tokenIdForPremint.is_zero() { | ||
false => Ok($crate::rules::Evaluation::Accept), | ||
true => $crate::reject!("Premint already minted"), | ||
} | ||
} | ||
|
||
pub async fn premint_version_supported<T: $crate::storage::Reader>( | ||
premint: &$typ, | ||
context: &$crate::rules::RuleContext<T>, | ||
) -> eyre::Result<$crate::rules::Evaluation> { | ||
let rpc = match context.rpc { | ||
None => return $crate::ignore!("Rule requires RPC provider"), | ||
Some(ref rpc) => rpc, | ||
}; | ||
|
||
let call = $namespace::supportedPremintSignatureVersionsCall { | ||
contractAddress: premint.collection_address, | ||
}; | ||
|
||
let result = $crate::chain::view_contract_call( | ||
call, | ||
rpc, | ||
$crate::premints::zora_premint::contract::PREMINT_FACTORY_ADDR, | ||
) | ||
.await?; | ||
|
||
match result.versions.contains(&$version.to_string()) { | ||
true => Ok($crate::rules::Evaluation::Accept), | ||
false => $crate::reject!(concat!( | ||
"Premint version ", | ||
$version, | ||
" not supported by contract" | ||
)), | ||
} | ||
} | ||
|
||
// * signatureIsValid ( this can be performed entirely offline ) | ||
// * check if the signature is valid | ||
// * check if the signature is equal to the proposed contract admin | ||
|
||
pub async fn is_valid_signature<T: $crate::storage::Reader>( | ||
premint: &$typ, | ||
_context: &$crate::rules::RuleContext<T>, | ||
) -> eyre::Result<$crate::rules::Evaluation> { | ||
// * if contract exists, check if the signer is the contract admin | ||
// * if contract does not exist, check if the signer is the proposed contract admin | ||
|
||
let signature: alloy::signers::Signature = | ||
core::str::FromStr::from_str(premint.signature.as_str())?; | ||
|
||
let domain = premint.eip712_domain(); | ||
let hash = alloy::sol_types::SolStruct::eip712_signing_hash(&premint.premint, &domain); | ||
let signer: alloy::primitives::Address = | ||
signature.recover_address_from_prehash(&hash)?; | ||
|
||
if signer != premint.collection.contractAdmin { | ||
$crate::reject!( | ||
"Invalid signature for contract admin {} vs recovered {}", | ||
premint.collection.contractAdmin, | ||
signer | ||
) | ||
} else { | ||
Ok($crate::rules::Evaluation::Accept) | ||
} | ||
} | ||
|
||
pub async fn is_chain_supported<T: $crate::storage::Reader>( | ||
premint: &$typ, | ||
_context: &$crate::rules::RuleContext<T>, | ||
) -> eyre::Result<$crate::rules::Evaluation> { | ||
let supported_chains: Vec<u64> = vec![7777777, 999999999, 8453]; | ||
let chain_id = premint.chain_id; | ||
|
||
match supported_chains.contains(&chain_id) { | ||
true => Ok($crate::rules::Evaluation::Accept), | ||
false => $crate::reject!("Chain not supported"), | ||
} | ||
} | ||
}; | ||
} |
Oops, something went wrong.