Skip to content

Commit 549b639

Browse files
authored
feat: snip-12 typed data parsing and hashing (#686)
1 parent de3fec7 commit 549b639

File tree

16 files changed

+3046
-18
lines changed

16 files changed

+3046
-18
lines changed

Cargo.lock

Lines changed: 17 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -95,21 +95,23 @@ Examples can be found in the [examples folder](./examples):
9595

9696
7. [Encoding and decoding Cairo types](./examples/serde.rs)
9797

98-
8. [Batched JSON-RPC requests](./examples/batch.rs)
98+
8. [Parse a SNIP-12 message and compute its hash](./examples/snip_12_json.rs)
9999

100-
9. [Call a contract view function](./examples/erc20_balance.rs)
100+
9. [Batched JSON-RPC requests](./examples/batch.rs)
101101

102-
10. [Deploy an Argent X account to a pre-funded address](./examples/deploy_argent_account.rs)
102+
10. [Call a contract view function](./examples/erc20_balance.rs)
103103

104-
11. [Inspect public key with Ledger](./examples/ledger_public_key.rs)
104+
11. [Deploy an Argent X account to a pre-funded address](./examples/deploy_argent_account.rs)
105105

106-
12. [Deploy an OpenZeppelin account with Ledger](./examples/deploy_account_with_ledger.rs)
106+
12. [Inspect public key with Ledger](./examples/ledger_public_key.rs)
107107

108-
13. [Transfer ERC20 tokens with Ledger](./examples/transfer_with_ledger.rs)
108+
13. [Deploy an OpenZeppelin account with Ledger](./examples/deploy_account_with_ledger.rs)
109109

110-
14. [Parsing a JSON-RPC request on the server side](./examples/parse_jsonrpc_request.rs)
110+
14. [Transfer ERC20 tokens with Ledger](./examples/transfer_with_ledger.rs)
111111

112-
15. [Inspecting a erased provider-specific error type](./examples/downcast_provider_error.rs)
112+
15. [Parsing a JSON-RPC request on the server side](./examples/parse_jsonrpc_request.rs)
113+
114+
16. [Inspecting a erased provider-specific error type](./examples/downcast_provider_error.rs)
113115

114116
## License
115117

examples/snip_12_json.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
use starknet::{core::types::TypedData, macros::felt};
2+
3+
fn main() {
4+
let raw = r#"{
5+
"types": {
6+
"StarknetDomain": [
7+
{ "name": "name", "type": "shortstring" },
8+
{ "name": "version", "type": "shortstring" },
9+
{ "name": "chainId", "type": "shortstring" },
10+
{ "name": "revision", "type": "shortstring" }
11+
],
12+
"Example Message": [
13+
{ "name": "Name", "type": "string" },
14+
{ "name": "Some Array", "type": "u128*" },
15+
{ "name": "Some Object", "type": "My Object" }
16+
],
17+
"My Object": [
18+
{ "name": "Some Selector", "type": "selector" },
19+
{ "name": "Some Contract Address", "type": "ContractAddress" }
20+
]
21+
},
22+
"primaryType": "Example Message",
23+
"domain": {
24+
"name": "Starknet Example",
25+
"version": "1",
26+
"chainId": "SN_MAIN",
27+
"revision": "1"
28+
},
29+
"message": {
30+
"Name": "some name",
31+
"Some Array": [1, 2, 3, 4],
32+
"Some Object": {
33+
"Some Selector": "transfer",
34+
"Some Contract Address": "0x0123"
35+
}
36+
}
37+
}"#;
38+
39+
let typed_data = serde_json::from_str::<TypedData>(raw).unwrap();
40+
println!("SNIP-12 revision: {}", typed_data.revision());
41+
42+
let message_hash = typed_data.message_hash(felt!("0x1234")).unwrap();
43+
println!("SNIP-12 hash: {:#064x}", message_hash);
44+
}

starknet-core/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ starknet-core-derive = { version = "0.1.0", path = "../starknet-core-derive" }
2222
base64 = { version = "0.21.0", default-features = false, features = ["alloc"] }
2323
crypto-bigint = { version = "0.5.1", default-features = false }
2424
flate2 = { version = "1.0.25", optional = true }
25+
foldhash = { version = "0.1.4", default-features = false }
2526
hex = { version = "0.4.3", default-features = false, features = ["alloc"] }
27+
indexmap = { version = "2.7.0", default-features = false, features = ["serde"] }
2628
num-traits = { version = "0.2.19", default-features = false }
2729
serde = { version = "1.0.160", default-features = false, features = ["derive"] }
2830
serde_json = { version = "1.0.96", default-features = false, features = ["alloc", "raw_value"] }
@@ -42,7 +44,7 @@ wasm-bindgen-test = "0.3.34"
4244

4345
[features]
4446
default = ["std"]
45-
std = ["dep:flate2", "starknet-crypto/std", "starknet-types-core/std"]
47+
std = ["dep:flate2", "starknet-crypto/std", "starknet-types-core/std", "indexmap/std"]
4648
no_unknown_fields = []
4749

4850
[[bench]]

starknet-core/src/codec.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use alloc::{boxed::Box, fmt::Formatter, format, string::*, vec::*};
22
use core::{fmt::Display, mem::MaybeUninit};
3+
use starknet_crypto::{PedersenHasher, PoseidonHasher};
34

45
use num_traits::ToPrimitive;
56

@@ -117,12 +118,31 @@ pub struct Error {
117118
repr: Box<str>,
118119
}
119120

121+
// This implementation is useful for encoding single-felt types.
122+
impl FeltWriter for Felt {
123+
fn write(&mut self, felt: Felt) {
124+
*self = felt;
125+
}
126+
}
127+
120128
impl FeltWriter for Vec<Felt> {
121129
fn write(&mut self, felt: Felt) {
122130
self.push(felt);
123131
}
124132
}
125133

134+
impl FeltWriter for PedersenHasher {
135+
fn write(&mut self, felt: Felt) {
136+
self.update(felt);
137+
}
138+
}
139+
140+
impl FeltWriter for PoseidonHasher {
141+
fn write(&mut self, felt: Felt) {
142+
self.update(felt);
143+
}
144+
}
145+
126146
impl Encode for Felt {
127147
fn encode<W: FeltWriter>(&self, writer: &mut W) -> Result<(), Error> {
128148
writer.write(*self);

starknet-core/src/types/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ mod conversions;
1111

1212
mod serde_impls;
1313

14+
/// SNIP-12 typed data.
15+
pub mod typed_data;
16+
pub use typed_data::TypedData;
17+
1418
// TODO: better namespacing of exports?
1519
mod codegen;
1620
pub use codegen::{

0 commit comments

Comments
 (0)