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
use ethers_core::types::{Address, Selector, U256};
use serde::Deserialize;
use std::str::FromStr;
use url::Url;
pub const ERC721_OWNER_SELECTOR: Selector = [0x63, 0x52, 0x21, 0x1e];
pub const ERC1155_BALANCE_SELECTOR: Selector = [0x00, 0xfd, 0xd5, 0x8e];
const IPFS_GATEWAY: &str = "https://ipfs.io/ipfs/";
pub struct ERCNFT {
pub type_: ERCNFTType,
pub contract: Address,
pub id: [u8; 32],
}
impl FromStr for ERCNFT {
type Err = String;
fn from_str(input: &str) -> Result<ERCNFT, Self::Err> {
let split: Vec<&str> =
input.trim_start_matches("eip155:").trim_start_matches("1/").split(':').collect();
let (token_type, inner_path) = if split.len() == 2 {
(
ERCNFTType::from_str(split[0])
.map_err(|_| "Unsupported ERC token type".to_string())?,
split[1],
)
} else {
return Err("Unsupported ERC link".to_string())
};
let token_split: Vec<&str> = inner_path.split('/').collect();
let (contract_addr, token_id) = if token_split.len() == 2 {
let token_id = U256::from_dec_str(token_split[1])
.map_err(|e| format!("Unsupported token id type: {} {e}", token_split[1]))?;
let mut token_id_bytes = [0x0; 32];
token_id.to_big_endian(&mut token_id_bytes);
(
Address::from_str(token_split[0].trim_start_matches("0x"))
.map_err(|e| format!("Invalid contract address: {} {e}", token_split[0]))?,
token_id_bytes,
)
} else {
return Err("Unsupported ERC link path".to_string())
};
Ok(ERCNFT { id: token_id, type_: token_type, contract: contract_addr })
}
}
#[derive(PartialEq, Eq)]
pub enum ERCNFTType {
ERC721,
ERC1155,
}
impl FromStr for ERCNFTType {
type Err = ();
fn from_str(input: &str) -> Result<ERCNFTType, Self::Err> {
match input {
"erc721" => Ok(ERCNFTType::ERC721),
"erc1155" => Ok(ERCNFTType::ERC1155),
_ => Err(()),
}
}
}
impl ERCNFTType {
pub fn resolution_selector(&self) -> Selector {
match self {
ERCNFTType::ERC721 => [0xc8, 0x7b, 0x56, 0xdd],
ERCNFTType::ERC1155 => [0x0e, 0x89, 0x34, 0x1c],
}
}
}
#[derive(Deserialize)]
pub struct Metadata {
pub image: String,
}
pub fn http_link_ipfs(url: Url) -> Result<Url, String> {
Url::parse(IPFS_GATEWAY)
.unwrap()
.join(url.to_string().trim_start_matches("ipfs://").trim_start_matches("ipfs/"))
.map_err(|e| e.to_string())
}