diff --git a/docs/devnet/content.md b/docs/devnet/content.md index a7e73e5a..dbb743c8 100644 --- a/docs/devnet/content.md +++ b/docs/devnet/content.md @@ -9,7 +9,3 @@ url: / ! import ./intro.md ! import ./config.md - ---- - -! import ./precompile.md diff --git a/docs/devnet/intro.md b/docs/devnet/intro.md index 59318121..961b4ae0 100644 --- a/docs/devnet/intro.md +++ b/docs/devnet/intro.md @@ -7,4 +7,7 @@ layout: single The pod devnet is a test network for developers to experiment with the pod network. It is designed to be a sandbox for testing and development purposes, allowing developers to build and test -their applications without the need for real assets or transactions. \ No newline at end of file +their applications without the need for real assets or transactions. + + +> We expect the devnet to have breaking changes or be reset (pruned completely) at any time. diff --git a/docs/devnet/precompile.md b/docs/devnet/precompile.md deleted file mode 100644 index 2ed60613..00000000 --- a/docs/devnet/precompile.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -layout: single ---- - -## Precompiles - -! table style1 -| Signature | Address | Description | -| ----------------------------------------------------- | ------------------------------------------ | ---------------------------------------------------------------------- | -| requireQuorum(boolean) | 0x4CF3F1637bfEf1534e56352B6ebAae243aF464c3 | Like `require` but passes if supermajority agrees | -| external_call([uint256, [Transaction,bytes]]) | 0x8712E00C337971f876621faB9326908fdF330d77 | Call a smart contract on another EVM-compatible chain | -| call_with_state([uint256, Header, EVMCall, EVMState]) | 0xb4bbff8874b41f97535bc8dafbaaff0dc5c72e5a | Simulate an EVM transaction execution given a particular initial state | -! table end - -> We expect the devnet to have breaking changes or be reset (pruned completely) at any time. \ No newline at end of file diff --git a/docs/examples/auctions/auction-contract-prod.md b/docs/examples/auctions/auction-contract-prod.md deleted file mode 100644 index 2b431e09..00000000 --- a/docs/examples/auctions/auction-contract-prod.md +++ /dev/null @@ -1,52 +0,0 @@ ---- -layout: simple ---- - -! content id="auction-contract-on-pod" - -## Auction Contract on pod - -The auction contract on pod is pre-deployed and ready to use. The implementation on the SDK side using the `sol!` macro looks as follows. - -! content end - -! content - -! sticky - -! codeblock title="Production sample" - -```rust -use alloy_sol_types::sol; - -sol! { - #[sol(bytecode = "608060405234801561001057600080fd5b506101a8806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063852ca61214610030575b600080fd5b61004361003e3660046100e5565b610045565b005b834211156100995760405162461bcd60e51b815260206004820152601760248201527f41756374696f6e20646561646c696e6520706173736564000000000000000000604482015260640160405180910390fd5b83336001600160a01b0316867f71a5674c44b823bc0df08201dfeb2e8bdf698cd684fd2bbaa79adcf2c99fc186866040516100d691815260200190565b60405180910390a45050505050565b6000806000806000608086880312156100fd57600080fd5b853594506020860135935060408601359250606086013567ffffffffffffffff8082111561012a57600080fd5b818801915088601f83011261013e57600080fd5b81358181111561014d57600080fd5b89602082850101111561015f57600080fd5b969995985093965060200194939250505056fea2646970667358221220b2c739e8530a3ddbc3107dcff0aac4bf8a7a78ab2225b6726d3087eb41178e0264736f6c63430008150033")] - contract Auction { - event BidSubmitted(uint256 indexed auction_id, address indexed bidder, uint256 indexed deadline, uint256 value); - - function submitBid(uint256 auction_id, uint256 deadline, uint256 value, bytes calldata data) public { - require(block.timestamp <= deadline, "Auction deadline passed"); - - emit BidSubmitted(auction_id, msg.sender, deadline, value); - } - } -} -``` - -! codeblock end - -The contract can be accessed as follows: - -! codeblock - -```rust -use pod_core::contracts::auction::Auction; -``` - -! codeblock end - -The contract is deployed to the address `0x217F5658c6ecC27D439922263AD9Bb8e992e0373` on pod network. - -! sticky end - -! content end diff --git a/docs/examples/auctions/auction-contract.md b/docs/examples/auctions/auction-contract.md deleted file mode 100644 index bdf5d966..00000000 --- a/docs/examples/auctions/auction-contract.md +++ /dev/null @@ -1,62 +0,0 @@ ---- -layout: simple ---- - -! content id="auction-contract" - -## Auction Contract - -### Solidity - -The auction contract implements a time-based bidding system where participants can submit bids during an active auction period. Here's the complete contract code: - -The contract features: - -- Checking that the auction was sent before the deadline. -- Events for tracking bid submissions - -! content end - -! content - -! sticky - -! codeblock title="Solidity" - -```javascript -contract Auction { - // Event emitted when a bid is submitted - event BidSubmitted( - uint256 indexed auction_id, - address indexed bidder, - uint256 indexed deadline, - uint256 value - ); - - /** - * @notice Submit a bid for an auction - * @param auction_id The ID of the auction - * @param deadline The deadline for the auction - * @param value The bid value - * @param data Additional data for the bid - */ - function submitBid( - uint256 auction_id, - uint256 deadline, - uint256 value, - bytes calldata data - ) public { - // Check that the auction deadline hasn't passed - requireTimeBefore(deadline, "Auction deadline passed"); - - // Emit the bid submission event - emit BidSubmitted(auction_id, msg.sender, deadline, value); - } -} -``` - -! codeblock end - -! sticky end - -! content end diff --git a/docs/examples/auctions/auction-mechanise.md b/docs/examples/auctions/auction-mechanise.md deleted file mode 100644 index 597be342..00000000 --- a/docs/examples/auctions/auction-mechanise.md +++ /dev/null @@ -1,36 +0,0 @@ ---- -layout: single ---- - -! anchor auction-mechanise - -## Auction Mechanism - -The Pod Auction is an optimistic, single-shot, first-price auction. It is optimistic because it assumes participants behave honestly by default, and only resorts to dispute resolution when misbehavior occurs. - -### Protocol Overview - -- **Single-shot**: Participants submit bids once without revisions. -- **First-price**: Highest bid wins the auction. -- **Decentralized**: No trusted third-party auctioneer. Pod network replicas act as validators. - -### Auction Phases - -1. Bidding Phase: - - - Bidders submit bids to Pod replicas within a specific timeframe (auction start to auction finish). - - Valid bids are signed by pod validators if submitted within this timeframe. - -2. Optimistic Outcome: - - - Once the bidding phase concludes (after the deadline is reached), bidders read Pod to locally identify the winner. - - The bidder observing themselves as the winner optimistically announces this outcome with sufficient signatures (2f+1) to an on-chain consumer. - -3. Optimistic Dispute Resolution (only if needed): - - - If a bidder wrongly claims victory, other bidders can dispute the outcome by submitting evidence of a higher bid. - - The smart contract consumer verifies signatures and settles disputes transparently. - -4. No-Show Handling: - - - If no bidder announces victory, bidders submit their local winning bids, and the consumer selects the highest valid bid. diff --git a/docs/examples/auctions/content.md b/docs/examples/auctions/content.md index 3822b0fd..7bd618b9 100644 --- a/docs/examples/auctions/content.md +++ b/docs/examples/auctions/content.md @@ -44,14 +44,16 @@ The contract assumes that the `deadline` for an `auction_id` is known between th ! codeblock title="Auction.sol" ```solidity -import {requireTimeBefore} from "pod-sdk/Time.sol"; +import {requireTimeBefore, Time} from "pod-sdk/Time.sol"; contract Auction { + using Time for Time.Timestamp; + // Event emitted when a bid is submitted event BidSubmitted( uint256 indexed auction_id, address indexed bidder, - uint256 indexed deadline, + Time.Timestamp indexed deadline, uint256 value, bytes data ); @@ -65,7 +67,7 @@ contract Auction { */ function submitBid( uint256 auction_id, - uint256 deadline, + Time.Timestamp deadline, uint256 value, bytes calldata data ) public { @@ -104,7 +106,7 @@ pub async fn submit_bid( pod_provider: &P, contract_address: Address, auction_id: U256, - deadline: U256, + deadline: u64, value: U256, data: Vec, ) -> Result { @@ -149,21 +151,23 @@ async fn subscribe_logs_for_auction_until_deadline( pod_provider: &P, contract_address: Address, auction_id: U256, - deadline: U257, + deadline: u64, ) -> Result<()> { println!("Waiting for on-chain time to pass the deadline {deadline}..."); - pod_provider.wait_past_perfect_time(deadline.as_u64()).await?; + pod_provider.wait_past_perfect_time(deadline).await?; println!("On-chain time is now past {deadline}."); let bid_submitted_sig = AuctionContract::events::BidSubmitted::SIGNATURE_HASH; let auction_id_topic = H256::from_uint(&auction_id); + let deadline_topic = H256::from_uint(&U256::from(deadline)); + let filter = Filter::new() .address(contract_address) .topic0(ValueOrArray::Value(bid_submitted_sig)) .topic1(ValueOrArray::Value(auction_id_topic)) - .topic2(ValueOrArray::Value(deadline)); + .topic2(ValueOrArray::Value(deadline_topic)); let logs = pod_provider.get_logs(&filter).await?; for log in logs { diff --git a/docs/examples/auctions/env.md b/docs/examples/auctions/env.md deleted file mode 100644 index abdcbdbd..00000000 --- a/docs/examples/auctions/env.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -layout: simple ---- - -! content id="environment-setup" - -### Environment setup - -! content end - -! content - -! sticky - -! codeblock title="Set up environment variables" - - -```bash -# Set up environment variables -export POD_RPC="https://rpc.v1.dev.pod.network" -export AUCTION_CONTRACT="" -export PRIVATE_KEY="" -``` - -! codeblock end - -! sticky end - -! content end diff --git a/docs/examples/auctions/future.md b/docs/examples/auctions/future.md deleted file mode 100644 index 56a2d1fa..00000000 --- a/docs/examples/auctions/future.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -layout: single ---- - -! anchor future - -## Further reading - -- Read about about the [RPC API](/reference/rpc-api). -- Learn more about pod's [Partial Order](/architecture/fast-path) and when working on timestamps with pod, pay attention to the Wiggle Room of Timestamps. diff --git a/docs/examples/auctions/intro.md b/docs/examples/auctions/intro.md deleted file mode 100644 index b014f6c9..00000000 --- a/docs/examples/auctions/intro.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -layout: single ---- - -# Auctions - -This guide explains how to participate in auctions on pod. In these auctions bidders submit bids within a duration when the auction is active, and then anyone can query for the set of valid bids. - -## Introduction - -An auction contract is deployed that accepts bids only during a certain time duration. Bidders submit their bids, and then anyone can query for the set of accepted bids. - -## Prerequisites - -Before participating in auctions, ensure you have: - -### Required tools - -- A funded wallet on pod devnet -- Pod SDK installed. How to build the pod provider can be seen in the [SDK](https://docs.pod.network/reference/sdk) section diff --git a/docs/examples/auctions/participating.md b/docs/examples/auctions/participating.md deleted file mode 100644 index c30fdbec..00000000 --- a/docs/examples/auctions/participating.md +++ /dev/null @@ -1,219 +0,0 @@ ---- -layout: simple ---- - -! content id="participating" - -## Participating in the auction - -### Loading the Environment variables - -First, we need to load the environment variables specified in the start of the documentation: - -! content end - -! content - -! sticky - -! codeblock - -```rust -use std::env; -use std::str::FromStr; - -use alloy_transport::http::reqwest::Url; -use alloy_primitives::Address; -use eyre::Result; - -/// Step 1: Load environment variables -fn load_env() -> Result<(Url, String, Address)> { - // Default to a known WS endpoint if POD_RPC is unset: - let rpc_ws = env::var("POD_RPC").unwrap_or_else(|_| "wss://rpc.v1.dev.pod.network/ws".to_string()); - // For example: wss://rpc.pod.network/ws or ws://127.0.0.1:8545 - let ws_url = Url::parse(&rpc_ws).expect("Invalid URL in POD_RPC"); - - // Private key must be set: - let private_key_hex = - env::var("PRIVATE_KEY").expect("Missing PRIVATE_KEY environment variable"); - - // Auction contract address must be set: - let contract_address_str = - env::var("AUCTION_CONTRACT").expect("Missing AUCTION_CONTRACT environment variable"); - let contract_address = - Address::from_str(&contract_address_str).expect("Invalid address format for AUCTION_CONTRACT"); - - Ok((ws_url, private_key_hex, contract_address)) -} -``` - -! codeblock end - -! sticky end - -! content end - -! content - -### Initializing the auction contract: - -Third, we want to initialize the auction contract: - -! content end - -! content - -! sticky - -! codeblock - -```rust -use alloy::providers::Provider; -use alloy_primitives::Address; -use pod_core::contracts::auction::Auction; - -/// Step 2: Initialize the Auction contract binding -fn init_auction(pod_provider: &P, contract_address: Address) -> Auction

{ - Auction::new(contract_address, pod_provider) -} -``` - -! codeblock end - -! sticky end - -! content end - -! content id="submitting-a-bid" - -## Submitting a bid: - -Now, we want to submit our bid: - -! content end - -! content - -! sticky - -! codeblock - -```rust -use alloy::providers::Provider; -use alloy_primitives::U256; -use eyre::Result; -use pod_core::contracts::auction::Auction; -use alloy_rpc_types_eth::TransactionReceipt; - -/// Step 3: Submit a bid with custom parameters -pub async fn submit_bid( - auction: &Auction

, - auction_id: U256, - deadline: U256, - value: U256, - data: Vec, -) -> Result { - // Build the call - let call = auction.submit_bid(auction_id, deadline, value, data); - - // Send the transaction - let pending_tx = call.send().await?; - println!("Submitted tx: {:?}", pending_tx.hash()); - - // Optionally wait for the transaction receipt - let receipt = pending_tx.get_receipt().await?; - println!("Transaction receipt: {:?}", receipt); - - Ok(receipt) -} -``` - -! codeblock end - -! sticky end - -! content end - -! content id="subscribing-to-the-logs" - -## Subscribing to the logs of the auction - -Lastly, we want to subscribe to the auction logs to get all the bids: - -! content end - -! content - -! sticky - -! codeblock - -```rust -async fn subscribe_logs_for_auction_until_deadline( - pod_provider: &P, - contract_address: Address, - auction_id: U256, - deadline: U256, -) -> Result<()> { - use alloy_rpc_types_eth::{BlockNumber, Filter, ValueOrArray}; - use alloy_primitives::H256; - use futures::StreamExt; - use pod_core::contracts::auction::Auction as AuctionContract; - - // (A) Ensure we've advanced the chain time beyond `deadline` - // so the next call to `get_block_number()` is guaranteed - // to be a block whose timestamp >= `deadline`. - println!("Waiting for on-chain time to pass the deadline {deadline}..."); - pod_provider.wait_past_perfect_time(deadline.as_u64()).await?; - println!("On-chain time is now past {deadline}."); - - // (B) Capture the current block number as `block_end` - // This block corresponds to (or just follows) the `deadline`. - let block_end = pod_provider - .get_block_number() - .await - .expect("Failed to fetch current block number"); - println!("Captured block number {block_end} as the block_end (at or after deadline)"); - - // 1) BidSubmitted event signature - let bid_submitted_sig = AuctionContract::events::BidSubmitted::SIGNATURE_HASH; - - // 2) Convert the auction_id to a 32-byte H256 - let auction_id_topic = H256::from_uint(&auction_id); - - // 3) Create a filter with the address, signature, and the auction_id as topic1 - // plus from_block = earliest (or some known start) and to_block = `block_end`. - let filter = Filter::new() - .address(contract_address) - .topic0(ValueOrArray::Value(bid_submitted_sig)) - .topic1(ValueOrArray::Value(auction_id_topic)) - .from_block(BlockNumber::Earliest) - .to_block(BlockNumber::Number(block_end)); - - // 4) Subscribe to logs up to `block_end` - // (No new logs beyond `block_end` will be streamed.) - let subscription = pod_provider.subscribe_logs_pod(&filter).await?; - let mut log_stream = subscription.into_stream(); - - tokio::spawn(async move { - while let Some(log) = log_stream.next().await { - println!("Filtered Log received: {log:?}"); - - let decoded = - AuctionContract::events::BidSubmitted::decode_log(&log) - .expect("Could not decode BidSubmitted event"); - println!("Decoded BidSubmitted event: {:?}", decoded); - } - - println!("No more logs up to block_end = {block_end}. Subscription ended."); - }); - - Ok(()) -} -``` - -! codeblock end - -! sticky end - -! content end diff --git a/docs/examples/auctions/together.md b/docs/examples/auctions/together.md deleted file mode 100644 index f189a7f6..00000000 --- a/docs/examples/auctions/together.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -layout: simple ---- - -! content id="together" - -## Putting it all together - -The following code snipped gives the full sequence of events from sending the transaction to waiting for the confirmation: - -! content end - -! content - -! sticky - -! codeblock - -```rust -use eyre::Result; -use alloy_primitives::{Address, U256}; -use std::str::FromStr; - -#[tokio::main] -async fn main() -> Result<()> { - // 1) Load environment variables - let (rpc_url, private_key_hex) = load_env()?; - - // 2) Build the Pod provider (from the Rust SDK approach) - let pod_provider = build_pod_provider(&rpc_url, &private_key_hex).await?; - - // 3) Let's define your 'from' (sender) address and the 'to' (recipient) - // Typically, you already know your "from_address" from the private key, but - // you can also query it from the signer if needed. - // For example, if your `build_pod_provider` can return the signer's address. - // We'll assume you already know it: - let from_address = Address::from_str("0xSender...")?; - let recipient = Address::from_str("0xabcDEF...")?; - - // 4) Send a payment transaction - let value_wei = U256::from(1_000_000u64); // 1,000,000 Wei for example - let (tx_hash, start_time) = send_payment_tx( - &pod_provider, - from_address, - recipient, - value_wei - ).await?; - - println!("Transaction hash: {:?}, start_time: {}", tx_hash, start_time); - - // 5) Wait for confirmation & verify - wait_for_receipts_and_verify(&pod_provider, recipient, start_time).await?; - - println!("Transaction fully confirmed!"); - Ok(()) -} -``` - -! codeblock end - -! sticky end - -! content end \ No newline at end of file diff --git a/docs/examples/overview/content.md b/docs/examples/content.md similarity index 85% rename from docs/examples/overview/content.md rename to docs/examples/content.md index 09ea2d63..8f032d6d 100644 --- a/docs/examples/overview/content.md +++ b/docs/examples/content.md @@ -2,14 +2,12 @@ title: Examples layout: single -url: /examples/overview - -toc: +url: /examples --- # Examples -### Simple examples to dip your toes into pod. +Explore end-to-end examples that show how to build on pod and the core concepts involved. Start with tokens and NFTs, then try auctions, voting, and ranked feeds. ! table style1 | Example | Description | diff --git a/docs/examples/notary/notary-contract.md b/docs/examples/notary/notary-contract.md index 7a26a0b8..7f6762e0 100644 --- a/docs/examples/notary/notary-contract.md +++ b/docs/examples/notary/notary-contract.md @@ -26,7 +26,7 @@ mapping(bytes32 => uint256) public timestamps; #### Events ```solidity -event DocumentTimestamped(bytes32 indexed documentHash, address indexed submitter, uint256 timestamp); +event DocumentTimestamped(bytes32 indexed documentHash, address indexed submitter, Time.Timestamp timestamp); ``` - Emitted whenever a document hash is timestamped or updated with an earlier timestamp. @@ -34,7 +34,7 @@ event DocumentTimestamped(bytes32 indexed documentHash, address indexed submitte #### Functions ```solidity -function timestamp(bytes32 documentHash, uint256 ts) external; +function timestamp(bytes32 documentHash, Time.Timestamp ts) external; ``` ##### Parameters @@ -60,31 +60,33 @@ function timestamp(bytes32 documentHash, uint256 ts) external; ```solidity pragma solidity ^0.8.26; -import {requireTimeBefore} from "../../../contracts/src/lib/Time.sol"; +import {requireTimeBefore, Time} from "pod-sdk/Time.sol"; function min(uint256 a, uint256 b) pure returns (uint256) { return a <= b ? a : b; } contract Notary { - mapping(bytes32 => uint256) public timestamps; + using Time for Time.Timestamp; - event DocumentTimestamped(bytes32 indexed documentHash, address indexed submitter, uint256 timestamp); + mapping(bytes32 => Time.Timestamp) public timestamps; + + event DocumentTimestamped(bytes32 indexed documentHash, address indexed submitter, Time.Timestamp timestamp); /// @notice Submit a document hash to be timestamped /// @param documentHash The keccak256 hash of the document /// @param ts The timestamp of the document. Must be in the future. - function timestamp(bytes32 documentHash, uint256 ts) external { + function timestamp(bytes32 documentHash, Time.Timestamp ts) external { requireTimeBefore(ts, "timestamp must be in the future"); - if (timestamps[documentHash] == 0) { + if ((timestamps[documentHash]).isZero()) { timestamps[documentHash] = ts; emit DocumentTimestamped(documentHash, msg.sender, ts); return; } - uint256 minTimestamp = min(ts, timestamps[documentHash]); - if (minTimestamp != timestamps[documentHash]) { + Time.Timestamp minTimestamp = Time.min(ts, timestamps[documentHash]); + if (minTimestamp.diffMicros(timestamps[documentHash]) != 0) { timestamps[documentHash] = minTimestamp; emit DocumentTimestamped(documentHash, msg.sender, minTimestamp); } diff --git a/docs/examples/notary/usage.md b/docs/examples/notary/usage.md index 5d1da9c8..8c1fe5a7 100644 --- a/docs/examples/notary/usage.md +++ b/docs/examples/notary/usage.md @@ -118,7 +118,7 @@ async fn timestamp( let document_hash = keccak256(doc); let pendix_tx = notary - .timestamp(document_hash, U256::from(timestamp.as_micros())) + .timestamp(document_hash, timestamp.as_micros() as u64) .send() .await?; diff --git a/docs/examples/voting/content.md b/docs/examples/voting/content.md index 5968b21b..8a86d147 100644 --- a/docs/examples/voting/content.md +++ b/docs/examples/voting/content.md @@ -41,10 +41,11 @@ The `hasVoted` variable stores whether a voter has voted for a proposal or not. ! codeblock title="Solidity" ```solidity -import {requireTimeBefore, requireTimeAfter} from "pod-sdk/Time.sol"; +import {requireTimeBefore, requireTimeAfter, Time} from "pod-sdk/Time.sol"; import {FastTypes} from "pod-sdk/FastTypes.sol"; contract Voting { + using Time for Time.Timestamp; using FastTypes for FastTypes.SharedCounter; using FastTypes for FastTypes.OwnedCounter; @@ -58,7 +59,7 @@ contract Voting { /// @param deadline The proposal deadline in seconds /// @param voters The proposal participants /// @return proposalId The unique proposal ID - function createProposal(uint256 deadline, uint256 threshold, address[] calldata voters, bytes calldata data) + function createProposal(Time.Timestamp deadline, uint256 threshold, address[] calldata voters, bytes calldata data) public returns (bytes32 proposalId) { @@ -160,7 +161,7 @@ async fn create_proposal( let pendix_tx = voting .createProposal( - U256::from(deadline.as_seconds()), + deadline.as_micros() as u64, U256::from(threshold), participants.clone(), data_bytes.into(), diff --git a/docs/examples/voting/creating-poll.md b/docs/examples/voting/creating-poll.md index 7e81a14d..d9e67fd9 100644 --- a/docs/examples/voting/creating-poll.md +++ b/docs/examples/voting/creating-poll.md @@ -66,7 +66,7 @@ async fn create_poll( let deadline = Timestamp::from(deadline); let pendix_tx = voting .createPoll( - U256::from(deadline.as_seconds()), + deadline.as_micros() as u64, U256::from(max_choice), participants.clone(), ) diff --git a/docs/examples/voting/voting-contract.md b/docs/examples/voting/voting-contract.md index 4ed0afef..1d4326d1 100644 --- a/docs/examples/voting/voting-contract.md +++ b/docs/examples/voting/voting-contract.md @@ -22,7 +22,7 @@ enum VoterState { Unregistered, Registered, Voted } ```solidity struct Poll { - uint256 deadline; + Time.Timestamp deadline; uint256 maxChoice; address owner; mapping(address => VoterState) voters; @@ -62,7 +62,7 @@ The contract has **no** publicly accessible state. Instead, it exposes a method #### Events -- `PollCreated(bytes32 pollId, uint256 deadline)` +- `PollCreated(bytes32 pollId, Time.Timestamp deadline)` - `Voted(bytes32 pollId, address voter, uint256 choice)` - `Winner(bytes32 pollId, uint256 choice)` @@ -75,7 +75,7 @@ real-time. For example, an application can obtain the ID of the poll created by ##### createPoll ```solidity -function createPoll(uint256 deadline, uint256 maxChoice, address[] calldata voters) public returns (bytes32) +function createPoll(Time.Timestamp deadline, uint256 maxChoice, address[] calldata voters) public returns (bytes32) ``` Used to create a new poll. @@ -135,9 +135,10 @@ It's a helper function that applications can call to gain insight into the poll ```solidity pragma solidity ^0.8.28; -import {requireTimeBefore, requireTimeAfter} from "pod-sdk/pod/Time.sol"; +import {requireTimeBefore, requireTimeAfter, Time} from "pod-sdk/Time.sol"; contract Voting { + using Time for Time.Timestamp; enum VoterState { Unregistered, Registered, @@ -145,7 +146,7 @@ contract Voting { } struct Poll { - uint256 deadline; + Time.Timestamp deadline; uint256 maxChoice; address owner; mapping(address => VoterState) voters; @@ -158,12 +159,12 @@ contract Voting { // Maps poll ID to poll data mapping(bytes32 => Poll) private polls; - event PollCreated(bytes32 indexed pollId, uint256 deadline); + event PollCreated(bytes32 indexed pollId, Time.Timestamp deadline); event Voted(bytes32 indexed pollId, address indexed voter, uint256 indexed choice); event Winner(bytes32 indexed pollId, uint256 indexed choice); function getPollId( - uint256 deadline, + Time.Timestamp deadline, uint256 maxChoice, address owner, address[] calldata voters @@ -178,7 +179,7 @@ contract Voting { } function createPoll( - uint256 deadline, + Time.Timestamp deadline, uint256 maxChoice, address[] calldata voters ) public returns (bytes32 pollId){ diff --git a/docs/langs.yml b/docs/langs.yml index 90e8286c..d503ec0c 100644 --- a/docs/langs.yml +++ b/docs/langs.yml @@ -4,3 +4,5 @@ langs: - lang: rust label: Rust default: true + - lang: solidity + label: Solidity diff --git a/docs/menu.yaml b/docs/menu.yaml index f72404de..993dfa3b 100644 --- a/docs/menu.yaml +++ b/docs/menu.yaml @@ -1,5 +1,5 @@ menu: - - heading: getting-started + - heading: getting started - href: / label: Welcome to pod - href: /devnet @@ -22,7 +22,9 @@ menu: label: Gas Pricing newTab: true - - heading: examples + - heading: examples + - href: /examples + label: Overview - href: /examples/tokens label: Tokens - href: /examples/nfts @@ -34,11 +36,18 @@ menu: - heading: Building on pod + - href: /precompiles + label: Precompiles - href: /json-rpc label: JSON-RPC - href: /solidity-sdk external: true label: Solidity SDK + children: + - label: FastTypes + tocOf: /solidity-sdk/fast-types + - label: Time + tocOf: /solidity-sdk/time - href: https://docs.rs/pod-sdk label: Rust SDK newTab: true diff --git a/docs/precompiles/callWithState.md b/docs/precompiles/callWithState.md new file mode 100644 index 00000000..95db4f83 --- /dev/null +++ b/docs/precompiles/callWithState.md @@ -0,0 +1,138 @@ +--- +layout: simple +--- + +! content id="callWithState" + +! anchor callWithState go-up +## Call With State + +Simulates an EVM call against a supplied header and state on a specified chain. Executes the provided call in an ephemeral VM and returns the call's raw return bytes. + +### Address + +0xB4BBff8874b41f97535bC8dAFBaAff0DC5c72E5A + +### Inputs + +! table style1 +| Byte range | Name | Description | +| ------------------ | ---------- | --------------------------------------------------------------------------- | +| [0; I size] | input (I) | struct `EVMCallWithStateArgs` with `chainId`, `header`, `call`, and `state` | +! table end + +The EVMCallWithStateArgs struct is defined as: +```solidity +struct EVMCallWithStateArgs { + uint256 chainId; + Header header; + EVMCall call; + EVMState state; +} + +struct Header { + bytes32 parentHash; + bytes32 uncleHash; + address coinbase; + bytes32 root; + bytes32 txHash; + bytes32 receiptHash; + bytes bloom; + uint256 difficulty; + uint256 number; + uint256 gasLimit; + uint256 gasUsed; + uint256 time; + bytes extra; + bytes32 mixDigest; + bytes8 nonce; +} + +struct EVMCall { + address from; + address to; + bytes input; +} + +struct EVMState { + Account[] accounts; +} + +struct Account { + AccountProof proof; + bytes code; +} + +struct StorageProof { + bytes32 key; + bytes32 value; + bytes[] proof; +} + +struct AccountProof { + address addr; + bytes[] accountProof; + uint256 balance; + bytes32 codeHash; + uint256 nonce; + bytes32 storageHash; + StorageProof[] storageProof; +} +``` + +### Output + +! table style1 +| Byte range | Name | Description | +| ------------------ | ---------- | ---------------------------------- | +| [0; R size] | result (R) | Return bytes of the EVM execution | +! table end + +### Errors + +- Out of gas if provided gas is less than base cost. +- Input must not be empty. +- Input decoding failed. +- Chain ID must fit in `uint64`. +- EVM creation failed (invalid header / state / account proofs / storage proofs). +- Returned empty output. +- Call failed or reverted. + +### Gas Cost + +Static gas: 500 + +Dynamic gas: gas used by the simulated EVM call + +! content end + + +! content +! sticky + +### Example + +! codeblock title="" +```solidity +address internal constant EVM_CALL_WITH_STATE = address( + uint160(uint256(keccak256("POD_EVM_CALL_WITH_STATE"))) +); + +function call_precompile(EVMCallWithStateArgs memory args) public view returns (bytes memory) { + bytes memory inputData = abi.encode( + args.chainId, + args.header, + args.call, + args.state + ); + + (bool success, bytes memory returnData) = EVM_CALL_WITH_STATE.staticcall{ gas: gasleft() }(inputData); + require(success, "Precompile call failed"); + + return returnData; +} +``` +! codeblock end + +! sticky end +! content end \ No newline at end of file diff --git a/docs/precompiles/content.md b/docs/precompiles/content.md new file mode 100644 index 00000000..77a545a4 --- /dev/null +++ b/docs/precompiles/content.md @@ -0,0 +1,39 @@ +--- +title: pod Precompiles +layout: blank + +url: /precompiles + +toc: + precompiles-overview: Overview + timestamp: timestamp + requireQuorum: requireQuorum + txInfo: txInfo + externalCall: externalCall + # callWithState: callWithState +--- + +! import ./overview.md +! import ./precompiles-table.md + +--- + +! import ./timestamp.md + +--- + +! import ./requireQuorum.md + +--- + +! import ./txInfo.md + +--- + +! import ./externalCall.md + + \ No newline at end of file diff --git a/docs/precompiles/externalCall.md b/docs/precompiles/externalCall.md new file mode 100644 index 00000000..09b513ad --- /dev/null +++ b/docs/precompiles/externalCall.md @@ -0,0 +1,82 @@ +--- +layout: simple +--- + +! content id="externalCall" + +! anchor externalCall go-up +## External Call + +Calls a smart contract on another EVM-compatible chain via the configured validators's RPC URL. Input specifies chain ID, transaction fields, and a block tag/number; output is the raw result of the remote `eth_call`. + +### Address + +0x8712E00C337971f876621faB9326908fdF330d77 + +### Inputs + +! table style1 +| Byte range | Name | Description | +| ------------------ | ------------------- | --------------------------------------------------------------------------------------------------------- | +| [0; I size] | input (I) | struct ExternalEthCallArgs defining the targeted chain and the arguments of the call (see details below) | +! table end + +The ExternalEthCallArgs struct is defined as: +```solidity + struct Transaction { + address from; + address to; + uint256 gas; + uint256 gasPrice; + uint256 value; + bytes data; +} + +struct EthCallArgs { + Transaction transaction; + bytes blockNumber; +} + +struct ExternalEthCallArgs { + uint256 chainId; + EthCallArgs ethCallArgs; +} +``` + +### Output + +Raw bytes returned by the remote `eth_call`. + +! table style1 +| Byte range | Name | Description | +| ------------------ | ---------- | --------------------------- | +| [0; R size] | result (R) | Remote `eth_call` return | +! table end + +### Errors + +- Out of gas if provided gas is less than base cost. +- Empty input. +- Input decoding failed. +- No RPC URL configured for the specified chain ID. +- Invalid argument: block number/tag format. +- Invalid argument: `to` is zero. + +### Gas Cost + +Static gas: 100 + +! content end + + +! content +! sticky + +### Example + +! codeblock title="solidity-sdk/src/ExternalEthCall.sol" +! codeblock import solidity "./src/ExternalEthCall.sol" lines=4-5,15-23,29-33,40-44 +! codeblock end + +! sticky end +! content end \ No newline at end of file diff --git a/docs/precompiles/externalGetLogs.md b/docs/precompiles/externalGetLogs.md new file mode 100644 index 00000000..4f8964f8 --- /dev/null +++ b/docs/precompiles/externalGetLogs.md @@ -0,0 +1,79 @@ +--- +layout: simple +--- + +! content id="externalGetLogs" + +! anchor externalGetLogs go-up +## External Get Logs + +Calls a smart contract on another EVM-compatible chain via the configured validators's RPC URL. Input specifies chain ID and log filter parameters; output is the raw result of the remote `eth_getLogs`. + +### Address + +0x9d2268c492bd5c3cc3c5190165005df0f043c076 + +### Inputs + +! table style1 +| Byte range | Name | Description | +| ------------------ | ------------------- | ------------------------------------------------------------------------------------------------------------ | +| [0; I size] | input (I) | struct ExternalEthGetLogsArgs defining the targeted chain and the log filter parameters (see details below) | +! table end + +The ExternalEthGetLogsArgs struct is defined as: +```solidity + +struct EthGetLogsArgs { + bytes fromBlock; + bytes toBlock; + address addr; + bytes32 blockHash; + bytes32[] topics; +} + +struct ExternalEthGetLogsArgs { + uint256 chainId; + EthGetLogsArgs ethGetLogsArgs; +} +``` + +### Output + +The resulting array of logs returned by the remote `eth_getLogs`, abi-encoded + +! table style1 +| Byte range | Name | Description | +| ------------------ | ---------- | ------------------------------ | +| [0; R size] | result (R) | Remote `eth_getLogs` return | +! table end + +### Errors + +- Out of gas if provided gas is less than base cost. +- Empty input. +- Input decoding failed. +- No RPC URL configured for the specified chain ID. +- Invalid argument: block number/tag format. +- Requst failed. + +### Gas Cost + +Static gas: 100 + +! content end + + +! content +! sticky + +### Example + +This example uses the POD_EXTERNAL_ETH_GET_LOGS precompile to run an eth_getLogs on Ethereum mainnet, returning the resulting logs array for the given log filter. + +! codeblock title="examples/solidity/src/ExternalEthGetLogs.sol" +! codeblock import solidity "./src/ExternalEthGetLogs.sol" +! codeblock end + +! sticky end +! content end \ No newline at end of file diff --git a/docs/precompiles/overview.md b/docs/precompiles/overview.md new file mode 100644 index 00000000..50ceb4ad --- /dev/null +++ b/docs/precompiles/overview.md @@ -0,0 +1,17 @@ +--- +layout: single +--- + +! anchor precompiles-overview +# Precompiles +In pod, precompiles work similarly to Ethereum. We currently support all precompiles available in the Prague version of the EVM, plus some Pod-specific ones listed in the table below. + +Recommendation: We recommend interacting with precompiles via the Pod Solidity SDK rather than calling them directly, as the SDK provides typed interfaces and safer defaults. See the [Solidity SDK documentation](/solidity-sdk). + + +## Precompile Addressing Scheme +The address of each Pod precompile is derived from the precompile name as the last 20 bytes of the `keccak256` hash of the name. + +```solidity +address constant POD_TIMESTAMP_PRECOMPILE = address(uint160(uint256(keccak256("POD_TIMESTAMP")))); +``` diff --git a/docs/precompiles/precompiles-table.md b/docs/precompiles/precompiles-table.md new file mode 100644 index 00000000..614d8d4a --- /dev/null +++ b/docs/precompiles/precompiles-table.md @@ -0,0 +1,16 @@ +--- +layout: full +--- + +! anchor precompiles-table +## Available Precompiles + +! table style1 rowLink="hash" rowLinkBy="id" rowLinkBase="/precompiles" hideFields="id" +| id | Address | Name | Minimum Gas | Description | +| ------------- | ------------------------------------------ | ----------------------- | ------------ | ------------------------------------------------------------------------------ | +| timestamp | 0x423Bb123D9d5143e662606Fd343b6766d7BCf721 | POD_TIMESTAMP | 100 | Fetches the current system timestamp | +| requireQuorum | 0x6AD9145E866c7A7DcCc6c277Ea86abBD268FBAc9 | POD_REQUIRE_QUORUM | 100 | Like `require` but passes if supermajority agrees | +| txInfo | 0x7687A3413739715807812b529f2d5f7Ef9057697 | POD_TX_INFO | 100 | Fetches information about the current transaction (nonce and transaction hash) | +| externalCall | 0x8712E00C337971f876621faB9326908fdF330d77 | POD_EXTERNAL_ETH_CALL | 100 | Call a smart contract on another EVM-compatible chain | + +! table end diff --git a/docs/precompiles/requireQuorum.md b/docs/precompiles/requireQuorum.md new file mode 100644 index 00000000..5bd8730b --- /dev/null +++ b/docs/precompiles/requireQuorum.md @@ -0,0 +1,68 @@ +--- +layout: simple +--- + +! content id="requireQuorum" + +! anchor requireQuorum go-up +## Require Quorum + +The Require Quorum precompile supports the two-round commit–execute flow used by pod. +It allows the enforcing a boolean check during the first round and skip it during the second round, once a quorum of validator approvals has been collected. + +This is ideal for scenarios where an action must first be validated by a majority of validators before it can be executed deterministically in the second round. + +#### How it works: + +**Round 1 – Commit Phase:** +Validators check the input boolean. + . If `false`, the call reverts. + . If `true`, an attestation is signed. + +**Round 2 – Execute Phase:** +The client submits a quorum of these attestations. +The precompile then accepts unconditionally, ensuring the transaction succeeds regardless of the boolean input. + +### Address + +0x6AD9145E866c7A7DcCc6c277Ea86abBD268FBAc9 + +### Inputs + +! table style1 +| Byte range | Name | Description | +| ------------------ | --------- | ------------------------------------- | +| [0; 31] (32 bytes) | input | Boolean to be evaluated by validators | +! table end + +> Note: `input` must be deterministic across validators for the same state and call data. + +### Output + +None. + +### Errors + +- Out of gas if provided gas is less than fixed base cost. +- Invalid input length (must be exactly 32 bytes). +- Round 1: reverts if `input == false` (quorum requirement not met). +- Round 2: succeeds regardless of `input` when quorum attestations are provided. + +### Gas Cost + +Static gas: 100 + +! content end + + +! content +! sticky + +### Example + +! codeblock title="solidity-sdk/src/Quorum.sol" +! codeblock import solidity "./src/Quorum.sol" lines=4-7,12-13 +! codeblock end + +! sticky end +! content end \ No newline at end of file diff --git a/docs/precompiles/src/Context.sol b/docs/precompiles/src/Context.sol new file mode 120000 index 00000000..37295c4e --- /dev/null +++ b/docs/precompiles/src/Context.sol @@ -0,0 +1 @@ +../../../solidity-sdk/src/Context.sol \ No newline at end of file diff --git a/docs/precompiles/src/ExternalEthCall.sol b/docs/precompiles/src/ExternalEthCall.sol new file mode 120000 index 00000000..43e148f9 --- /dev/null +++ b/docs/precompiles/src/ExternalEthCall.sol @@ -0,0 +1 @@ +../../../solidity-sdk/src/ExternalEthCall.sol \ No newline at end of file diff --git a/docs/precompiles/src/ExternalEthGetLogs.sol b/docs/precompiles/src/ExternalEthGetLogs.sol new file mode 120000 index 00000000..746064c9 --- /dev/null +++ b/docs/precompiles/src/ExternalEthGetLogs.sol @@ -0,0 +1 @@ +../../../solidity-sdk/src/ExternalEthGetLogs.sol \ No newline at end of file diff --git a/docs/precompiles/src/Quorum.sol b/docs/precompiles/src/Quorum.sol new file mode 120000 index 00000000..6734df93 --- /dev/null +++ b/docs/precompiles/src/Quorum.sol @@ -0,0 +1 @@ +../../../solidity-sdk/src/Quorum.sol \ No newline at end of file diff --git a/docs/precompiles/src/Time.sol b/docs/precompiles/src/Time.sol new file mode 120000 index 00000000..9fbaf982 --- /dev/null +++ b/docs/precompiles/src/Time.sol @@ -0,0 +1 @@ +../../../solidity-sdk/src/Time.sol \ No newline at end of file diff --git a/docs/precompiles/timestamp.md b/docs/precompiles/timestamp.md new file mode 100644 index 00000000..2e6f0496 --- /dev/null +++ b/docs/precompiles/timestamp.md @@ -0,0 +1,51 @@ +--- +layout: simple +--- + +! content id="timestamp" + +! anchor timestamp go-up +## Timestamp + +Fetches the current system timestamp as microseconds since the UNIX epoch. + +### Address + +0x423Bb123D9d5143e662606Fd343b6766d7BCf721 + + +### Inputs + +None. + +### Output + +! table style1 +| Byte range | Name | Description | +| ------------------ | --------- | ---------------------------------------------------------- | +| [0; 31] (32 bytes) | timestamp | `uint128` microsecond timestamp, right aligned to 32 bytes | +! table end + +### Errors + +- Out of gas if provided gas is less than base cost. +- "time before unix epoch" if the system time is earlier than the UNIX epoch. + +### Gas Cost + +Static gas: 100 + +! content end + + +! content +! sticky + +### Example + +! codeblock title="solidity-sdk/src/Time.sol" +! codeblock import solidity "./src/Time.sol" lines="6-7,30-38" +! codeblock end + +! sticky end +! content end \ No newline at end of file diff --git a/docs/precompiles/txInfo.md b/docs/precompiles/txInfo.md new file mode 100644 index 00000000..977a6033 --- /dev/null +++ b/docs/precompiles/txInfo.md @@ -0,0 +1,55 @@ +--- +layout: simple +--- + +! content id="txInfo" + +! anchor txInfo go-up +## Transaction Information + +Fetches information about the current transaction. +Current implementation provides: +- nonce +- transaction hash + +### Address + +0x7687A3413739715807812b529f2d5f7Ef9057697 + +### Inputs + +None. + +### Output + +! table style1 +| Byte range | Name | Description | +| ------------------ | --------- | ------------------------------------------ | +| [0; 31] (32 bytes) | nonce | `uint64` transaction nonce, right aligned | +| [32; 63] (32 bytes)| txHash | transaction hash | +! table end + +> Note: If the precompile is used in a call, txHash is 0x00 + +### Errors + +- Out of gas if provided gas is less than base cost. + +### Gas Cost + +Static gas: 100 + +! content end + + +! content +! sticky + +### Example + +! codeblock title="solidity-sdk/src/Context.sol" +! codeblock import solidity "./src/Context.sol" lines="4-5,11-15,20-30" +! codeblock end + +! sticky end +! content end \ No newline at end of file diff --git a/docs/rust-sdk/content.md b/docs/rust-sdk/content.md deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/rust-sdk/getting-started/content.md b/docs/rust-sdk/getting-started/content.md deleted file mode 100644 index 652d4bfe..00000000 --- a/docs/rust-sdk/getting-started/content.md +++ /dev/null @@ -1,81 +0,0 @@ ---- -title: Getting started with pod Rust SDK -layout: simple - -url: /rust-sdk/getting-started - -toc: -installation: Installation -basic-usage: Basic Usage ---- - -! content id="installation" - -## Getting Started - -### Installation - -To begin using the pod Rust SDK, add the following dependency to your project's `Cargo.toml` - -! content end - -! content - -! sticky - -! codeblock title="Cargo.toml" - -```toml -[dependencies] -pod-sdk = "0.1.0" -``` - -! codeblock end - -! sticky end - -! content end - -! content - -### Basic Usage - -! anchor basic-usage - -Here's a simple example demonstrating how to initialize the client and perform basic operations. - -! content end - -! content - -! sticky - -! codeblock title="Example" - -```rust -use pod_sdk::provider; -use alloy_primitives::B256; - -#[tokio::main] -async fn main() -> Result<(), Box> { - let ws_url = Url::parse("ws://127.0.0.1:8545")?; - let ws = WsConnect::new(ws_url); - - let pod_client = provider::PodProviderBuilder::new() - .on_ws(ws) - .await?; - - // Get transaction by hash - let tx_hash = B256::from_str("0x...")?; - // Get transaction without attestations - let tx = pod_client.get_transaction_by_hash(&tx_hash).await?; - - Ok(()) -} -``` - -! codeblock end - -! sticky end - -! content end diff --git a/docs/rust-sdk/guides/content.md b/docs/rust-sdk/guides/content.md deleted file mode 100644 index f063aea4..00000000 --- a/docs/rust-sdk/guides/content.md +++ /dev/null @@ -1,129 +0,0 @@ ---- -title: Rust SDK Guides -layout: single - -url: /rust-sdk/guides - -toc: - sending-transactions: Sending Transactions - retrieving-transactions: Retrieving Transactions - retrieving-transaction-receipts: Retrieving Transaction Receipts ---- - -! anchor sending-transactions - -### Sending Transactions - -In order to submit a fund transfer transaction to the network, please follow the script. - -! codeblock title="Example" - -```rust -#[tokio::main] -async fn main() -> Result<()> { - let ws_url = Url::parse("ws://127.0.0.1:8545")?; - let ws = WsConnect::new(ws_url); - - let private_key_bytes = - <[u8; 32]>::from_hex("abc...")?; /// Your Private key - let field_bytes = FieldBytes::from_slice(&private_key_bytes); - let signing_key = SigningKey::from_bytes(field_bytes)?; - let signer = PrivateKeySigner::from(signing_key); - let wallet = EthereumWallet::new(signer); - - let pod_provider = provider::PodProviderBuilder::new() - .wallet(wallet) - .on_ws(ws) - .await?; - - let tx = TxLegacy { - chain_id: Some(1293), - nonce: 0, - gas_price: 20_000_000_000, - gas_limit: 21_000, - to: TxKind::Call(Address::from_str("0x742d35Cc6634C0532925a3b844Bc454e4438f44e").unwrap()), - value: U256::from(1000000000000000000u64), - input: Bytes::default(), - }; - - let pending_tx = pod_provider.send_transaction(tx.into()).await?; - let receipt = pending_tx.get_receipt().await?; - - println!("receipt: {:?}", receipt); -} -``` - -! codeblock end - ---- - -! anchor retrieving-transactions - -### Retrieving Transactions - -As shown in the introductory section, the transaction can be retrieved by hash as - -! codeblock title="Example" - -```rust -use pod_sdk::provider; -use alloy_primitives::B256; - -#[tokio::main] -async fn main() -> Result<(), Box> { - let ws_url = Url::parse("ws://127.0.0.1:8545")?; - let ws = WsConnect::new(ws_url); - - let pod_client = provider::PodProviderBuilder::new() - .on_ws(ws) - .await?; - - // Get transaction by hash - let tx_hash = B256::from_str("0x...")?; - // Get transaction without attestations - let tx = pod_client.get_transaction_by_hash(&tx_hash).await?; - - Ok(()) -} -``` - -! codeblock end - -This method returns the transaction details along with pod-specific certificate information. - ---- - -! anchor retrieving-transaction-receipts - -### Retrieving Transaction Receipts - -To obtain the transaction receipt with Pod-specific metadata and verify whether the signatures have passed the quorum threshold. For a pending transaction the receipt can be obtained as - -! codeblock title="Example" - -```rust -let pending_tx = pod_provider.send_transaction(tx.into()).await?; -let receipt = pending_tx.get_receipt().await?; /// Wait for the transaction to be finalized -``` - -! codeblock end - -If you need to obtain the transaction by the transaction hash, you can do it as follows - -! codeblock - -```rust -// Replace with your transaction hash -let tx_hash: B256 = "0xabc...".parse()?; - -// Fetch the transaction receipt -let receipt = pod_provider.get_transaction_receipt(tx_hash).await?; - -// Handle the result -match receipt { - Some(receipt) => println!("Transaction Receipt: {:?}", receipt), - None => println!("Transaction not mined yet or invalid hash."), -} -``` - -! codeblock end diff --git a/docs/rust-sdk/overview/basic-usage.md b/docs/rust-sdk/overview/basic-usage.md deleted file mode 100644 index 945ea445..00000000 --- a/docs/rust-sdk/overview/basic-usage.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -layout: simple ---- - -! content - -### Basic Usage - -! anchor basic-usage - -Here's a simple example demonstrating how to initialize the client and perform basic operations. - -! content end - -! content - -! sticky - -! codeblock title="Example" - -```rust -use pod_sdk::provider; -use alloy_primitives::B256; - -#[tokio::main] -async fn main() -> Result<(), Box> { - let ws_url = Url::parse("ws://127.0.0.1:8545")?; -``` - -! codeblock end - -! sticky end - -! content end diff --git a/docs/rust-sdk/overview/coming-from-alloy.md b/docs/rust-sdk/overview/coming-from-alloy.md deleted file mode 100644 index 76251a1e..00000000 --- a/docs/rust-sdk/overview/coming-from-alloy.md +++ /dev/null @@ -1,71 +0,0 @@ ---- -layout: simple ---- - -! content id="coming-from-alloy" - -## Coming from alloy - -pod Rust SDK is built on top of alloy. Therefore, alloy could be used to interact with the pod -network, however, this is not recommended, as the pod SDK provides additional essential -functionality such as `wait_past_perfect_time`, which integrate pod-specific features. Additionally, -using alloy directly may lead to unexpected behavior when waiting for transaction confirmations or -fetching blocks. - -The main different between using pod-sdk and alloy is that pod has its own ProviderBuilder, called -`PodProviderBuilder`. The rest of the API remains the same, as it's illustrated in the example. - -! content end - -! content - -! sticky - -! codeblock title="Send transaction with pod-sdk" - -```rust -#[tokio::main] -async fn main() -> Result<()> { - // Initialize a wallet - alloy compatible - let private_key_bytes = <[u8; 32]>::from_hex("abc...")?; - let field_bytes = FieldBytes::from_slice(&private_key_bytes); - let signing_key = SigningKey::from_bytes(field_bytes)?; - let signer = PrivateKeySigner::from(signing_key); - let wallet = EthereumWallet::new(signer); - - let ws_url = Url::parse("ws://rpc.v1.dev.pod.network:8545")?; - let ws = WsConnect::new(ws_url); - // Instantiate a provider - // Use pod-specific Provider instead of use alloy::providers::ProviderBuilder - let pod_provider = provider::PodProviderBuilder::new() - .wallet(wallet) - .on_ws(ws) - .await?; - - // Send transaction - // Use alloy structs - let tx = TxLegacy { - chain_id: Some(1293), - nonce: 0, - gas_price: 20_000_000_000, - gas_limit: 21_000, - to: TxKind::Call(Address::from_str("0x70997970C51812dc3A010C7d01b50e0d17dc79C8").unwrap()), - value: U256::from(1000000000000000000u64), - input: Bytes::default(), - }; - // Use send_transaction - alloy compatible - let pending_tx = pod_provider.send_transaction(tx.into()).await?; - - // Get receipt - alloy compatible - let receipt = pending_tx.get_receipt().await?; - println!("receipt: {:?}", receipt); - - Ok(()) -} -``` - -! codeblock end - -! sticky end - -! content end \ No newline at end of file diff --git a/docs/rust-sdk/overview/content.md b/docs/rust-sdk/overview/content.md deleted file mode 100644 index 68f2d905..00000000 --- a/docs/rust-sdk/overview/content.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: Rust SDK Overview -layout: blank - -url: /rust-sdk/overview - -toc: -introduction: Introduction -getting-started: Getting started -coming-from-alloy: Coming from alloy -provider: PodProvider -error-handling: Error Handling ---- - -! import ./intro.md - ---- - -! import ./installation.md - ---- - -! import ./basic-usage.md - ---- - -! import ./coming-from-alloy.md - ---- - -! import ./rest.md - - diff --git a/docs/rust-sdk/overview/installation.md b/docs/rust-sdk/overview/installation.md deleted file mode 100644 index 4707a6e0..00000000 --- a/docs/rust-sdk/overview/installation.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -layout: simple ---- - -! content id="installation" - -## Getting Started - -### Installation - -To begin using the pod Rust SDK, add the following dependency to your project's `Cargo.toml` - -! content end - -! content - -! sticky - -! codeblock title="Cargo.toml" - -```toml -[dependencies] -pod-sdk = "0.1.0" -``` - -! codeblock end - -! sticky end - -! content end \ No newline at end of file diff --git a/docs/rust-sdk/overview/intro.md b/docs/rust-sdk/overview/intro.md deleted file mode 100644 index 4498a396..00000000 --- a/docs/rust-sdk/overview/intro.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -layout: single ---- - -! anchor introduction - -# pod Rust SDK - -Rust library for interacting with pod. - -## Introduction - -The pod Rust SDK provides a robust interface for interacting with the pod network through its [JSON-RPC API](/reference/rpc-api). This SDK enables developers to communicate with pod nodes, manage transactions, and handle network responses in a type-safe manner. The SDK includes comprehensive error handling, serialization management, and strongly-typed responses for pod-specific features. \ No newline at end of file diff --git a/docs/rust-sdk/overview/rest.md b/docs/rust-sdk/overview/rest.md deleted file mode 100644 index a76ce8ba..00000000 --- a/docs/rust-sdk/overview/rest.md +++ /dev/null @@ -1,47 +0,0 @@ ---- -layout: single ---- - -## PodProvider - -! anchor provider - -The PodProvider serves as the primary interface for interacting with the Pod network. It manages RPC communication and provides methods for executing common operations. PodProvider is built on top of the Alloy Provider trait, making most of its methods Alloy-compatible. - ---- - -### Initialization - -Create a new PodProvider instance by using PodProviderBuilder and passing your url. - -! codeblock title="Example" - -```rust -let ws_url = Url::parse("ws://127.0.0.1:8545")?; -let ws = WsConnect::new(ws_url); -let pod_client = provider::PodProviderBuilder::new().on_ws(ws).await?; -``` - -! codeblock end - -The same procedure can be repeated for http endpoint - -! codeblock title="Example" - -```rust -let rpc_url = "http://127.0.0.1:8545".parse()?; -let pod_client = provider::ProviderBuilder::new().on_http(rpc_url).await?; -``` - -! codeblock end - ---- - -! anchor error-handling - -## Error Handling - -The error handling is identical to the Alloy error handling framework: - -- [alloy rs: event errors](https://github.com/alloy-rs/examples/blob/main/examples/sol-macro/examples/events_errors.rs) -- [alloy rs: jsonrpc error decoding](https://github.com/alloy-rs/examples/blob/main/examples/contracts/examples/jsonrpc_error_decoding.rs) \ No newline at end of file diff --git a/docs/solidity-sdk/content.md b/docs/solidity-sdk/content.md index 9f56897a..df8fae78 100644 --- a/docs/solidity-sdk/content.md +++ b/docs/solidity-sdk/content.md @@ -1,186 +1,33 @@ --- -title: Solidity SDK Reference -layout: single +title: Solidity SDK +layout: blank -url: /solidity-sdk/reference +url: /solidity-sdk toc: - shared-counter: SharedCounter - owned-counter: OwnedCounter - balance: Balance - uint256-set: Uint256Set - address-set: AddressSet - require-time-before: requireTimeBefore - require-time-after: requireTimeAfter + quorum: requireQuorum + external-call: ExternalEthCall + context: Context --- -# Solidity SDK Reference - -The Solidity SDK is available at the pod-sdk [github repository](https://github.com/podnetwork/pod-sdk.git). - -For example, to install with forge use: - -```bash - $ forge install podnetwork/pod-sdk -``` - -! anchor fast-types - -## Fast types - -The `FastTypes` library provides coordination-free data structures through precompiled contracts. All operations are designed to be commutative and safe under pod's consensus model which avoids coordination between the validators. - -A smart contract written for pod must not depend on the order of transactions arriving to a validator, otherwise there may be inconsistencies between validators, which may lead to safety issues or a correct transaction to not be approved. However, if a smart contract is written to use only types from `FastTypes` as storage, then it is guaranteed to be safe despite lack of coordination. - -To use the library, import the necessary types from `pod-sdk/FastTypes.sol`: - -```solidity -import {SharedCounter} from "pod-sdk/FastTypes.sol"; -``` +! import ./overview.md --- -! anchor owned-counter - -### OwnedCounter - -A collection of owned `uint256` values. It can be considered as one `bytes32 => uint256` mapping for each transaction sender. Functions revert if a sender is trying to manipulate the value owned by another address. - -**Functions** - - * **set(address owner, bytes32 key, uint256 value)**: Set counter to `value`. Ignores previous values. - * **increment(address owner, bytes32 key, uint256 value)**: Increment counter owned by `owner`, by `value`. - * **decrement(address owner, bytes32 key, uint256 value)**: Decrement counter owned by `owner` by `value`. - * **get(address owner, bytes32 key)**: Retrieve value of counter. - -All functions revert if `tx.origin` does not equal `owner`. The `key` allows for every owner to have multiple values. The same key on different owners refers to different values. - -**Why is OwnedCounter coordination-free?** If two transactions were sent by different users then they cannot access the same key, and if they were sent by the same user they are already ordered by the account nonce. +! import ./fast-types.md --- -! anchor shared-counter - -### SharedCounter - -Shared monotonically increasing values that support increment and threshold checking operations. - -**Functions** - - * **increment(bytes32 key, uint256 value)**: Increase counter named `key` by `value`. - * **requireGte(bytes32 key, uint256 value, string errorMessage)**: Revert if counter named `key` is less than `value`. - -**Why is SharedCounter coordination-free?** While the SharedCounter allows transactions by different users to affect the same memory, it does not matter in which order the increments happen: if `reguireGte` is true for one validator it will remain true forever and will eventually be true for all other validators as well. Importantly, the shared counter does *not* allow decreasing the counter, or checking if it is smaller than some value (eg. reguireLte), because both would violate this principle. +! import ./time.md --- -! anchor balance - -### Balance - -A collection of `uint256` values, where every sender can decrement (spend) his value, but anyone can increment (debit) anyone else's value. This is a basic building block for building any kind of token balances. It does *not* enforce that incrementing value of one address must decrement some amount from another address. - -**Functions** - - * **increment(address owner, bytes32 key, uint256 value)** Increase the balance of `owner` for `key` by `value`. Anyone can call. - * **decrement(address owner, bytes32 key, uint256 value)** Decrease balance of `owner` for `key` by value. Only owner can call. - * **requireGte(address owner, bytes32 key, string errorMessage)** Require that the balance of `owner` for `key` is at least `value`. Only owner can call. - -See [Tokens](/examples/tokens) or [NFTs](/examples/nfts) for examples using the `Balance` type. - -**Why is Balance coordination-free?** It is essentially a combination of SharedCounter and OwnedCounter. +! import ./quorum.md --- -! anchor uint256-set - -### Uint256Set - -Shared collection of uint256 values. - -**Functions** - - * **add(uint256 value)** Add a value to the set. - * **requireExists(uint256 value, string error)** Revert if `value` not in the set. - * **requireLengthGte(uint256 length, string error)** Revert if size of set less than `length`. - * **requireMaxValueGte(uint256 value, string error)** Revert if maximum value in set less than `value`. - -**Why is Uint256Set coordination-free?** A set with `add` and `exists` operations is the most typical CRDT operation. It does not matter in which order elements are added to a set. However, removing elements is non-monotonic and requires coordination. Instead, deletion can be implemented by having a second set, the set of all deleted values. +! import ./external-call.md --- -! anchor address-set - -### AddressSet - -Shared collection of addresses. - -**Functions** - - * **add(address addr)** Add address to the set. - * **requireExists(address addr, string error)** Revert if address is not in the set. - * **requireLengthGte(uint256 length, string error)** Revert if set does not contain at least `length` addresses. - ---- - -! anchor time - -## Time - -The `Time` package provides utilities for working with time on pod. These utilities work by accessing the local time on each validator, which depends on the time that they first see a transaction. - -They ensure that a supermajority of the validators agree on a statement (for example, that the transaction was sent before (or after) a certain time. They also ensure that even if some small minority of validators did not see the transaction in time but later (for example, due to connectivity issues), they will still accept the transaction and execute the same code as the supermajority. - -To use, import `requireTimeAfter` or `requireTimeBefore` from `pod-sdk/Time.sol`: - -```solidity -import {requireTimeAfter, requireTimeBefore} from "pod-sdk/Time.sol"; -``` - ---- - -! anchor require-time-before - -### requireTimeBefore - -```solidity -function requireTimeBefore(uint256 timestamp, string memory message) view -``` - -Requires that the current timestamp is before the specified time. - -**Parameters:** -- `timestamp`: Unix timestamp that must be in the future -- `message`: Error message if validation fails - -**Behavior:** -- Validates that the current timestamp is less than the specified timestamp -- Uses validators' local timestamps - each validator has a different local time -- Ensures a supermajority of validators saw the transaction before the required time -- Reverts with the provided message if condition fails -- Accounts for validator clock differences across the network - -See [Auctions](/examples/auctions) for an example that uses `requireTimeBefore`. - ---- - -! anchor require-time-after - -### requireTimeAfter - -```solidity -function requireTimeAfter(uint256 timestamp, string memory message) view -``` - -Requires that the current timestamp is after the specified time. - -**Parameters:** -- `timestamp`: Unix timestamp that must be in the past -- `message`: Error message if validation fails - -**Behavior:** -- Validates that the current timestamp is greater than the specified timestamp -- Uses validators' local timestamps - each validator has a different local time -- Ensures a supermajority of validators saw the transaction after the required time -- Reverts with the provided message if condition fails -- Accounts for validator clock differences across the network +! import ./context.md \ No newline at end of file diff --git a/docs/solidity-sdk/context.md b/docs/solidity-sdk/context.md new file mode 100644 index 00000000..2e123a5b --- /dev/null +++ b/docs/solidity-sdk/context.md @@ -0,0 +1,57 @@ +--- +title: Context +layout: simple + +url: /solidity-sdk/context + +toc: + functions: Available Functions + gettxinfo: getTxInfo +--- + +! content id="solidity-context" + +! anchor context +## Context + +Utility to access pod's context information. + +To use, import from `pod-sdk/Context.sol`: + +```solidity +import {TxInfo, getTxInfo} from "pod-sdk/Context.sol"; +``` + +### Functions +* **getTxInfo()** Get current transaction info. + + +! anchor gettxinfo go-up=context +### getTxInfo + +Provides a lightweight interface to a precompile that exposes the current transaction's nonce and hash (as a TxInfo struct). This is useful for logging, replay protection logic, or deriving per-transaction identifiers. +Reverts if the precompile call fails or the return payload is not well-formed. + +! codeblock +! codeblock import solidity "./src/Context.sol" lines=6-15,20 +! codeblock end + +! content end + + +! content +! sticky + +### Example + +```solidity +import {TxInfo, getTxInfo} from "pod-sdk/Context.sol"; + +function currentTxHash() view returns (bytes32) { + TxInfo memory info = getTxInfo(); + return info.txHash; +} +``` + +! sticky end +! content end \ No newline at end of file diff --git a/docs/solidity-sdk/external-call.md b/docs/solidity-sdk/external-call.md new file mode 100644 index 00000000..ee6620c0 --- /dev/null +++ b/docs/solidity-sdk/external-call.md @@ -0,0 +1,67 @@ +--- +title: ExternalEthCall +layout: simple + +url: /solidity-sdk/external-call + +toc: + functions: Available Functions + external-eth-call: externalEthCall +--- + +! content id="solidity-external-call" + +! anchor external-call +## ExternalEthCall + +Call external Ethereum contracts from pod using a precompile. This utility takes an Ethereum-like transaction, forwards it to the configured chain, and returns the calldata result if successful. + +To use, import the items from `pod-sdk/ExternalEthCall.sol`: + +```solidity +import {externalEthCall, Transaction, EthCallArgs} from "pod-sdk/ExternalEthCall.sol"; +``` + +### Functions +* **externalEthCall(uint256 chainId, EthCallArgs memory callArgs)** Performs an eth_call request on an external EVM compatible chain. + + +! anchor external-eth-call go-up=external-call +### externalEthCall + +Executes a read-only call to a contract on an external Ethereum network and returns the raw return data. + +**Parameters:** +- `chainId`: Chain ID of the target Ethereum network (e.g., 1 for Mainnet). +- `callArgs`: The `EthCallArgs` payload with transaction and block context. + +**Behavior:** +- Forwards the call via a pod precompile to the specified network. +- Reverts if the precompile call fails or the external call is unsuccessful. +- Returns the returned bytes from the external call on success. + + +#### Types +- **Transaction**: Describes the Ethereum call parameters. +- **EthCallArgs**: Wraps a `Transaction` with the block number context. + +! codeblock +! codeblock import solidity "./src/ExternalEthCall.sol" lines=6-33,40 +! codeblock end + +! content end + + +! content +! sticky + +### Example + +This example uses the POD_EXTERNAL_ETH_CALL precompile to run an eth_call on Ethereum mainnet, returning the USDC balance for a given account. + +! codeblock title="examples/solidity/src/EthereumERC20Balance.sol" +! codeblock import solidity "./src/EthereumERC20Balance.sol" +! codeblock end + +! sticky end +! content end \ No newline at end of file diff --git a/docs/solidity-sdk/fast-types.md b/docs/solidity-sdk/fast-types.md new file mode 100644 index 00000000..e95ff9ba --- /dev/null +++ b/docs/solidity-sdk/fast-types.md @@ -0,0 +1,104 @@ +--- +title: FastTypes +layout: single + +url: /solidity-sdk/fast-types + +toc: + owned-counter: OwnedCounter + shared-counter: SharedCounter + balance: Balance + uint256-set: Uint256Set + address-set: AddressSet +--- + +! anchor fast-types +## FastTypes + +The `FastTypes` library provides coordination-free data structures through precompiled contracts. All operations are designed to be commutative and safe under pod's consensus model which avoids coordination between the validators. + +A smart contract written for pod must not depend on the order of transactions arriving to a validator, otherwise there may be inconsistencies between validators, which may lead to safety issues or a correct transaction to not be approved. However, if a smart contract is written to use only types from `FastTypes` as storage, then it is guaranteed to be safe despite lack of coordination. + +To use the library, import the necessary types from `pod-sdk/FastTypes.sol`: + +```solidity +import {SharedCounter} from "pod-sdk/FastTypes.sol"; +``` + +--- + +! anchor owned-counter go-up=fast-types +### OwnedCounter + +A collection of owned `uint256` values. It can be considered as one `bytes32 => uint256` mapping for each transaction sender. Functions revert if a sender is trying to manipulate the value owned by another address. + +**Functions** + + * **set(address owner, bytes32 key, uint256 value)**: Set counter to `value`. Ignores previous values. + * **increment(address owner, bytes32 key, uint256 value)**: Increment counter owned by `owner`, by `value`. + * **decrement(address owner, bytes32 key, uint256 value)**: Decrement counter owned by `owner` by `value`. + * **get(address owner, bytes32 key)**: Retrieve value of counter. + +All functions revert if `tx.origin` does not equal `owner`. The `key` allows for every owner to have multiple values. The same key on different owners refers to different values. + +**Why is OwnedCounter coordination-free?** If two transactions were sent by different users then they cannot access the same key, and if they were sent by the same user they are already ordered by the account nonce. + +--- + +! anchor shared-counter go-up=fast-types +### SharedCounter + +Shared monotonically increasing values that support increment and threshold checking operations. + +**Functions** + + * **increment(bytes32 key, uint256 value)**: Increase counter named `key` by `value`. + * **requireGte(bytes32 key, uint256 value, string errorMessage)**: Revert if counter named `key` is less than `value`. + +**Why is SharedCounter coordination-free?** While the SharedCounter allows transactions by different users to affect the same memory, it does not matter in which order the increments happen: if `reguireGte` is true for one validator it will remain true forever and will eventually be true for all other validators as well. Importantly, the shared counter does *not* allow decreasing the counter, or checking if it is smaller than some value (eg. reguireLte), because both would violate this principle. + +--- + +! anchor balance go-up=fast-types +### Balance + +A collection of `uint256` values, where every sender can decrement (spend) his value, but anyone can increment (debit) anyone else's value. This is a basic building block for building any kind of token balances. It does *not* enforce that incrementing value of one address must decrement some amount from another address. + +**Functions** + + * **increment(address owner, bytes32 key, uint256 value)** Increase the balance of `owner` for `key` by `value`. Anyone can call. + * **decrement(address owner, bytes32 key, uint256 value)** Decrease balance of `owner` for `key` by value. Only owner can call. + * **requireGte(address owner, bytes32 key, string errorMessage)** Require that the balance of `owner` for `key` is at least `value`. Only owner can call. + +See [Tokens](/examples/tokens) or [NFTs](/examples/nfts) for examples using the `Balance` type. + +**Why is Balance coordination-free?** It is essentially a combination of SharedCounter and OwnedCounter. + +--- + +! anchor uint256-set go-up=fast-types +### Uint256Set + +Shared collection of uint256 values. + +**Functions** + + * **add(uint256 value)** Add a value to the set. + * **requireExists(uint256 value, string error)** Revert if `value` not in the set. + * **requireLengthGte(uint256 length, string error)** Revert if size of set less than `length`. + * **requireMaxValueGte(uint256 value, string error)** Revert if maximum value in set less than `value`. + +**Why is Uint256Set coordination-free?** A set with `add` and `exists` operations is the most typical CRDT operation. It does not matter in which order elements are added to a set. However, removing elements is non-monotonic and requires coordination. Instead, deletion can be implemented by having a second set, the set of all deleted values. + +--- + +! anchor address-set go-up=fast-types +### AddressSet + +Shared collection of addresses. + +**Functions** + + * **add(address addr)** Add address to the set. + * **requireExists(address addr, string error)** Revert if address is not in the set. + * **requireLengthGte(uint256 length, string error)** Revert if set does not contain at least `length` addresses. diff --git a/docs/solidity-sdk/overview.md b/docs/solidity-sdk/overview.md new file mode 100644 index 00000000..6643f909 --- /dev/null +++ b/docs/solidity-sdk/overview.md @@ -0,0 +1,14 @@ +--- +layout: single +--- + +! anchor solidity-sdk-overview +# Solidity SDK Reference + +The Solidity SDK is available at the pod-sdk [github repository](https://github.com/podnetwork/pod-sdk.git). + +For example, to install with forge use: + +```bash + $ forge install podnetwork/pod-sdk +``` \ No newline at end of file diff --git a/docs/solidity-sdk/quorum.md b/docs/solidity-sdk/quorum.md new file mode 100644 index 00000000..7c8ce4da --- /dev/null +++ b/docs/solidity-sdk/quorum.md @@ -0,0 +1,84 @@ +--- +title: requireQuorum +layout: simple + +url: /solidity-sdk/quorum + +toc: + functions: Available Functions + usage: Usage + testing: Testing +--- + +! content id="solidity-quorum" + +! anchor quorum +## requireQuorum + +Validator-quorum guard for coordination-free checks. This function routes a boolean condition to a pod precompile that enforces supermajority agreement among validators. If the quorum is not met, the call reverts with the provided error message. + +To use, import from `pod-sdk/Quorum.sol`: + +```solidity +import {requireQuorum} from "pod-sdk/Quorum.sol"; +``` + +### Functions +* **requireQuorum(bool input, string memory message)** evaluates a condition under pod's consensus rules. + + +! anchor require-quorum go-up=quorum +#### requireQuorum + +`requireQuorum` evaluates a condition under pod's consensus rules: + +- If a supermajority of validators agree the condition is true, the call proceeds. +- If the condition is false (or quorum is not met), execution reverts with `message`. + +This allows application-level assertions (e.g., time guards, counters, membership checks) to be validated consistently across validators without explicit coordination. + +```solidity +function requireQuorum(bool input, string memory message) view; +``` + +Use `requireQuorum` anywhere you would normally use `require`, but where correctness depends on validator agreement rather than a single local state check. Typical examples include: + +- Time assertions (see [requireTimeAfter](/solidity-sdk#requireTimeAfter), [requireTimeBefore](/solidity-sdk#requireTimeBefore)). +- Monotonic data structure checks (see [FastTypes.SharedCounter.requireGte](/solidity-sdk#shared-counter)). + + +! anchor testing go-up=quorum +### Testing + +When testing with Foundry, you can mock the quorum precompile using the helper from `pod-sdk/src/test/podTest.sol`: + +```solidity +import {PodTest} from "pod-sdk/src/test/podTest.sol"; +import {requireQuorum} from "pod-sdk/Quorum.sol"; + +contract MyTest is PodTest { + function test_guard() public { + podMockQuorum(); // sets up REQUIRE_QUORUM behavior + requireQuorum(true, "should pass"); // succeeds + } +} +``` + +! content end + + +! content +! sticky + +### Example + +The example contract shows a balance-gated action: +- In Round 1, validators check if the caller has at least 1 ether. +- In Round 2, after quorum attestations are collected, the action can be executed without rechecking the balance. + +! codeblock title="examples/solidity/src/QuorumRestrictedAction.sol" +! codeblock import solidity "./src/QuorumRestrictedAction.sol" +! codeblock end + +! sticky end +! content end \ No newline at end of file diff --git a/docs/solidity-sdk/src/Context.sol b/docs/solidity-sdk/src/Context.sol new file mode 120000 index 00000000..37295c4e --- /dev/null +++ b/docs/solidity-sdk/src/Context.sol @@ -0,0 +1 @@ +../../../solidity-sdk/src/Context.sol \ No newline at end of file diff --git a/docs/solidity-sdk/src/EthereumERC20Balance.sol b/docs/solidity-sdk/src/EthereumERC20Balance.sol new file mode 120000 index 00000000..e532dcea --- /dev/null +++ b/docs/solidity-sdk/src/EthereumERC20Balance.sol @@ -0,0 +1 @@ +../../../examples/solidity/src/EthereumERC20Balance.sol \ No newline at end of file diff --git a/docs/solidity-sdk/src/ExternalEthCall.sol b/docs/solidity-sdk/src/ExternalEthCall.sol new file mode 120000 index 00000000..43e148f9 --- /dev/null +++ b/docs/solidity-sdk/src/ExternalEthCall.sol @@ -0,0 +1 @@ +../../../solidity-sdk/src/ExternalEthCall.sol \ No newline at end of file diff --git a/docs/solidity-sdk/src/QuorumRestrictedAction.sol b/docs/solidity-sdk/src/QuorumRestrictedAction.sol new file mode 120000 index 00000000..18dde660 --- /dev/null +++ b/docs/solidity-sdk/src/QuorumRestrictedAction.sol @@ -0,0 +1 @@ +../../../examples/solidity/src/QuorumRestrictedAction.sol \ No newline at end of file diff --git a/docs/solidity-sdk/time.md b/docs/solidity-sdk/time.md new file mode 100644 index 00000000..b118550f --- /dev/null +++ b/docs/solidity-sdk/time.md @@ -0,0 +1,167 @@ +--- +title: Time library +layout: single + +url: /solidity-sdk/time + +toc: + functions: Available Functions + requireTimeBefore: requireTimeBefore + requireTimeAfter: requireTimeAfter + requireTimeAtLeast: requireTimeAtLeast + requireTimeAtMost: requireTimeAtMost +--- + + +! anchor time +## Time + +The `Time` package provides utilities for working with time on pod. These utilities work by accessing the local time on each validator, which depends on the time that they first see a transaction. + +They ensure that a supermajority of the validators agree on a statement (for example, that the transaction was sent before (or after) a certain time. They also ensure that even if some small minority of validators did not see the transaction in time but later (for example, due to connectivity issues), they will still accept the transaction and execute the same code as the supermajority. + +Timestamps in this package use microseconds and are represented by the `Time.Timestamp` type. Obtain one with `Time.currentTime()` or construct with `Time.fromSeconds`, `Time.fromMillis`, or `Time.fromMicros`. + +To use the library, import `Time` (and optionally the time guards) from `pod-sdk/Time.sol`: + +```solidity +import {Time, requireTimeAfter, requireTimeAtLeast, requireTimeBefore, requireTimeAtMost} from "pod-sdk/Time.sol"; +``` + +Add the `using ... for ...` directive to enable method-style usage on `Time.Timestamp`: + +```solidity +using Time for Time.Timestamp; + +Time.Timestamp ts = Time.currentTime(); +bool isZero = ts.isZero(); +``` + +! anchor functions go-up=time +### Functions + + * **currentTime()**: Get current timestamp in microseconds as `Time.Timestamp`. + * **min()**: Minimum possible `Time.Timestamp` value. + * **max()**: Maximum possible `Time.Timestamp` value. + * **isZero(Time.Timestamp timestamp)**: Return true if `timestamp` is zero. + * **fromSeconds(uint64 seconds_)**: Create `Time.Timestamp` from seconds. + * **fromMillis(uint64 milliseconds)**: Create `Time.Timestamp` from milliseconds. + * **fromMicros(uint64 microseconds)**: Create `Time.Timestamp` from microseconds. + * **toSeconds(Time.Timestamp timestamp)**: Convert to whole seconds (truncates microseconds). + * **addSeconds(Time.Timestamp timestamp, uint64 seconds_)**: Add seconds to a timestamp. + * **addMillis(Time.Timestamp timestamp, uint64 milliseconds)**: Add milliseconds to a timestamp. + * **addMicros(Time.Timestamp timestamp, uint64 microseconds)**: Add microseconds to a timestamp. + * **subSeconds(Time.Timestamp timestamp, uint64 seconds_)**: Subtract seconds (reverts on underflow). + * **subMillis(Time.Timestamp timestamp, uint64 milliseconds)**: Subtract milliseconds (reverts on underflow). + * **subMicros(Time.Timestamp timestamp, uint64 microseconds)**: Subtract microseconds (reverts on underflow). + * **eq(Time.Timestamp a, Time.Timestamp b)**: Return true if timestamps are equal. + * **gt(Time.Timestamp a, Time.Timestamp b)**: Return true if `a` is greater than `b`. + * **lt(Time.Timestamp a, Time.Timestamp b)**: Return true if `a` is less than `b`. + * **gte(Time.Timestamp a, Time.Timestamp b)**: Return true if `a` is greater than or equal to `b`. + * **lte(Time.Timestamp a, Time.Timestamp b)**: Return true if `a` is less than or equal to `b`. + * **between(Time.Timestamp timestamp, Time.Timestamp lower, Time.Timestamp upper)**: Return true if within `[lower, upper]` (reverts if `lower > upper`). + * **diffMicros(Time.Timestamp a, Time.Timestamp b)**: Absolute difference in microseconds. + * **diffMillis(Time.Timestamp a, Time.Timestamp b)**: Absolute difference in milliseconds. + * **diffSeconds(Time.Timestamp a, Time.Timestamp b)**: Absolute difference in seconds. + * **min(Time.Timestamp a, Time.Timestamp b)**: Smaller of two timestamps. + * **max(Time.Timestamp a, Time.Timestamp b)**: Larger of two timestamps. + +--- + +### Time guards + +Helpers to assert time-based conditions using validators' local timestamps and quorum checks. + +! anchor requireTimeBefore go-up=time +#### requireTimeBefore + +```solidity +function requireTimeBefore(Time.Timestamp timestamp, string memory message) view +``` + +Requires that the current timestamp is before the specified time. + +**Parameters:** +- `timestamp`: `Time.Timestamp` (microseconds) that must be in the future. Use `Time.fromSeconds`, `Time.fromMillis`, or `Time.fromMicros` to construct. +- `message`: Error message if validation fails + +**Behavior:** +- Validates that the current timestamp is less than the specified timestamp +- Uses validators' local timestamps - each validator has a different local time +- Ensures a supermajority of validators saw the transaction before the required time +- Reverts with the provided message if condition fails +- Accounts for validator clock differences across the network + +See [Auctions](/examples/auctions) for an example that uses `requireTimeBefore`. + +--- + +! anchor requireTimeAfter go-up=time +#### requireTimeAfter + +```solidity +function requireTimeAfter(Time.Timestamp timestamp, string memory message) view +``` + +Requires that the current timestamp is after the specified time. + +**Parameters:** +- `timestamp`: `Time.Timestamp` (microseconds) that must be in the past. Use `Time.fromSeconds`, `Time.fromMillis`, or `Time.fromMicros` to construct. +- `message`: Error message if validation fails + +**Behavior:** +- Validates that the current timestamp is greater than the specified timestamp +- Uses validators' local timestamps - each validator has a different local time +- Ensures a supermajority of validators saw the transaction after the required time +- Reverts with the provided message if condition fails +- Accounts for validator clock differences across the network + +See [Voting](/examples/voting) for an example that uses `requireTimeAfter`. + +--- + +! anchor requireTimeAtLeast go-up=time +#### requireTimeAtLeast + +```solidity +function requireTimeAtLeast(Time.Timestamp timestamp, string memory message) view +``` + +Requires that the current timestamp is greater than or equal to the specified time. + +**Parameters:** +- `timestamp`: `Time.Timestamp` (microseconds) that must be in the past or present. Use `Time.fromSeconds`, `Time.fromMillis`, or `Time.fromMicros` to construct. +- `message`: Error message if validation fails + +**Behavior:** +- Validates that the current timestamp is greater than or equal to the specified timestamp +- Uses validators' local timestamps - each validator has a different local time +- Ensures a supermajority of validators saw the transaction at or after the required time +- Reverts with the provided message if condition fails +- Accounts for validator clock differences across the network + +See [Optimistic Auction](/examples/optimistic-auction) for an example that uses `requireTimeAtLeast`. + +--- + +! anchor requireTimeAtMost go-up=time +#### requireTimeAtMost + +```solidity +function requireTimeAtMost(Time.Timestamp timestamp, string memory message) view +``` + +Requires that the current timestamp is less than or equal to the specified time. + +**Parameters:** +- `timestamp`: `Time.Timestamp` (microseconds) that must be in the future or present. Use `Time.fromSeconds`, `Time.fromMillis`, or `Time.fromMicros` to construct. +- `message`: Error message if validation fails + +**Behavior:** +- Validates that the current timestamp is less than or equal to the specified timestamp +- Uses validators' local timestamps - each validator has a different local time +- Ensures a supermajority of validators saw the transaction at or before the required time +- Reverts with the provided message if condition fails +- Accounts for validator clock differences across the network + +See [Optimistic Auction](/examples/optimistic-auction) for an example that uses `requireTimeAtMost`. diff --git a/examples/solidity/bindings/src/ethereum_erc20_balance.rs b/examples/solidity/bindings/src/ethereum_erc20_balance.rs new file mode 100644 index 00000000..52fc64c8 --- /dev/null +++ b/examples/solidity/bindings/src/ethereum_erc20_balance.rs @@ -0,0 +1,529 @@ +/** + +Generated by the following Solidity interface... +```solidity +interface EthereumERC20Balance { + function getUSDCBalanceEthereum(address account) external view returns (uint256); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "getUSDCBalanceEthereum", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod EthereumERC20Balance { + use super::*; + use alloy::sol_types as alloy_sol_types; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x6080604052348015600e575f5ffd5b506106828061001c5f395ff3fe608060405234801561000f575f5ffd5b5060043610610029575f3560e01c80637d6220671461002d575b5f5ffd5b610047600480360381019061004291906102ec565b61005d565b604051610054919061032f565b60405180910390f35b5f5f6370a0823160e01b836040516020016100789190610357565b60405160208183030381529060405260405160200161009892919061040d565b60405160208183030381529060405290505f60405180604001604052806040518060c001604052805f73ffffffffffffffffffffffffffffffffffffffff16815260200173a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4873ffffffffffffffffffffffffffffffffffffffff168152602001620186a081526020016103e881526020015f81526020018581525081526020016040518060400160405280600681526020017f6c6174657374000000000000000000000000000000000000000000000000000081525081525090505f610173600183610193565b905080806020019051810190610189919061045e565b9350505050919050565b60605f5f7f7a15f80d7c4f6713e4b96ee58712e00c337971f876621fab9326908fdf330d775f1c73ffffffffffffffffffffffffffffffffffffffff165a86866040516020016101e49291906105c6565b60405160208183030381529060405260405161020091906105f4565b5f604051808303818686fa925050503d805f8114610239576040519150601f19603f3d011682016040523d82523d5f602084013e61023e565b606091505b509150915081610283576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161027a90610664565b60405180910390fd5b809250505092915050565b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6102bb82610292565b9050919050565b6102cb816102b1565b81146102d5575f5ffd5b50565b5f813590506102e6816102c2565b92915050565b5f602082840312156103015761030061028e565b5b5f61030e848285016102d8565b91505092915050565b5f819050919050565b61032981610317565b82525050565b5f6020820190506103425f830184610320565b92915050565b610351816102b1565b82525050565b5f60208201905061036a5f830184610348565b92915050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b5f819050919050565b6103b56103b082610370565b61039b565b82525050565b5f81519050919050565b5f81905092915050565b8281835e5f83830152505050565b5f6103e7826103bb565b6103f181856103c5565b93506104018185602086016103cf565b80840191505092915050565b5f61041882856103a4565b60048201915061042882846103dd565b91508190509392505050565b61043d81610317565b8114610447575f5ffd5b50565b5f8151905061045881610434565b92915050565b5f602082840312156104735761047261028e565b5b5f6104808482850161044a565b91505092915050565b610492816102b1565b82525050565b6104a181610317565b82525050565b5f82825260208201905092915050565b5f601f19601f8301169050919050565b5f6104d1826103bb565b6104db81856104a7565b93506104eb8185602086016103cf565b6104f4816104b7565b840191505092915050565b5f60c083015f8301516105145f860182610489565b5060208301516105276020860182610489565b50604083015161053a6040860182610498565b50606083015161054d6060860182610498565b5060808301516105606080860182610498565b5060a083015184820360a086015261057882826104c7565b9150508091505092915050565b5f604083015f8301518482035f86015261059f82826104ff565b915050602083015184820360208601526105b982826104c7565b9150508091505092915050565b5f6040820190506105d95f830185610320565b81810360208301526105eb8184610585565b90509392505050565b5f6105ff82846103dd565b915081905092915050565b5f82825260208201905092915050565b7f507265636f6d70696c652063616c6c206661696c6564000000000000000000005f82015250565b5f61064e60168361060a565b91506106598261061a565b602082019050919050565b5f6020820190508181035f83015261067b81610642565b905091905056 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15`\x0EW__\xFD[Pa\x06\x82\x80a\0\x1C_9_\xF3\xFE`\x80`@R4\x80\x15a\0\x0FW__\xFD[P`\x046\x10a\0)W_5`\xE0\x1C\x80c}b g\x14a\0-W[__\xFD[a\0G`\x04\x806\x03\x81\x01\x90a\0B\x91\x90a\x02\xECV[a\0]V[`@Qa\0T\x91\x90a\x03/V[`@Q\x80\x91\x03\x90\xF3[__cp\xA0\x821`\xE0\x1B\x83`@Q` \x01a\0x\x91\x90a\x03WV[`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Q` \x01a\0\x98\x92\x91\x90a\x04\rV[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x90P_`@Q\x80`@\x01`@R\x80`@Q\x80`\xC0\x01`@R\x80_s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01s\xA0\xB8i\x91\xC6!\x8B6\xC1\xD1\x9DJ.\x9E\xB0\xCE6\x06\xEBHs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01b\x01\x86\xA0\x81R` \x01a\x03\xE8\x81R` \x01_\x81R` \x01\x85\x81RP\x81R` \x01`@Q\x80`@\x01`@R\x80`\x06\x81R` \x01\x7Flatest\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP\x81RP\x90P_a\x01s`\x01\x83a\x01\x93V[\x90P\x80\x80` \x01\x90Q\x81\x01\x90a\x01\x89\x91\x90a\x04^V[\x93PPPP\x91\x90PV[``__\x7Fz\x15\xF8\r|Og\x13\xE4\xB9n\xE5\x87\x12\xE0\x0C3yq\xF8vb\x1F\xAB\x93&\x90\x8F\xDF3\rw_\x1Cs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16Z\x86\x86`@Q` \x01a\x01\xE4\x92\x91\x90a\x05\xC6V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Qa\x02\0\x91\x90a\x05\xF4V[_`@Q\x80\x83\x03\x81\x86\x86\xFA\x92PPP=\x80_\x81\x14a\x029W`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=_` \x84\x01>a\x02>V[``\x91P[P\x91P\x91P\x81a\x02\x83W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x02z\x90a\x06dV[`@Q\x80\x91\x03\x90\xFD[\x80\x92PPP\x92\x91PPV[__\xFD[_s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16\x90P\x91\x90PV[_a\x02\xBB\x82a\x02\x92V[\x90P\x91\x90PV[a\x02\xCB\x81a\x02\xB1V[\x81\x14a\x02\xD5W__\xFD[PV[_\x815\x90Pa\x02\xE6\x81a\x02\xC2V[\x92\x91PPV[_` \x82\x84\x03\x12\x15a\x03\x01Wa\x03\0a\x02\x8EV[[_a\x03\x0E\x84\x82\x85\x01a\x02\xD8V[\x91PP\x92\x91PPV[_\x81\x90P\x91\x90PV[a\x03)\x81a\x03\x17V[\x82RPPV[_` \x82\x01\x90Pa\x03B_\x83\x01\x84a\x03 V[\x92\x91PPV[a\x03Q\x81a\x02\xB1V[\x82RPPV[_` \x82\x01\x90Pa\x03j_\x83\x01\x84a\x03HV[\x92\x91PPV[_\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x82\x16\x90P\x91\x90PV[_\x81\x90P\x91\x90PV[a\x03\xB5a\x03\xB0\x82a\x03pV[a\x03\x9BV[\x82RPPV[_\x81Q\x90P\x91\x90PV[_\x81\x90P\x92\x91PPV[\x82\x81\x83^_\x83\x83\x01RPPPV[_a\x03\xE7\x82a\x03\xBBV[a\x03\xF1\x81\x85a\x03\xC5V[\x93Pa\x04\x01\x81\x85` \x86\x01a\x03\xCFV[\x80\x84\x01\x91PP\x92\x91PPV[_a\x04\x18\x82\x85a\x03\xA4V[`\x04\x82\x01\x91Pa\x04(\x82\x84a\x03\xDDV[\x91P\x81\x90P\x93\x92PPPV[a\x04=\x81a\x03\x17V[\x81\x14a\x04GW__\xFD[PV[_\x81Q\x90Pa\x04X\x81a\x044V[\x92\x91PPV[_` \x82\x84\x03\x12\x15a\x04sWa\x04ra\x02\x8EV[[_a\x04\x80\x84\x82\x85\x01a\x04JV[\x91PP\x92\x91PPV[a\x04\x92\x81a\x02\xB1V[\x82RPPV[a\x04\xA1\x81a\x03\x17V[\x82RPPV[_\x82\x82R` \x82\x01\x90P\x92\x91PPV[_`\x1F\x19`\x1F\x83\x01\x16\x90P\x91\x90PV[_a\x04\xD1\x82a\x03\xBBV[a\x04\xDB\x81\x85a\x04\xA7V[\x93Pa\x04\xEB\x81\x85` \x86\x01a\x03\xCFV[a\x04\xF4\x81a\x04\xB7V[\x84\x01\x91PP\x92\x91PPV[_`\xC0\x83\x01_\x83\x01Qa\x05\x14_\x86\x01\x82a\x04\x89V[P` \x83\x01Qa\x05'` \x86\x01\x82a\x04\x89V[P`@\x83\x01Qa\x05:`@\x86\x01\x82a\x04\x98V[P``\x83\x01Qa\x05M``\x86\x01\x82a\x04\x98V[P`\x80\x83\x01Qa\x05``\x80\x86\x01\x82a\x04\x98V[P`\xA0\x83\x01Q\x84\x82\x03`\xA0\x86\x01Ra\x05x\x82\x82a\x04\xC7V[\x91PP\x80\x91PP\x92\x91PPV[_`@\x83\x01_\x83\x01Q\x84\x82\x03_\x86\x01Ra\x05\x9F\x82\x82a\x04\xFFV[\x91PP` \x83\x01Q\x84\x82\x03` \x86\x01Ra\x05\xB9\x82\x82a\x04\xC7V[\x91PP\x80\x91PP\x92\x91PPV[_`@\x82\x01\x90Pa\x05\xD9_\x83\x01\x85a\x03 V[\x81\x81\x03` \x83\x01Ra\x05\xEB\x81\x84a\x05\x85V[\x90P\x93\x92PPPV[_a\x05\xFF\x82\x84a\x03\xDDV[\x91P\x81\x90P\x92\x91PPV[_\x82\x82R` \x82\x01\x90P\x92\x91PPV[\x7FPrecompile call failed\0\0\0\0\0\0\0\0\0\0_\x82\x01RPV[_a\x06N`\x16\x83a\x06\nV[\x91Pa\x06Y\x82a\x06\x1AV[` \x82\x01\x90P\x91\x90PV[_` \x82\x01\x90P\x81\x81\x03_\x83\x01Ra\x06{\x81a\x06BV[\x90P\x91\x90PV", + ); + /// The runtime bytecode of the contract, as deployed on the network. + /// + /// ```text + ///0x608060405234801561000f575f5ffd5b5060043610610029575f3560e01c80637d6220671461002d575b5f5ffd5b610047600480360381019061004291906102ec565b61005d565b604051610054919061032f565b60405180910390f35b5f5f6370a0823160e01b836040516020016100789190610357565b60405160208183030381529060405260405160200161009892919061040d565b60405160208183030381529060405290505f60405180604001604052806040518060c001604052805f73ffffffffffffffffffffffffffffffffffffffff16815260200173a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4873ffffffffffffffffffffffffffffffffffffffff168152602001620186a081526020016103e881526020015f81526020018581525081526020016040518060400160405280600681526020017f6c6174657374000000000000000000000000000000000000000000000000000081525081525090505f610173600183610193565b905080806020019051810190610189919061045e565b9350505050919050565b60605f5f7f7a15f80d7c4f6713e4b96ee58712e00c337971f876621fab9326908fdf330d775f1c73ffffffffffffffffffffffffffffffffffffffff165a86866040516020016101e49291906105c6565b60405160208183030381529060405260405161020091906105f4565b5f604051808303818686fa925050503d805f8114610239576040519150601f19603f3d011682016040523d82523d5f602084013e61023e565b606091505b509150915081610283576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161027a90610664565b60405180910390fd5b809250505092915050565b5f5ffd5b5f73ffffffffffffffffffffffffffffffffffffffff82169050919050565b5f6102bb82610292565b9050919050565b6102cb816102b1565b81146102d5575f5ffd5b50565b5f813590506102e6816102c2565b92915050565b5f602082840312156103015761030061028e565b5b5f61030e848285016102d8565b91505092915050565b5f819050919050565b61032981610317565b82525050565b5f6020820190506103425f830184610320565b92915050565b610351816102b1565b82525050565b5f60208201905061036a5f830184610348565b92915050565b5f7fffffffff0000000000000000000000000000000000000000000000000000000082169050919050565b5f819050919050565b6103b56103b082610370565b61039b565b82525050565b5f81519050919050565b5f81905092915050565b8281835e5f83830152505050565b5f6103e7826103bb565b6103f181856103c5565b93506104018185602086016103cf565b80840191505092915050565b5f61041882856103a4565b60048201915061042882846103dd565b91508190509392505050565b61043d81610317565b8114610447575f5ffd5b50565b5f8151905061045881610434565b92915050565b5f602082840312156104735761047261028e565b5b5f6104808482850161044a565b91505092915050565b610492816102b1565b82525050565b6104a181610317565b82525050565b5f82825260208201905092915050565b5f601f19601f8301169050919050565b5f6104d1826103bb565b6104db81856104a7565b93506104eb8185602086016103cf565b6104f4816104b7565b840191505092915050565b5f60c083015f8301516105145f860182610489565b5060208301516105276020860182610489565b50604083015161053a6040860182610498565b50606083015161054d6060860182610498565b5060808301516105606080860182610498565b5060a083015184820360a086015261057882826104c7565b9150508091505092915050565b5f604083015f8301518482035f86015261059f82826104ff565b915050602083015184820360208601526105b982826104c7565b9150508091505092915050565b5f6040820190506105d95f830185610320565b81810360208301526105eb8184610585565b90509392505050565b5f6105ff82846103dd565b915081905092915050565b5f82825260208201905092915050565b7f507265636f6d70696c652063616c6c206661696c6564000000000000000000005f82015250565b5f61064e60168361060a565b91506106598261061a565b602082019050919050565b5f6020820190508181035f83015261067b81610642565b905091905056 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static DEPLOYED_BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15a\0\x0FW__\xFD[P`\x046\x10a\0)W_5`\xE0\x1C\x80c}b g\x14a\0-W[__\xFD[a\0G`\x04\x806\x03\x81\x01\x90a\0B\x91\x90a\x02\xECV[a\0]V[`@Qa\0T\x91\x90a\x03/V[`@Q\x80\x91\x03\x90\xF3[__cp\xA0\x821`\xE0\x1B\x83`@Q` \x01a\0x\x91\x90a\x03WV[`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Q` \x01a\0\x98\x92\x91\x90a\x04\rV[`@Q` \x81\x83\x03\x03\x81R\x90`@R\x90P_`@Q\x80`@\x01`@R\x80`@Q\x80`\xC0\x01`@R\x80_s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01s\xA0\xB8i\x91\xC6!\x8B6\xC1\xD1\x9DJ.\x9E\xB0\xCE6\x06\xEBHs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x81R` \x01b\x01\x86\xA0\x81R` \x01a\x03\xE8\x81R` \x01_\x81R` \x01\x85\x81RP\x81R` \x01`@Q\x80`@\x01`@R\x80`\x06\x81R` \x01\x7Flatest\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81RP\x81RP\x90P_a\x01s`\x01\x83a\x01\x93V[\x90P\x80\x80` \x01\x90Q\x81\x01\x90a\x01\x89\x91\x90a\x04^V[\x93PPPP\x91\x90PV[``__\x7Fz\x15\xF8\r|Og\x13\xE4\xB9n\xE5\x87\x12\xE0\x0C3yq\xF8vb\x1F\xAB\x93&\x90\x8F\xDF3\rw_\x1Cs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16Z\x86\x86`@Q` \x01a\x01\xE4\x92\x91\x90a\x05\xC6V[`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Qa\x02\0\x91\x90a\x05\xF4V[_`@Q\x80\x83\x03\x81\x86\x86\xFA\x92PPP=\x80_\x81\x14a\x029W`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=_` \x84\x01>a\x02>V[``\x91P[P\x91P\x91P\x81a\x02\x83W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x02z\x90a\x06dV[`@Q\x80\x91\x03\x90\xFD[\x80\x92PPP\x92\x91PPV[__\xFD[_s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x16\x90P\x91\x90PV[_a\x02\xBB\x82a\x02\x92V[\x90P\x91\x90PV[a\x02\xCB\x81a\x02\xB1V[\x81\x14a\x02\xD5W__\xFD[PV[_\x815\x90Pa\x02\xE6\x81a\x02\xC2V[\x92\x91PPV[_` \x82\x84\x03\x12\x15a\x03\x01Wa\x03\0a\x02\x8EV[[_a\x03\x0E\x84\x82\x85\x01a\x02\xD8V[\x91PP\x92\x91PPV[_\x81\x90P\x91\x90PV[a\x03)\x81a\x03\x17V[\x82RPPV[_` \x82\x01\x90Pa\x03B_\x83\x01\x84a\x03 V[\x92\x91PPV[a\x03Q\x81a\x02\xB1V[\x82RPPV[_` \x82\x01\x90Pa\x03j_\x83\x01\x84a\x03HV[\x92\x91PPV[_\x7F\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x82\x16\x90P\x91\x90PV[_\x81\x90P\x91\x90PV[a\x03\xB5a\x03\xB0\x82a\x03pV[a\x03\x9BV[\x82RPPV[_\x81Q\x90P\x91\x90PV[_\x81\x90P\x92\x91PPV[\x82\x81\x83^_\x83\x83\x01RPPPV[_a\x03\xE7\x82a\x03\xBBV[a\x03\xF1\x81\x85a\x03\xC5V[\x93Pa\x04\x01\x81\x85` \x86\x01a\x03\xCFV[\x80\x84\x01\x91PP\x92\x91PPV[_a\x04\x18\x82\x85a\x03\xA4V[`\x04\x82\x01\x91Pa\x04(\x82\x84a\x03\xDDV[\x91P\x81\x90P\x93\x92PPPV[a\x04=\x81a\x03\x17V[\x81\x14a\x04GW__\xFD[PV[_\x81Q\x90Pa\x04X\x81a\x044V[\x92\x91PPV[_` \x82\x84\x03\x12\x15a\x04sWa\x04ra\x02\x8EV[[_a\x04\x80\x84\x82\x85\x01a\x04JV[\x91PP\x92\x91PPV[a\x04\x92\x81a\x02\xB1V[\x82RPPV[a\x04\xA1\x81a\x03\x17V[\x82RPPV[_\x82\x82R` \x82\x01\x90P\x92\x91PPV[_`\x1F\x19`\x1F\x83\x01\x16\x90P\x91\x90PV[_a\x04\xD1\x82a\x03\xBBV[a\x04\xDB\x81\x85a\x04\xA7V[\x93Pa\x04\xEB\x81\x85` \x86\x01a\x03\xCFV[a\x04\xF4\x81a\x04\xB7V[\x84\x01\x91PP\x92\x91PPV[_`\xC0\x83\x01_\x83\x01Qa\x05\x14_\x86\x01\x82a\x04\x89V[P` \x83\x01Qa\x05'` \x86\x01\x82a\x04\x89V[P`@\x83\x01Qa\x05:`@\x86\x01\x82a\x04\x98V[P``\x83\x01Qa\x05M``\x86\x01\x82a\x04\x98V[P`\x80\x83\x01Qa\x05``\x80\x86\x01\x82a\x04\x98V[P`\xA0\x83\x01Q\x84\x82\x03`\xA0\x86\x01Ra\x05x\x82\x82a\x04\xC7V[\x91PP\x80\x91PP\x92\x91PPV[_`@\x83\x01_\x83\x01Q\x84\x82\x03_\x86\x01Ra\x05\x9F\x82\x82a\x04\xFFV[\x91PP` \x83\x01Q\x84\x82\x03` \x86\x01Ra\x05\xB9\x82\x82a\x04\xC7V[\x91PP\x80\x91PP\x92\x91PPV[_`@\x82\x01\x90Pa\x05\xD9_\x83\x01\x85a\x03 V[\x81\x81\x03` \x83\x01Ra\x05\xEB\x81\x84a\x05\x85V[\x90P\x93\x92PPPV[_a\x05\xFF\x82\x84a\x03\xDDV[\x91P\x81\x90P\x92\x91PPV[_\x82\x82R` \x82\x01\x90P\x92\x91PPV[\x7FPrecompile call failed\0\0\0\0\0\0\0\0\0\0_\x82\x01RPV[_a\x06N`\x16\x83a\x06\nV[\x91Pa\x06Y\x82a\x06\x1AV[` \x82\x01\x90P\x91\x90PV[_` \x82\x01\x90P\x81\x81\x03_\x83\x01Ra\x06{\x81a\x06BV[\x90P\x91\x90PV", + ); + #[derive(serde::Serialize, serde::Deserialize)] + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `getUSDCBalanceEthereum(address)` and selector `0x7d622067`. +```solidity +function getUSDCBalanceEthereum(address account) external view returns (uint256); +```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getUSDCBalanceEthereumCall { + #[allow(missing_docs)] + pub account: alloy::sol_types::private::Address, + } + #[derive(serde::Serialize, serde::Deserialize)] + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`getUSDCBalanceEthereum(address)`](getUSDCBalanceEthereumCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct getUSDCBalanceEthereumReturn { + #[allow(missing_docs)] + pub _0: alloy::sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy::sol_types as alloy_sol_types; + { + #[doc(hidden)] + type UnderlyingSolTuple<'a> = (alloy::sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy::sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion( + _t: alloy_sol_types::private::AssertTypeEq, + ) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From + for UnderlyingRustTuple<'_> { + fn from(value: getUSDCBalanceEthereumCall) -> Self { + (value.account,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> + for getUSDCBalanceEthereumCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { account: tuple.0 } + } + } + } + { + #[doc(hidden)] + type UnderlyingSolTuple<'a> = (alloy::sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy::sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion( + _t: alloy_sol_types::private::AssertTypeEq, + ) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From + for UnderlyingRustTuple<'_> { + fn from(value: getUSDCBalanceEthereumReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> + for getUSDCBalanceEthereumReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for getUSDCBalanceEthereumCall { + type Parameters<'a> = (alloy::sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + type Return = alloy::sol_types::private::primitives::aliases::U256; + type ReturnTuple<'a> = (alloy::sol_types::sol_data::Uint<256>,); + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + const SIGNATURE: &'static str = "getUSDCBalanceEthereum(address)"; + const SELECTOR: [u8; 4] = [125u8, 98u8, 32u8, 103u8]; + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.account, + ), + ) + } + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(|r| { + let r: getUSDCBalanceEthereumReturn = r.into(); + r._0 + }) + } + #[inline] + fn abi_decode_returns_validate( + data: &[u8], + ) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate(data) + .map(|r| { + let r: getUSDCBalanceEthereumReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`EthereumERC20Balance`](self) function calls. + #[derive(serde::Serialize, serde::Deserialize)] + #[derive()] + pub enum EthereumERC20BalanceCalls { + #[allow(missing_docs)] + getUSDCBalanceEthereum(getUSDCBalanceEthereumCall), + } + #[automatically_derived] + impl EthereumERC20BalanceCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the variants. + /// No guarantees are made about the order of the selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[[125u8, 98u8, 32u8, 103u8]]; + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for EthereumERC20BalanceCalls { + const NAME: &'static str = "EthereumERC20BalanceCalls"; + const MIN_DATA_LENGTH: usize = 32usize; + const COUNT: usize = 1usize; + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::getUSDCBalanceEthereum(_) => { + ::SELECTOR + } + } + } + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result] = &[ + { + fn getUSDCBalanceEthereum( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(EthereumERC20BalanceCalls::getUSDCBalanceEthereum) + } + getUSDCBalanceEthereum + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err( + alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + ), + ); + }; + DECODE_SHIMS[idx](data) + } + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result] = &[ + { + fn getUSDCBalanceEthereum( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(EthereumERC20BalanceCalls::getUSDCBalanceEthereum) + } + getUSDCBalanceEthereum + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err( + alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + ), + ); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::getUSDCBalanceEthereum(inner) => { + ::abi_encoded_size( + inner, + ) + } + } + } + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::getUSDCBalanceEthereum(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + } + } + } + use alloy::contract as alloy_contract; + /**Creates a new wrapper around an on-chain [`EthereumERC20Balance`](self) contract instance. + +See the [wrapper's documentation](`EthereumERC20BalanceInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + provider: P, + ) -> EthereumERC20BalanceInstance { + EthereumERC20BalanceInstance::::new(address, provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + +Returns a new instance of the contract, if the deployment was successful. + +For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + provider: P, + ) -> impl ::core::future::Future< + Output = alloy_contract::Result>, + > { + EthereumERC20BalanceInstance::::deploy(provider) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` +and constructor arguments, if any. + +This is a simple wrapper around creating a `RawCallBuilder` with the data set to +the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >(provider: P) -> alloy_contract::RawCallBuilder { + EthereumERC20BalanceInstance::::deploy_builder(provider) + } + /**A [`EthereumERC20Balance`](self) instance. + +Contains type-safe methods for interacting with an on-chain instance of the +[`EthereumERC20Balance`](self) contract located at a given `address`, using a given +provider `P`. + +If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) +documentation on how to provide it), the `deploy` and `deploy_builder` methods can +be used to deploy a new instance of the contract. + +See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct EthereumERC20BalanceInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for EthereumERC20BalanceInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("EthereumERC20BalanceInstance").field(&self.address).finish() + } + } + /// Instantiation and getters/setters. + #[automatically_derived] + impl< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + > EthereumERC20BalanceInstance { + /**Creates a new wrapper around an on-chain [`EthereumERC20Balance`](self) contract instance. + +See the [wrapper's documentation](`EthereumERC20BalanceInstance`) for more details.*/ + #[inline] + pub const fn new( + address: alloy_sol_types::private::Address, + provider: P, + ) -> Self { + Self { + address, + provider, + _network: ::core::marker::PhantomData, + } + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + +Returns a new instance of the contract, if the deployment was successful. + +For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + provider: P, + ) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(provider); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` +and constructor arguments, if any. + +This is a simple wrapper around creating a `RawCallBuilder` with the data set to +the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder(provider: P) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + provider, + ::core::clone::Clone::clone(&BYTECODE), + ) + } + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl EthereumERC20BalanceInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned provider. + #[inline] + pub fn with_cloned_provider(self) -> EthereumERC20BalanceInstance { + EthereumERC20BalanceInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + #[automatically_derived] + impl< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + > EthereumERC20BalanceInstance { + /// Creates a new call builder using this contract instance's provider and address. + /// + /// Note that the call can be any function call, not just those defined in this + /// contract. Prefer using the other methods for building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + ///Creates a new call builder for the [`getUSDCBalanceEthereum`] function. + pub fn getUSDCBalanceEthereum( + &self, + account: alloy::sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, getUSDCBalanceEthereumCall, N> { + self.call_builder( + &getUSDCBalanceEthereumCall { + account, + }, + ) + } + } + /// Event filters. + #[automatically_derived] + impl< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + > EthereumERC20BalanceInstance { + /// Creates a new event filter using this contract instance's provider and address. + /// + /// Note that the type can be any event, not just those defined in this contract. + /// Prefer using the other methods for building type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + } +} diff --git a/examples/solidity/bindings/src/ierc20.rs b/examples/solidity/bindings/src/ierc20.rs new file mode 100644 index 00000000..75c3565c --- /dev/null +++ b/examples/solidity/bindings/src/ierc20.rs @@ -0,0 +1,2049 @@ +/** + +Generated by the following Solidity interface... +```solidity +interface IERC20 { + event Approval(address indexed owner, address indexed spender, uint256 value); + event Transfer(address indexed from, address indexed to, uint256 value); + + function allowance(address owner, address spender) external view returns (uint256); + function approve(address spender, uint256 value) external returns (bool); + function balanceOf(address account) external view returns (uint256); + function totalSupply() external view returns (uint256); + function transfer(address to, uint256 value) external returns (bool); + function transferFrom(address from, address to, uint256 value) external returns (bool); +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "allowance", + "inputs": [ + { + "name": "owner", + "type": "address", + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "approve", + "inputs": [ + { + "name": "spender", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "balanceOf", + "inputs": [ + { + "name": "account", + "type": "address", + "internalType": "address" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "totalSupply", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "transfer", + "inputs": [ + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "function", + "name": "transferFrom", + "inputs": [ + { + "name": "from", + "type": "address", + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "internalType": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "bool", + "internalType": "bool" + } + ], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "Approval", + "inputs": [ + { + "name": "owner", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "spender", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + }, + { + "type": "event", + "name": "Transfer", + "inputs": [ + { + "name": "from", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "to", + "type": "address", + "indexed": true, + "internalType": "address" + }, + { + "name": "value", + "type": "uint256", + "indexed": false, + "internalType": "uint256" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod IERC20 { + use super::*; + use alloy::sol_types as alloy_sol_types; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"", + ); + /// The runtime bytecode of the contract, as deployed on the network. + /// + /// ```text + ///0x + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static DEPLOYED_BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"", + ); + #[derive(serde::Serialize, serde::Deserialize)] + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Approval(address,address,uint256)` and selector `0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925`. +```solidity +event Approval(address indexed owner, address indexed spender, uint256 value); +```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Approval { + #[allow(missing_docs)] + pub owner: alloy::sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy::sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy::sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy::sol_types as alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Approval { + type DataTuple<'a> = (alloy::sol_types::sol_data::Uint<256>,); + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy::sol_types::sol_data::Address, + alloy::sol_types::sol_data::Address, + ); + const SIGNATURE: &'static str = "Approval(address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = alloy_sol_types::private::B256::new([ + 140u8, 91u8, 225u8, 229u8, 235u8, 236u8, 125u8, 91u8, 209u8, 79u8, 113u8, + 66u8, 125u8, 30u8, 132u8, 243u8, 221u8, 3u8, 20u8, 192u8, 247u8, 178u8, + 41u8, 30u8, 91u8, 32u8, 10u8, 200u8, 199u8, 195u8, 185u8, 37u8, + ]); + const ANONYMOUS: bool = false; + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + owner: topics.1, + spender: topics.2, + value: data.0, + } + } + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err( + alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + ), + ); + } + Ok(()) + } + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.value), + ) + } + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.owner.clone(), self.spender.clone()) + } + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken( + Self::SIGNATURE_HASH, + ); + out[1usize] = ::encode_topic( + &self.owner, + ); + out[2usize] = ::encode_topic( + &self.spender, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Approval { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Approval> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Approval) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(serde::Serialize, serde::Deserialize)] + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `Transfer(address,address,uint256)` and selector `0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef`. +```solidity +event Transfer(address indexed from, address indexed to, uint256 value); +```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct Transfer { + #[allow(missing_docs)] + pub from: alloy::sol_types::private::Address, + #[allow(missing_docs)] + pub to: alloy::sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy::sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy::sol_types as alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for Transfer { + type DataTuple<'a> = (alloy::sol_types::sol_data::Uint<256>,); + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy::sol_types::sol_data::Address, + alloy::sol_types::sol_data::Address, + ); + const SIGNATURE: &'static str = "Transfer(address,address,uint256)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = alloy_sol_types::private::B256::new([ + 221u8, 242u8, 82u8, 173u8, 27u8, 226u8, 200u8, 155u8, 105u8, 194u8, + 176u8, 104u8, 252u8, 55u8, 141u8, 170u8, 149u8, 43u8, 167u8, 241u8, 99u8, + 196u8, 161u8, 22u8, 40u8, 245u8, 90u8, 77u8, 245u8, 35u8, 179u8, 239u8, + ]); + const ANONYMOUS: bool = false; + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { + from: topics.1, + to: topics.2, + value: data.0, + } + } + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err( + alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + ), + ); + } + Ok(()) + } + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(&self.value), + ) + } + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.from.clone(), self.to.clone()) + } + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken( + Self::SIGNATURE_HASH, + ); + out[1usize] = ::encode_topic( + &self.from, + ); + out[2usize] = ::encode_topic( + &self.to, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for Transfer { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&Transfer> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &Transfer) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(serde::Serialize, serde::Deserialize)] + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `allowance(address,address)` and selector `0xdd62ed3e`. +```solidity +function allowance(address owner, address spender) external view returns (uint256); +```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceCall { + #[allow(missing_docs)] + pub owner: alloy::sol_types::private::Address, + #[allow(missing_docs)] + pub spender: alloy::sol_types::private::Address, + } + #[derive(serde::Serialize, serde::Deserialize)] + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`allowance(address,address)`](allowanceCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct allowanceReturn { + #[allow(missing_docs)] + pub _0: alloy::sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy::sol_types as alloy_sol_types; + { + #[doc(hidden)] + type UnderlyingSolTuple<'a> = ( + alloy::sol_types::sol_data::Address, + alloy::sol_types::sol_data::Address, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy::sol_types::private::Address, + alloy::sol_types::private::Address, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion( + _t: alloy_sol_types::private::AssertTypeEq, + ) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceCall) -> Self { + (value.owner, value.spender) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + owner: tuple.0, + spender: tuple.1, + } + } + } + } + { + #[doc(hidden)] + type UnderlyingSolTuple<'a> = (alloy::sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy::sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion( + _t: alloy_sol_types::private::AssertTypeEq, + ) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: allowanceReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for allowanceReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for allowanceCall { + type Parameters<'a> = ( + alloy::sol_types::sol_data::Address, + alloy::sol_types::sol_data::Address, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + type Return = alloy::sol_types::private::primitives::aliases::U256; + type ReturnTuple<'a> = (alloy::sol_types::sol_data::Uint<256>,); + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + const SIGNATURE: &'static str = "allowance(address,address)"; + const SELECTOR: [u8; 4] = [221u8, 98u8, 237u8, 62u8]; + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.owner, + ), + ::tokenize( + &self.spender, + ), + ) + } + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(|r| { + let r: allowanceReturn = r.into(); + r._0 + }) + } + #[inline] + fn abi_decode_returns_validate( + data: &[u8], + ) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate(data) + .map(|r| { + let r: allowanceReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(serde::Serialize, serde::Deserialize)] + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `approve(address,uint256)` and selector `0x095ea7b3`. +```solidity +function approve(address spender, uint256 value) external returns (bool); +```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveCall { + #[allow(missing_docs)] + pub spender: alloy::sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy::sol_types::private::primitives::aliases::U256, + } + #[derive(serde::Serialize, serde::Deserialize)] + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`approve(address,uint256)`](approveCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct approveReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy::sol_types as alloy_sol_types; + { + #[doc(hidden)] + type UnderlyingSolTuple<'a> = ( + alloy::sol_types::sol_data::Address, + alloy::sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy::sol_types::private::Address, + alloy::sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion( + _t: alloy_sol_types::private::AssertTypeEq, + ) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveCall) -> Self { + (value.spender, value.value) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + spender: tuple.0, + value: tuple.1, + } + } + } + } + { + #[doc(hidden)] + type UnderlyingSolTuple<'a> = (alloy::sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion( + _t: alloy_sol_types::private::AssertTypeEq, + ) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: approveReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for approveReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for approveCall { + type Parameters<'a> = ( + alloy::sol_types::sol_data::Address, + alloy::sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + type Return = bool; + type ReturnTuple<'a> = (alloy::sol_types::sol_data::Bool,); + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + const SIGNATURE: &'static str = "approve(address,uint256)"; + const SELECTOR: [u8; 4] = [9u8, 94u8, 167u8, 179u8]; + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.spender, + ), + as alloy_sol_types::SolType>::tokenize(&self.value), + ) + } + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + ::tokenize( + ret, + ), + ) + } + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(|r| { + let r: approveReturn = r.into(); + r._0 + }) + } + #[inline] + fn abi_decode_returns_validate( + data: &[u8], + ) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate(data) + .map(|r| { + let r: approveReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(serde::Serialize, serde::Deserialize)] + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `balanceOf(address)` and selector `0x70a08231`. +```solidity +function balanceOf(address account) external view returns (uint256); +```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfCall { + #[allow(missing_docs)] + pub account: alloy::sol_types::private::Address, + } + #[derive(serde::Serialize, serde::Deserialize)] + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`balanceOf(address)`](balanceOfCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct balanceOfReturn { + #[allow(missing_docs)] + pub _0: alloy::sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy::sol_types as alloy_sol_types; + { + #[doc(hidden)] + type UnderlyingSolTuple<'a> = (alloy::sol_types::sol_data::Address,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (alloy::sol_types::private::Address,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion( + _t: alloy_sol_types::private::AssertTypeEq, + ) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfCall) -> Self { + (value.account,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { account: tuple.0 } + } + } + } + { + #[doc(hidden)] + type UnderlyingSolTuple<'a> = (alloy::sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy::sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion( + _t: alloy_sol_types::private::AssertTypeEq, + ) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: balanceOfReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for balanceOfReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for balanceOfCall { + type Parameters<'a> = (alloy::sol_types::sol_data::Address,); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + type Return = alloy::sol_types::private::primitives::aliases::U256; + type ReturnTuple<'a> = (alloy::sol_types::sol_data::Uint<256>,); + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + const SIGNATURE: &'static str = "balanceOf(address)"; + const SELECTOR: [u8; 4] = [112u8, 160u8, 130u8, 49u8]; + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.account, + ), + ) + } + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(|r| { + let r: balanceOfReturn = r.into(); + r._0 + }) + } + #[inline] + fn abi_decode_returns_validate( + data: &[u8], + ) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate(data) + .map(|r| { + let r: balanceOfReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(serde::Serialize, serde::Deserialize)] + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `totalSupply()` and selector `0x18160ddd`. +```solidity +function totalSupply() external view returns (uint256); +```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct totalSupplyCall; + #[derive(serde::Serialize, serde::Deserialize)] + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`totalSupply()`](totalSupplyCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct totalSupplyReturn { + #[allow(missing_docs)] + pub _0: alloy::sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy::sol_types as alloy_sol_types; + { + #[doc(hidden)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion( + _t: alloy_sol_types::private::AssertTypeEq, + ) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: totalSupplyCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for totalSupplyCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + type UnderlyingSolTuple<'a> = (alloy::sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy::sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion( + _t: alloy_sol_types::private::AssertTypeEq, + ) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: totalSupplyReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for totalSupplyReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for totalSupplyCall { + type Parameters<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + type Return = alloy::sol_types::private::primitives::aliases::U256; + type ReturnTuple<'a> = (alloy::sol_types::sol_data::Uint<256>,); + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + const SIGNATURE: &'static str = "totalSupply()"; + const SELECTOR: [u8; 4] = [24u8, 22u8, 13u8, 221u8]; + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(|r| { + let r: totalSupplyReturn = r.into(); + r._0 + }) + } + #[inline] + fn abi_decode_returns_validate( + data: &[u8], + ) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate(data) + .map(|r| { + let r: totalSupplyReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(serde::Serialize, serde::Deserialize)] + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transfer(address,uint256)` and selector `0xa9059cbb`. +```solidity +function transfer(address to, uint256 value) external returns (bool); +```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferCall { + #[allow(missing_docs)] + pub to: alloy::sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy::sol_types::private::primitives::aliases::U256, + } + #[derive(serde::Serialize, serde::Deserialize)] + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`transfer(address,uint256)`](transferCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy::sol_types as alloy_sol_types; + { + #[doc(hidden)] + type UnderlyingSolTuple<'a> = ( + alloy::sol_types::sol_data::Address, + alloy::sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy::sol_types::private::Address, + alloy::sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion( + _t: alloy_sol_types::private::AssertTypeEq, + ) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferCall) -> Self { + (value.to, value.value) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + to: tuple.0, + value: tuple.1, + } + } + } + } + { + #[doc(hidden)] + type UnderlyingSolTuple<'a> = (alloy::sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion( + _t: alloy_sol_types::private::AssertTypeEq, + ) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferCall { + type Parameters<'a> = ( + alloy::sol_types::sol_data::Address, + alloy::sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + type Return = bool; + type ReturnTuple<'a> = (alloy::sol_types::sol_data::Bool,); + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + const SIGNATURE: &'static str = "transfer(address,uint256)"; + const SELECTOR: [u8; 4] = [169u8, 5u8, 156u8, 187u8]; + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize(&self.value), + ) + } + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + ::tokenize( + ret, + ), + ) + } + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(|r| { + let r: transferReturn = r.into(); + r._0 + }) + } + #[inline] + fn abi_decode_returns_validate( + data: &[u8], + ) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate(data) + .map(|r| { + let r: transferReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(serde::Serialize, serde::Deserialize)] + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `transferFrom(address,address,uint256)` and selector `0x23b872dd`. +```solidity +function transferFrom(address from, address to, uint256 value) external returns (bool); +```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromCall { + #[allow(missing_docs)] + pub from: alloy::sol_types::private::Address, + #[allow(missing_docs)] + pub to: alloy::sol_types::private::Address, + #[allow(missing_docs)] + pub value: alloy::sol_types::private::primitives::aliases::U256, + } + #[derive(serde::Serialize, serde::Deserialize)] + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`transferFrom(address,address,uint256)`](transferFromCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct transferFromReturn { + #[allow(missing_docs)] + pub _0: bool, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy::sol_types as alloy_sol_types; + { + #[doc(hidden)] + type UnderlyingSolTuple<'a> = ( + alloy::sol_types::sol_data::Address, + alloy::sol_types::sol_data::Address, + alloy::sol_types::sol_data::Uint<256>, + ); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy::sol_types::private::Address, + alloy::sol_types::private::Address, + alloy::sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion( + _t: alloy_sol_types::private::AssertTypeEq, + ) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromCall) -> Self { + (value.from, value.to, value.value) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { + from: tuple.0, + to: tuple.1, + value: tuple.2, + } + } + } + } + { + #[doc(hidden)] + type UnderlyingSolTuple<'a> = (alloy::sol_types::sol_data::Bool,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (bool,); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion( + _t: alloy_sol_types::private::AssertTypeEq, + ) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: transferFromReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for transferFromReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for transferFromCall { + type Parameters<'a> = ( + alloy::sol_types::sol_data::Address, + alloy::sol_types::sol_data::Address, + alloy::sol_types::sol_data::Uint<256>, + ); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + type Return = bool; + type ReturnTuple<'a> = (alloy::sol_types::sol_data::Bool,); + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + const SIGNATURE: &'static str = "transferFrom(address,address,uint256)"; + const SELECTOR: [u8; 4] = [35u8, 184u8, 114u8, 221u8]; + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + ( + ::tokenize( + &self.from, + ), + ::tokenize( + &self.to, + ), + as alloy_sol_types::SolType>::tokenize(&self.value), + ) + } + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + ::tokenize( + ret, + ), + ) + } + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(|r| { + let r: transferFromReturn = r.into(); + r._0 + }) + } + #[inline] + fn abi_decode_returns_validate( + data: &[u8], + ) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate(data) + .map(|r| { + let r: transferFromReturn = r.into(); + r._0 + }) + } + } + }; + ///Container for all the [`IERC20`](self) function calls. + #[derive(serde::Serialize, serde::Deserialize)] + #[derive()] + pub enum IERC20Calls { + #[allow(missing_docs)] + allowance(allowanceCall), + #[allow(missing_docs)] + approve(approveCall), + #[allow(missing_docs)] + balanceOf(balanceOfCall), + #[allow(missing_docs)] + totalSupply(totalSupplyCall), + #[allow(missing_docs)] + transfer(transferCall), + #[allow(missing_docs)] + transferFrom(transferFromCall), + } + #[automatically_derived] + impl IERC20Calls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the variants. + /// No guarantees are made about the order of the selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [9u8, 94u8, 167u8, 179u8], + [24u8, 22u8, 13u8, 221u8], + [35u8, 184u8, 114u8, 221u8], + [112u8, 160u8, 130u8, 49u8], + [169u8, 5u8, 156u8, 187u8], + [221u8, 98u8, 237u8, 62u8], + ]; + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for IERC20Calls { + const NAME: &'static str = "IERC20Calls"; + const MIN_DATA_LENGTH: usize = 0usize; + const COUNT: usize = 6usize; + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::allowance(_) => { + ::SELECTOR + } + Self::approve(_) => ::SELECTOR, + Self::balanceOf(_) => { + ::SELECTOR + } + Self::totalSupply(_) => { + ::SELECTOR + } + Self::transfer(_) => ::SELECTOR, + Self::transferFrom(_) => { + ::SELECTOR + } + } + } + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn(&[u8]) -> alloy_sol_types::Result] = &[ + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IERC20Calls::approve) + } + approve + }, + { + fn totalSupply(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(IERC20Calls::totalSupply) + } + totalSupply + }, + { + fn transferFrom( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(IERC20Calls::transferFrom) + } + transferFrom + }, + { + fn balanceOf(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IERC20Calls::balanceOf) + } + balanceOf + }, + { + fn transfer(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IERC20Calls::transfer) + } + transfer + }, + { + fn allowance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw(data) + .map(IERC20Calls::allowance) + } + allowance + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err( + alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + ), + ); + }; + DECODE_SHIMS[idx](data) + } + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result] = &[ + { + fn approve(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(IERC20Calls::approve) + } + approve + }, + { + fn totalSupply(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(IERC20Calls::totalSupply) + } + totalSupply + }, + { + fn transferFrom( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(IERC20Calls::transferFrom) + } + transferFrom + }, + { + fn balanceOf(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(IERC20Calls::balanceOf) + } + balanceOf + }, + { + fn transfer(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(IERC20Calls::transfer) + } + transfer + }, + { + fn allowance(data: &[u8]) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(IERC20Calls::allowance) + } + allowance + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err( + alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + ), + ); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::allowance(inner) => { + ::abi_encoded_size(inner) + } + Self::approve(inner) => { + ::abi_encoded_size(inner) + } + Self::balanceOf(inner) => { + ::abi_encoded_size(inner) + } + Self::totalSupply(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::transfer(inner) => { + ::abi_encoded_size(inner) + } + Self::transferFrom(inner) => { + ::abi_encoded_size( + inner, + ) + } + } + } + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::allowance(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::approve(inner) => { + ::abi_encode_raw(inner, out) + } + Self::balanceOf(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::totalSupply(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::transfer(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::transferFrom(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + } + } + } + ///Container for all the [`IERC20`](self) events. + #[derive(serde::Serialize, serde::Deserialize)] + #[derive(Debug, PartialEq, Eq, Hash)] + pub enum IERC20Events { + #[allow(missing_docs)] + Approval(Approval), + #[allow(missing_docs)] + Transfer(Transfer), + } + #[automatically_derived] + impl IERC20Events { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the variants. + /// No guarantees are made about the order of the selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 140u8, 91u8, 225u8, 229u8, 235u8, 236u8, 125u8, 91u8, 209u8, 79u8, 113u8, + 66u8, 125u8, 30u8, 132u8, 243u8, 221u8, 3u8, 20u8, 192u8, 247u8, 178u8, + 41u8, 30u8, 91u8, 32u8, 10u8, 200u8, 199u8, 195u8, 185u8, 37u8, + ], + [ + 221u8, 242u8, 82u8, 173u8, 27u8, 226u8, 200u8, 155u8, 105u8, 194u8, + 176u8, 104u8, 252u8, 55u8, 141u8, 170u8, 149u8, 43u8, 167u8, 241u8, 99u8, + 196u8, 161u8, 22u8, 40u8, 245u8, 90u8, 77u8, 245u8, 35u8, 179u8, 239u8, + ], + ]; + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for IERC20Events { + const NAME: &'static str = "IERC20Events"; + const COUNT: usize = 2usize; + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Approval) + } + Some(::SIGNATURE_HASH) => { + ::decode_raw_log(topics, data) + .map(Self::Transfer) + } + _ => { + alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }) + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for IERC20Events { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::Approval(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + Self::Transfer(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::Approval(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + Self::Transfer(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy::contract as alloy_contract; + /**Creates a new wrapper around an on-chain [`IERC20`](self) contract instance. + +See the [wrapper's documentation](`IERC20Instance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >(address: alloy_sol_types::private::Address, provider: P) -> IERC20Instance { + IERC20Instance::::new(address, provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + +Returns a new instance of the contract, if the deployment was successful. + +For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + provider: P, + ) -> impl ::core::future::Future< + Output = alloy_contract::Result>, + > { + IERC20Instance::::deploy(provider) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` +and constructor arguments, if any. + +This is a simple wrapper around creating a `RawCallBuilder` with the data set to +the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >(provider: P) -> alloy_contract::RawCallBuilder { + IERC20Instance::::deploy_builder(provider) + } + /**A [`IERC20`](self) instance. + +Contains type-safe methods for interacting with an on-chain instance of the +[`IERC20`](self) contract located at a given `address`, using a given +provider `P`. + +If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) +documentation on how to provide it), the `deploy` and `deploy_builder` methods can +be used to deploy a new instance of the contract. + +See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct IERC20Instance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for IERC20Instance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("IERC20Instance").field(&self.address).finish() + } + } + /// Instantiation and getters/setters. + #[automatically_derived] + impl< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + > IERC20Instance { + /**Creates a new wrapper around an on-chain [`IERC20`](self) contract instance. + +See the [wrapper's documentation](`IERC20Instance`) for more details.*/ + #[inline] + pub const fn new( + address: alloy_sol_types::private::Address, + provider: P, + ) -> Self { + Self { + address, + provider, + _network: ::core::marker::PhantomData, + } + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + +Returns a new instance of the contract, if the deployment was successful. + +For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + provider: P, + ) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(provider); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` +and constructor arguments, if any. + +This is a simple wrapper around creating a `RawCallBuilder` with the data set to +the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder(provider: P) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + provider, + ::core::clone::Clone::clone(&BYTECODE), + ) + } + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl IERC20Instance<&P, N> { + /// Clones the provider and returns a new instance with the cloned provider. + #[inline] + pub fn with_cloned_provider(self) -> IERC20Instance { + IERC20Instance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + #[automatically_derived] + impl< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + > IERC20Instance { + /// Creates a new call builder using this contract instance's provider and address. + /// + /// Note that the call can be any function call, not just those defined in this + /// contract. Prefer using the other methods for building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + ///Creates a new call builder for the [`allowance`] function. + pub fn allowance( + &self, + owner: alloy::sol_types::private::Address, + spender: alloy::sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, allowanceCall, N> { + self.call_builder(&allowanceCall { owner, spender }) + } + ///Creates a new call builder for the [`approve`] function. + pub fn approve( + &self, + spender: alloy::sol_types::private::Address, + value: alloy::sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, approveCall, N> { + self.call_builder(&approveCall { spender, value }) + } + ///Creates a new call builder for the [`balanceOf`] function. + pub fn balanceOf( + &self, + account: alloy::sol_types::private::Address, + ) -> alloy_contract::SolCallBuilder<&P, balanceOfCall, N> { + self.call_builder(&balanceOfCall { account }) + } + ///Creates a new call builder for the [`totalSupply`] function. + pub fn totalSupply( + &self, + ) -> alloy_contract::SolCallBuilder<&P, totalSupplyCall, N> { + self.call_builder(&totalSupplyCall) + } + ///Creates a new call builder for the [`transfer`] function. + pub fn transfer( + &self, + to: alloy::sol_types::private::Address, + value: alloy::sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferCall, N> { + self.call_builder(&transferCall { to, value }) + } + ///Creates a new call builder for the [`transferFrom`] function. + pub fn transferFrom( + &self, + from: alloy::sol_types::private::Address, + to: alloy::sol_types::private::Address, + value: alloy::sol_types::private::primitives::aliases::U256, + ) -> alloy_contract::SolCallBuilder<&P, transferFromCall, N> { + self.call_builder( + &transferFromCall { + from, + to, + value, + }, + ) + } + } + /// Event filters. + #[automatically_derived] + impl< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + > IERC20Instance { + /// Creates a new event filter using this contract instance's provider and address. + /// + /// Note that the type can be any event, not just those defined in this contract. + /// Prefer using the other methods for building type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + ///Creates a new event filter for the [`Approval`] event. + pub fn Approval_filter(&self) -> alloy_contract::Event<&P, Approval, N> { + self.event_filter::() + } + ///Creates a new event filter for the [`Transfer`] event. + pub fn Transfer_filter(&self) -> alloy_contract::Event<&P, Transfer, N> { + self.event_filter::() + } + } +} diff --git a/examples/solidity/bindings/src/lib.rs b/examples/solidity/bindings/src/lib.rs index d98739bd..273593db 100644 --- a/examples/solidity/bindings/src/lib.rs +++ b/examples/solidity/bindings/src/lib.rs @@ -4,8 +4,11 @@ //! Do not manually edit these files. //! These files may be overwritten by the codegen system at any time. pub mod r#auction; +pub mod r#ethereum_erc20_balance; pub mod r#fast_types; +pub mod r#ierc20; pub mod r#pi2; +pub mod r#quorum_restricted_action; pub mod r#ranked_feed; pub mod r#test_mint_balance_precompile; pub mod r#time; diff --git a/examples/solidity/bindings/src/quorum_restricted_action.rs b/examples/solidity/bindings/src/quorum_restricted_action.rs new file mode 100644 index 00000000..41bb3c55 --- /dev/null +++ b/examples/solidity/bindings/src/quorum_restricted_action.rs @@ -0,0 +1,901 @@ +/** + +Generated by the following Solidity interface... +```solidity +interface QuorumRestrictedAction { + event ActionAllowed(address indexed account); + + function etherThreshold() external view returns (uint256); + function restrictedAction() external; +} +``` + +...which was generated by the following JSON ABI: +```json +[ + { + "type": "function", + "name": "etherThreshold", + "inputs": [], + "outputs": [ + { + "name": "", + "type": "uint256", + "internalType": "uint256" + } + ], + "stateMutability": "view" + }, + { + "type": "function", + "name": "restrictedAction", + "inputs": [], + "outputs": [], + "stateMutability": "nonpayable" + }, + { + "type": "event", + "name": "ActionAllowed", + "inputs": [ + { + "name": "account", + "type": "address", + "indexed": true, + "internalType": "address" + } + ], + "anonymous": false + } +] +```*/ +#[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style, + clippy::empty_structs_with_brackets +)] +pub mod QuorumRestrictedAction { + use super::*; + use alloy::sol_types as alloy_sol_types; + /// The creation / init bytecode of the contract. + /// + /// ```text + ///0x6080604052670de0b6b3a76400005f553480156019575f5ffd5b50610345806100275f395ff3fe608060405234801561000f575f5ffd5b5060043610610034575f3560e01c80635a7b56a31461003857806361baffe614610056575b5f5ffd5b610040610060565b60405161004d919061020f565b60405180910390f35b61005e610065565b005b5f5481565b336100c05f548273ffffffffffffffffffffffffffffffffffffffff163110156040518060400160405280601881526020017f4e6f7420656e6f7567682045746865722062616c616e63650000000000000000815250610106565b3373ffffffffffffffffffffffffffffffffffffffff167f11511a1056af152a51f79222be7a074f7d19b5a13439cd362364797976fe6cb360405160405180910390a250565b5f7f3dcdf63b41c103567d7225976ad9145e866c7a7dccc6c277ea86abbd268fbac95f1c73ffffffffffffffffffffffffffffffffffffffff16836040516020016101519190610242565b60405160208183030381529060405260405161016d91906102ad565b5f60405180830381855afa9150503d805f81146101a5576040519150601f19603f3d011682016040523d82523d5f602084013e6101aa565b606091505b505090508082906101f1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101e89190610325565b60405180910390fd5b50505050565b5f819050919050565b610209816101f7565b82525050565b5f6020820190506102225f830184610200565b92915050565b5f8115159050919050565b61023c81610228565b82525050565b5f6020820190506102555f830184610233565b92915050565b5f81519050919050565b5f81905092915050565b8281835e5f83830152505050565b5f6102878261025b565b6102918185610265565b93506102a181856020860161026f565b80840191505092915050565b5f6102b8828461027d565b915081905092915050565b5f81519050919050565b5f82825260208201905092915050565b5f601f19601f8301169050919050565b5f6102f7826102c3565b61030181856102cd565b935061031181856020860161026f565b61031a816102dd565b840191505092915050565b5f6020820190508181035f83015261033d81846102ed565b90509291505056 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@Rg\r\xE0\xB6\xB3\xA7d\0\0_U4\x80\x15`\x19W__\xFD[Pa\x03E\x80a\0'_9_\xF3\xFE`\x80`@R4\x80\x15a\0\x0FW__\xFD[P`\x046\x10a\x004W_5`\xE0\x1C\x80cZ{V\xA3\x14a\08W\x80ca\xBA\xFF\xE6\x14a\0VW[__\xFD[a\0@a\0`V[`@Qa\0M\x91\x90a\x02\x0FV[`@Q\x80\x91\x03\x90\xF3[a\0^a\0eV[\0[_T\x81V[3a\0\xC0_T\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x161\x10\x15`@Q\x80`@\x01`@R\x80`\x18\x81R` \x01\x7FNot enough Ether balance\0\0\0\0\0\0\0\0\x81RPa\x01\x06V[3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\x11Q\x1A\x10V\xAF\x15*Q\xF7\x92\"\xBEz\x07O}\x19\xB5\xA149\xCD6#dyyv\xFEl\xB3`@Q`@Q\x80\x91\x03\x90\xA2PV[_\x7F=\xCD\xF6;A\xC1\x03V}r%\x97j\xD9\x14^\x86lz}\xCC\xC6\xC2w\xEA\x86\xAB\xBD&\x8F\xBA\xC9_\x1Cs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x83`@Q` \x01a\x01Q\x91\x90a\x02BV[`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Qa\x01m\x91\x90a\x02\xADV[_`@Q\x80\x83\x03\x81\x85Z\xFA\x91PP=\x80_\x81\x14a\x01\xA5W`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=_` \x84\x01>a\x01\xAAV[``\x91P[PP\x90P\x80\x82\x90a\x01\xF1W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x01\xE8\x91\x90a\x03%V[`@Q\x80\x91\x03\x90\xFD[PPPPV[_\x81\x90P\x91\x90PV[a\x02\t\x81a\x01\xF7V[\x82RPPV[_` \x82\x01\x90Pa\x02\"_\x83\x01\x84a\x02\0V[\x92\x91PPV[_\x81\x15\x15\x90P\x91\x90PV[a\x02<\x81a\x02(V[\x82RPPV[_` \x82\x01\x90Pa\x02U_\x83\x01\x84a\x023V[\x92\x91PPV[_\x81Q\x90P\x91\x90PV[_\x81\x90P\x92\x91PPV[\x82\x81\x83^_\x83\x83\x01RPPPV[_a\x02\x87\x82a\x02[V[a\x02\x91\x81\x85a\x02eV[\x93Pa\x02\xA1\x81\x85` \x86\x01a\x02oV[\x80\x84\x01\x91PP\x92\x91PPV[_a\x02\xB8\x82\x84a\x02}V[\x91P\x81\x90P\x92\x91PPV[_\x81Q\x90P\x91\x90PV[_\x82\x82R` \x82\x01\x90P\x92\x91PPV[_`\x1F\x19`\x1F\x83\x01\x16\x90P\x91\x90PV[_a\x02\xF7\x82a\x02\xC3V[a\x03\x01\x81\x85a\x02\xCDV[\x93Pa\x03\x11\x81\x85` \x86\x01a\x02oV[a\x03\x1A\x81a\x02\xDDV[\x84\x01\x91PP\x92\x91PPV[_` \x82\x01\x90P\x81\x81\x03_\x83\x01Ra\x03=\x81\x84a\x02\xEDV[\x90P\x92\x91PPV", + ); + /// The runtime bytecode of the contract, as deployed on the network. + /// + /// ```text + ///0x608060405234801561000f575f5ffd5b5060043610610034575f3560e01c80635a7b56a31461003857806361baffe614610056575b5f5ffd5b610040610060565b60405161004d919061020f565b60405180910390f35b61005e610065565b005b5f5481565b336100c05f548273ffffffffffffffffffffffffffffffffffffffff163110156040518060400160405280601881526020017f4e6f7420656e6f7567682045746865722062616c616e63650000000000000000815250610106565b3373ffffffffffffffffffffffffffffffffffffffff167f11511a1056af152a51f79222be7a074f7d19b5a13439cd362364797976fe6cb360405160405180910390a250565b5f7f3dcdf63b41c103567d7225976ad9145e866c7a7dccc6c277ea86abbd268fbac95f1c73ffffffffffffffffffffffffffffffffffffffff16836040516020016101519190610242565b60405160208183030381529060405260405161016d91906102ad565b5f60405180830381855afa9150503d805f81146101a5576040519150601f19603f3d011682016040523d82523d5f602084013e6101aa565b606091505b505090508082906101f1576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016101e89190610325565b60405180910390fd5b50505050565b5f819050919050565b610209816101f7565b82525050565b5f6020820190506102225f830184610200565b92915050565b5f8115159050919050565b61023c81610228565b82525050565b5f6020820190506102555f830184610233565b92915050565b5f81519050919050565b5f81905092915050565b8281835e5f83830152505050565b5f6102878261025b565b6102918185610265565b93506102a181856020860161026f565b80840191505092915050565b5f6102b8828461027d565b915081905092915050565b5f81519050919050565b5f82825260208201905092915050565b5f601f19601f8301169050919050565b5f6102f7826102c3565b61030181856102cd565b935061031181856020860161026f565b61031a816102dd565b840191505092915050565b5f6020820190508181035f83015261033d81846102ed565b90509291505056 + /// ``` + #[rustfmt::skip] + #[allow(clippy::all)] + pub static DEPLOYED_BYTECODE: alloy_sol_types::private::Bytes = alloy_sol_types::private::Bytes::from_static( + b"`\x80`@R4\x80\x15a\0\x0FW__\xFD[P`\x046\x10a\x004W_5`\xE0\x1C\x80cZ{V\xA3\x14a\08W\x80ca\xBA\xFF\xE6\x14a\0VW[__\xFD[a\0@a\0`V[`@Qa\0M\x91\x90a\x02\x0FV[`@Q\x80\x91\x03\x90\xF3[a\0^a\0eV[\0[_T\x81V[3a\0\xC0_T\x82s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x161\x10\x15`@Q\x80`@\x01`@R\x80`\x18\x81R` \x01\x7FNot enough Ether balance\0\0\0\0\0\0\0\0\x81RPa\x01\x06V[3s\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x7F\x11Q\x1A\x10V\xAF\x15*Q\xF7\x92\"\xBEz\x07O}\x19\xB5\xA149\xCD6#dyyv\xFEl\xB3`@Q`@Q\x80\x91\x03\x90\xA2PV[_\x7F=\xCD\xF6;A\xC1\x03V}r%\x97j\xD9\x14^\x86lz}\xCC\xC6\xC2w\xEA\x86\xAB\xBD&\x8F\xBA\xC9_\x1Cs\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x16\x83`@Q` \x01a\x01Q\x91\x90a\x02BV[`@Q` \x81\x83\x03\x03\x81R\x90`@R`@Qa\x01m\x91\x90a\x02\xADV[_`@Q\x80\x83\x03\x81\x85Z\xFA\x91PP=\x80_\x81\x14a\x01\xA5W`@Q\x91P`\x1F\x19`?=\x01\x16\x82\x01`@R=\x82R=_` \x84\x01>a\x01\xAAV[``\x91P[PP\x90P\x80\x82\x90a\x01\xF1W`@Q\x7F\x08\xC3y\xA0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x81R`\x04\x01a\x01\xE8\x91\x90a\x03%V[`@Q\x80\x91\x03\x90\xFD[PPPPV[_\x81\x90P\x91\x90PV[a\x02\t\x81a\x01\xF7V[\x82RPPV[_` \x82\x01\x90Pa\x02\"_\x83\x01\x84a\x02\0V[\x92\x91PPV[_\x81\x15\x15\x90P\x91\x90PV[a\x02<\x81a\x02(V[\x82RPPV[_` \x82\x01\x90Pa\x02U_\x83\x01\x84a\x023V[\x92\x91PPV[_\x81Q\x90P\x91\x90PV[_\x81\x90P\x92\x91PPV[\x82\x81\x83^_\x83\x83\x01RPPPV[_a\x02\x87\x82a\x02[V[a\x02\x91\x81\x85a\x02eV[\x93Pa\x02\xA1\x81\x85` \x86\x01a\x02oV[\x80\x84\x01\x91PP\x92\x91PPV[_a\x02\xB8\x82\x84a\x02}V[\x91P\x81\x90P\x92\x91PPV[_\x81Q\x90P\x91\x90PV[_\x82\x82R` \x82\x01\x90P\x92\x91PPV[_`\x1F\x19`\x1F\x83\x01\x16\x90P\x91\x90PV[_a\x02\xF7\x82a\x02\xC3V[a\x03\x01\x81\x85a\x02\xCDV[\x93Pa\x03\x11\x81\x85` \x86\x01a\x02oV[a\x03\x1A\x81a\x02\xDDV[\x84\x01\x91PP\x92\x91PPV[_` \x82\x01\x90P\x81\x81\x03_\x83\x01Ra\x03=\x81\x84a\x02\xEDV[\x90P\x92\x91PPV", + ); + #[derive(serde::Serialize, serde::Deserialize)] + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Event with signature `ActionAllowed(address)` and selector `0x11511a1056af152a51f79222be7a074f7d19b5a13439cd362364797976fe6cb3`. +```solidity +event ActionAllowed(address indexed account); +```*/ + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + #[derive(Clone)] + pub struct ActionAllowed { + #[allow(missing_docs)] + pub account: alloy::sol_types::private::Address, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy::sol_types as alloy_sol_types; + #[automatically_derived] + impl alloy_sol_types::SolEvent for ActionAllowed { + type DataTuple<'a> = (); + type DataToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + type TopicList = ( + alloy_sol_types::sol_data::FixedBytes<32>, + alloy::sol_types::sol_data::Address, + ); + const SIGNATURE: &'static str = "ActionAllowed(address)"; + const SIGNATURE_HASH: alloy_sol_types::private::B256 = alloy_sol_types::private::B256::new([ + 17u8, 81u8, 26u8, 16u8, 86u8, 175u8, 21u8, 42u8, 81u8, 247u8, 146u8, + 34u8, 190u8, 122u8, 7u8, 79u8, 125u8, 25u8, 181u8, 161u8, 52u8, 57u8, + 205u8, 54u8, 35u8, 100u8, 121u8, 121u8, 118u8, 254u8, 108u8, 179u8, + ]); + const ANONYMOUS: bool = false; + #[allow(unused_variables)] + #[inline] + fn new( + topics: ::RustType, + data: as alloy_sol_types::SolType>::RustType, + ) -> Self { + Self { account: topics.1 } + } + #[inline] + fn check_signature( + topics: &::RustType, + ) -> alloy_sol_types::Result<()> { + if topics.0 != Self::SIGNATURE_HASH { + return Err( + alloy_sol_types::Error::invalid_event_signature_hash( + Self::SIGNATURE, + topics.0, + Self::SIGNATURE_HASH, + ), + ); + } + Ok(()) + } + #[inline] + fn tokenize_body(&self) -> Self::DataToken<'_> { + () + } + #[inline] + fn topics(&self) -> ::RustType { + (Self::SIGNATURE_HASH.into(), self.account.clone()) + } + #[inline] + fn encode_topics_raw( + &self, + out: &mut [alloy_sol_types::abi::token::WordToken], + ) -> alloy_sol_types::Result<()> { + if out.len() < ::COUNT { + return Err(alloy_sol_types::Error::Overrun); + } + out[0usize] = alloy_sol_types::abi::token::WordToken( + Self::SIGNATURE_HASH, + ); + out[1usize] = ::encode_topic( + &self.account, + ); + Ok(()) + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for ActionAllowed { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + From::from(self) + } + fn into_log_data(self) -> alloy_sol_types::private::LogData { + From::from(&self) + } + } + #[automatically_derived] + impl From<&ActionAllowed> for alloy_sol_types::private::LogData { + #[inline] + fn from(this: &ActionAllowed) -> alloy_sol_types::private::LogData { + alloy_sol_types::SolEvent::encode_log_data(this) + } + } + }; + #[derive(serde::Serialize, serde::Deserialize)] + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `etherThreshold()` and selector `0x5a7b56a3`. +```solidity +function etherThreshold() external view returns (uint256); +```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct etherThresholdCall; + #[derive(serde::Serialize, serde::Deserialize)] + #[derive(Default, Debug, PartialEq, Eq, Hash)] + ///Container type for the return parameters of the [`etherThreshold()`](etherThresholdCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct etherThresholdReturn { + #[allow(missing_docs)] + pub _0: alloy::sol_types::private::primitives::aliases::U256, + } + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy::sol_types as alloy_sol_types; + { + #[doc(hidden)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion( + _t: alloy_sol_types::private::AssertTypeEq, + ) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From for UnderlyingRustTuple<'_> { + fn from(value: etherThresholdCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> for etherThresholdCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + type UnderlyingSolTuple<'a> = (alloy::sol_types::sol_data::Uint<256>,); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = ( + alloy::sol_types::private::primitives::aliases::U256, + ); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion( + _t: alloy_sol_types::private::AssertTypeEq, + ) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From + for UnderlyingRustTuple<'_> { + fn from(value: etherThresholdReturn) -> Self { + (value._0,) + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> + for etherThresholdReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self { _0: tuple.0 } + } + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for etherThresholdCall { + type Parameters<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + type Return = alloy::sol_types::private::primitives::aliases::U256; + type ReturnTuple<'a> = (alloy::sol_types::sol_data::Uint<256>,); + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + const SIGNATURE: &'static str = "etherThreshold()"; + const SELECTOR: [u8; 4] = [90u8, 123u8, 86u8, 163u8]; + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + ( + as alloy_sol_types::SolType>::tokenize(ret), + ) + } + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(|r| { + let r: etherThresholdReturn = r.into(); + r._0 + }) + } + #[inline] + fn abi_decode_returns_validate( + data: &[u8], + ) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate(data) + .map(|r| { + let r: etherThresholdReturn = r.into(); + r._0 + }) + } + } + }; + #[derive(serde::Serialize, serde::Deserialize)] + #[derive(Default, Debug, PartialEq, Eq, Hash)] + /**Function with signature `restrictedAction()` and selector `0x61baffe6`. +```solidity +function restrictedAction() external; +```*/ + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct restrictedActionCall; + ///Container type for the return parameters of the [`restrictedAction()`](restrictedActionCall) function. + #[allow(non_camel_case_types, non_snake_case, clippy::pub_underscore_fields)] + #[derive(Clone)] + pub struct restrictedActionReturn {} + #[allow( + non_camel_case_types, + non_snake_case, + clippy::pub_underscore_fields, + clippy::style + )] + const _: () = { + use alloy::sol_types as alloy_sol_types; + { + #[doc(hidden)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion( + _t: alloy_sol_types::private::AssertTypeEq, + ) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From + for UnderlyingRustTuple<'_> { + fn from(value: restrictedActionCall) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> + for restrictedActionCall { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self + } + } + } + { + #[doc(hidden)] + type UnderlyingSolTuple<'a> = (); + #[doc(hidden)] + type UnderlyingRustTuple<'a> = (); + #[cfg(test)] + #[allow(dead_code, unreachable_patterns)] + fn _type_assertion( + _t: alloy_sol_types::private::AssertTypeEq, + ) { + match _t { + alloy_sol_types::private::AssertTypeEq::< + ::RustType, + >(_) => {} + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From + for UnderlyingRustTuple<'_> { + fn from(value: restrictedActionReturn) -> Self { + () + } + } + #[automatically_derived] + #[doc(hidden)] + impl ::core::convert::From> + for restrictedActionReturn { + fn from(tuple: UnderlyingRustTuple<'_>) -> Self { + Self {} + } + } + } + impl restrictedActionReturn { + fn _tokenize( + &self, + ) -> ::ReturnToken<'_> { + () + } + } + #[automatically_derived] + impl alloy_sol_types::SolCall for restrictedActionCall { + type Parameters<'a> = (); + type Token<'a> = as alloy_sol_types::SolType>::Token<'a>; + type Return = restrictedActionReturn; + type ReturnTuple<'a> = (); + type ReturnToken<'a> = as alloy_sol_types::SolType>::Token<'a>; + const SIGNATURE: &'static str = "restrictedAction()"; + const SELECTOR: [u8; 4] = [97u8, 186u8, 255u8, 230u8]; + #[inline] + fn new<'a>( + tuple: as alloy_sol_types::SolType>::RustType, + ) -> Self { + tuple.into() + } + #[inline] + fn tokenize(&self) -> Self::Token<'_> { + () + } + #[inline] + fn tokenize_returns(ret: &Self::Return) -> Self::ReturnToken<'_> { + restrictedActionReturn::_tokenize(ret) + } + #[inline] + fn abi_decode_returns(data: &[u8]) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence(data) + .map(Into::into) + } + #[inline] + fn abi_decode_returns_validate( + data: &[u8], + ) -> alloy_sol_types::Result { + as alloy_sol_types::SolType>::abi_decode_sequence_validate(data) + .map(Into::into) + } + } + }; + ///Container for all the [`QuorumRestrictedAction`](self) function calls. + #[derive(serde::Serialize, serde::Deserialize)] + #[derive()] + pub enum QuorumRestrictedActionCalls { + #[allow(missing_docs)] + etherThreshold(etherThresholdCall), + #[allow(missing_docs)] + restrictedAction(restrictedActionCall), + } + #[automatically_derived] + impl QuorumRestrictedActionCalls { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the variants. + /// No guarantees are made about the order of the selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 4usize]] = &[ + [90u8, 123u8, 86u8, 163u8], + [97u8, 186u8, 255u8, 230u8], + ]; + } + #[automatically_derived] + impl alloy_sol_types::SolInterface for QuorumRestrictedActionCalls { + const NAME: &'static str = "QuorumRestrictedActionCalls"; + const MIN_DATA_LENGTH: usize = 0usize; + const COUNT: usize = 2usize; + #[inline] + fn selector(&self) -> [u8; 4] { + match self { + Self::etherThreshold(_) => { + ::SELECTOR + } + Self::restrictedAction(_) => { + ::SELECTOR + } + } + } + #[inline] + fn selector_at(i: usize) -> ::core::option::Option<[u8; 4]> { + Self::SELECTORS.get(i).copied() + } + #[inline] + fn valid_selector(selector: [u8; 4]) -> bool { + Self::SELECTORS.binary_search(&selector).is_ok() + } + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result] = &[ + { + fn etherThreshold( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(QuorumRestrictedActionCalls::etherThreshold) + } + etherThreshold + }, + { + fn restrictedAction( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw( + data, + ) + .map(QuorumRestrictedActionCalls::restrictedAction) + } + restrictedAction + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err( + alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + ), + ); + }; + DECODE_SHIMS[idx](data) + } + #[inline] + #[allow(non_snake_case)] + fn abi_decode_raw_validate( + selector: [u8; 4], + data: &[u8], + ) -> alloy_sol_types::Result { + static DECODE_VALIDATE_SHIMS: &[fn( + &[u8], + ) -> alloy_sol_types::Result] = &[ + { + fn etherThreshold( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(QuorumRestrictedActionCalls::etherThreshold) + } + etherThreshold + }, + { + fn restrictedAction( + data: &[u8], + ) -> alloy_sol_types::Result { + ::abi_decode_raw_validate( + data, + ) + .map(QuorumRestrictedActionCalls::restrictedAction) + } + restrictedAction + }, + ]; + let Ok(idx) = Self::SELECTORS.binary_search(&selector) else { + return Err( + alloy_sol_types::Error::unknown_selector( + ::NAME, + selector, + ), + ); + }; + DECODE_VALIDATE_SHIMS[idx](data) + } + #[inline] + fn abi_encoded_size(&self) -> usize { + match self { + Self::etherThreshold(inner) => { + ::abi_encoded_size( + inner, + ) + } + Self::restrictedAction(inner) => { + ::abi_encoded_size( + inner, + ) + } + } + } + #[inline] + fn abi_encode_raw(&self, out: &mut alloy_sol_types::private::Vec) { + match self { + Self::etherThreshold(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + Self::restrictedAction(inner) => { + ::abi_encode_raw( + inner, + out, + ) + } + } + } + } + ///Container for all the [`QuorumRestrictedAction`](self) events. + #[derive(serde::Serialize, serde::Deserialize)] + #[derive(Debug, PartialEq, Eq, Hash)] + pub enum QuorumRestrictedActionEvents { + #[allow(missing_docs)] + ActionAllowed(ActionAllowed), + } + #[automatically_derived] + impl QuorumRestrictedActionEvents { + /// All the selectors of this enum. + /// + /// Note that the selectors might not be in the same order as the variants. + /// No guarantees are made about the order of the selectors. + /// + /// Prefer using `SolInterface` methods instead. + pub const SELECTORS: &'static [[u8; 32usize]] = &[ + [ + 17u8, 81u8, 26u8, 16u8, 86u8, 175u8, 21u8, 42u8, 81u8, 247u8, 146u8, + 34u8, 190u8, 122u8, 7u8, 79u8, 125u8, 25u8, 181u8, 161u8, 52u8, 57u8, + 205u8, 54u8, 35u8, 100u8, 121u8, 121u8, 118u8, 254u8, 108u8, 179u8, + ], + ]; + } + #[automatically_derived] + impl alloy_sol_types::SolEventInterface for QuorumRestrictedActionEvents { + const NAME: &'static str = "QuorumRestrictedActionEvents"; + const COUNT: usize = 1usize; + fn decode_raw_log( + topics: &[alloy_sol_types::Word], + data: &[u8], + ) -> alloy_sol_types::Result { + match topics.first().copied() { + Some(::SIGNATURE_HASH) => { + ::decode_raw_log( + topics, + data, + ) + .map(Self::ActionAllowed) + } + _ => { + alloy_sol_types::private::Err(alloy_sol_types::Error::InvalidLog { + name: ::NAME, + log: alloy_sol_types::private::Box::new( + alloy_sol_types::private::LogData::new_unchecked( + topics.to_vec(), + data.to_vec().into(), + ), + ), + }) + } + } + } + } + #[automatically_derived] + impl alloy_sol_types::private::IntoLogData for QuorumRestrictedActionEvents { + fn to_log_data(&self) -> alloy_sol_types::private::LogData { + match self { + Self::ActionAllowed(inner) => { + alloy_sol_types::private::IntoLogData::to_log_data(inner) + } + } + } + fn into_log_data(self) -> alloy_sol_types::private::LogData { + match self { + Self::ActionAllowed(inner) => { + alloy_sol_types::private::IntoLogData::into_log_data(inner) + } + } + } + } + use alloy::contract as alloy_contract; + /**Creates a new wrapper around an on-chain [`QuorumRestrictedAction`](self) contract instance. + +See the [wrapper's documentation](`QuorumRestrictedActionInstance`) for more details.*/ + #[inline] + pub const fn new< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + address: alloy_sol_types::private::Address, + provider: P, + ) -> QuorumRestrictedActionInstance { + QuorumRestrictedActionInstance::::new(address, provider) + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + +Returns a new instance of the contract, if the deployment was successful. + +For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub fn deploy< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >( + provider: P, + ) -> impl ::core::future::Future< + Output = alloy_contract::Result>, + > { + QuorumRestrictedActionInstance::::deploy(provider) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` +and constructor arguments, if any. + +This is a simple wrapper around creating a `RawCallBuilder` with the data set to +the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + >(provider: P) -> alloy_contract::RawCallBuilder { + QuorumRestrictedActionInstance::::deploy_builder(provider) + } + /**A [`QuorumRestrictedAction`](self) instance. + +Contains type-safe methods for interacting with an on-chain instance of the +[`QuorumRestrictedAction`](self) contract located at a given `address`, using a given +provider `P`. + +If the contract bytecode is available (see the [`sol!`](alloy_sol_types::sol!) +documentation on how to provide it), the `deploy` and `deploy_builder` methods can +be used to deploy a new instance of the contract. + +See the [module-level documentation](self) for all the available methods.*/ + #[derive(Clone)] + pub struct QuorumRestrictedActionInstance { + address: alloy_sol_types::private::Address, + provider: P, + _network: ::core::marker::PhantomData, + } + #[automatically_derived] + impl ::core::fmt::Debug for QuorumRestrictedActionInstance { + #[inline] + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple("QuorumRestrictedActionInstance").field(&self.address).finish() + } + } + /// Instantiation and getters/setters. + #[automatically_derived] + impl< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + > QuorumRestrictedActionInstance { + /**Creates a new wrapper around an on-chain [`QuorumRestrictedAction`](self) contract instance. + +See the [wrapper's documentation](`QuorumRestrictedActionInstance`) for more details.*/ + #[inline] + pub const fn new( + address: alloy_sol_types::private::Address, + provider: P, + ) -> Self { + Self { + address, + provider, + _network: ::core::marker::PhantomData, + } + } + /**Deploys this contract using the given `provider` and constructor arguments, if any. + +Returns a new instance of the contract, if the deployment was successful. + +For more fine-grained control over the deployment process, use [`deploy_builder`] instead.*/ + #[inline] + pub async fn deploy( + provider: P, + ) -> alloy_contract::Result> { + let call_builder = Self::deploy_builder(provider); + let contract_address = call_builder.deploy().await?; + Ok(Self::new(contract_address, call_builder.provider)) + } + /**Creates a `RawCallBuilder` for deploying this contract using the given `provider` +and constructor arguments, if any. + +This is a simple wrapper around creating a `RawCallBuilder` with the data set to +the bytecode concatenated with the constructor's ABI-encoded arguments.*/ + #[inline] + pub fn deploy_builder(provider: P) -> alloy_contract::RawCallBuilder { + alloy_contract::RawCallBuilder::new_raw_deploy( + provider, + ::core::clone::Clone::clone(&BYTECODE), + ) + } + /// Returns a reference to the address. + #[inline] + pub const fn address(&self) -> &alloy_sol_types::private::Address { + &self.address + } + /// Sets the address. + #[inline] + pub fn set_address(&mut self, address: alloy_sol_types::private::Address) { + self.address = address; + } + /// Sets the address and returns `self`. + pub fn at(mut self, address: alloy_sol_types::private::Address) -> Self { + self.set_address(address); + self + } + /// Returns a reference to the provider. + #[inline] + pub const fn provider(&self) -> &P { + &self.provider + } + } + impl QuorumRestrictedActionInstance<&P, N> { + /// Clones the provider and returns a new instance with the cloned provider. + #[inline] + pub fn with_cloned_provider(self) -> QuorumRestrictedActionInstance { + QuorumRestrictedActionInstance { + address: self.address, + provider: ::core::clone::Clone::clone(&self.provider), + _network: ::core::marker::PhantomData, + } + } + } + /// Function calls. + #[automatically_derived] + impl< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + > QuorumRestrictedActionInstance { + /// Creates a new call builder using this contract instance's provider and address. + /// + /// Note that the call can be any function call, not just those defined in this + /// contract. Prefer using the other methods for building type-safe contract calls. + pub fn call_builder( + &self, + call: &C, + ) -> alloy_contract::SolCallBuilder<&P, C, N> { + alloy_contract::SolCallBuilder::new_sol(&self.provider, &self.address, call) + } + ///Creates a new call builder for the [`etherThreshold`] function. + pub fn etherThreshold( + &self, + ) -> alloy_contract::SolCallBuilder<&P, etherThresholdCall, N> { + self.call_builder(ðerThresholdCall) + } + ///Creates a new call builder for the [`restrictedAction`] function. + pub fn restrictedAction( + &self, + ) -> alloy_contract::SolCallBuilder<&P, restrictedActionCall, N> { + self.call_builder(&restrictedActionCall) + } + } + /// Event filters. + #[automatically_derived] + impl< + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + > QuorumRestrictedActionInstance { + /// Creates a new event filter using this contract instance's provider and address. + /// + /// Note that the type can be any event, not just those defined in this contract. + /// Prefer using the other methods for building type-safe event filters. + pub fn event_filter( + &self, + ) -> alloy_contract::Event<&P, E, N> { + alloy_contract::Event::new_sol(&self.provider, &self.address) + } + ///Creates a new event filter for the [`ActionAllowed`] event. + pub fn ActionAllowed_filter( + &self, + ) -> alloy_contract::Event<&P, ActionAllowed, N> { + self.event_filter::() + } + } +} diff --git a/examples/solidity/src/Auction.sol b/examples/solidity/src/Auction.sol index 8caadd35..c3b48f7c 100644 --- a/examples/solidity/src/Auction.sol +++ b/examples/solidity/src/Auction.sol @@ -10,6 +10,11 @@ contract Auction { ); /** + * @notice Submit a bid for an auction + * @param auction_id The ID of the auction + * @param deadline The deadline for the auction + * @param value The bid value + * @param data Additional data for the bid * @notice deadline in microseconds */ function submitBid(uint256 auction_id, Time.Timestamp deadline, uint256 value, bytes calldata data) public { diff --git a/examples/solidity/src/EthereumERC20Balance.sol b/examples/solidity/src/EthereumERC20Balance.sol new file mode 100644 index 00000000..57f24f90 --- /dev/null +++ b/examples/solidity/src/EthereumERC20Balance.sol @@ -0,0 +1,34 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {IERC20} from "openzeppelin-contracts/token/ERC20/IERC20.sol"; +import {Transaction, EthCallArgs, externalEthCall} from "pod-sdk/ExternalEthCall.sol"; + +/// @title EthereumERC20Balance +contract EthereumERC20Balance { + uint256 internal constant ETH_CHAIN_ID = 1; + address internal constant ETH_USDC_CONTRACT = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + + /// @notice Returns the USDC balance for `account` on Ethereum mainnet. + /// @param account The account to query on Ethereum. + /// @return balance The USDC balance in base units. + /// @dev Builds ERC-20 calldata and delegates to the external-call precompile. Reverts on failure. + function getUSDCBalanceEthereum(address account) public view returns (uint256) { + bytes memory data = bytes.concat(IERC20.balanceOf.selector, abi.encode(account)); + + EthCallArgs memory callArgs = EthCallArgs({ + transaction: Transaction({ + from: address(0), + to: ETH_USDC_CONTRACT, + gas: 100000, + gasPrice: 1000, + value: 0, + data: data + }), + blockNumber: bytes("latest") + }); + + bytes memory result = externalEthCall(ETH_CHAIN_ID, callArgs); + return abi.decode(result, (uint256)); + } +} diff --git a/examples/solidity/src/QuorumRestrictedAction.sol b/examples/solidity/src/QuorumRestrictedAction.sol new file mode 100644 index 00000000..8181a9a4 --- /dev/null +++ b/examples/solidity/src/QuorumRestrictedAction.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {requireQuorum} from "pod-sdk/Quorum.sol"; + +/// @title QuorumRestrictedAction +/// @notice Demonstrates gating function execution on quorum over a boolean predicate. +contract QuorumRestrictedAction { + uint256 public etherThreshold = 1 ether; + + event ActionAllowed(address indexed account); + + /// @notice Reverts unless there is validator quorum over the predicate + /// `account.balance >= etherThreshold`. + /// @param account The account whose Ether balance is checked. + modifier requireEnoughEther(address account) { + requireQuorum(account.balance >= etherThreshold, "Not enough Ether balance"); + _; + } + + /// @notice Example function restricted to callers whose Ether balance meets `etherThreshold`. + /// @dev Emits an `ActionAllowed` event on success. + function restrictedAction() public requireEnoughEther(msg.sender) { + emit ActionAllowed(msg.sender); + } +} diff --git a/solidity-sdk/src/ExternalEthCall.sol b/solidity-sdk/src/ExternalEthCall.sol new file mode 100644 index 00000000..b7c167e2 --- /dev/null +++ b/solidity-sdk/src/ExternalEthCall.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.28; + +address constant POD_EXTERNAL_ETH_CALL = address(uint160(uint256(keccak256("POD_EXTERNAL_ETH_CALL")))); + +/** + * @notice An Ethereum transaction data structure. + * @param from The address of the sender. + * @param to The address of the contract to call. + * @param gas The gas limit for the transaction. + * @param gasPrice The gas price in wei for the transaction. + * @param value The value in wei to send with the transaction. + * @param data The calldata to send with the transaction. + */ +struct Transaction { + address from; + address to; + uint256 gas; + uint256 gasPrice; + uint256 value; + bytes data; +} + +/** + * @notice The arguments used to call an external Ethereum contract. + * @param transaction The transaction to call the external contract with. + * @param blockNumber The block number to use for the transaction. + */ +struct EthCallArgs { + Transaction transaction; + bytes blockNumber; +} + +/** + * @notice Call an external Ethereum contract. + * @param chainId The chain ID of the Ethereum network. + * @param callArgs The arguments used to call the external contract. + * @return The result of the external call. Reverts if the call fails. + */ +function externalEthCall(uint256 chainId, EthCallArgs memory callArgs) view returns (bytes memory) { + (bool success, bytes memory output) = + POD_EXTERNAL_ETH_CALL.staticcall{gas: gasleft()}(abi.encode(chainId, callArgs)); + require(success, "Precompile call failed"); + return output; +} diff --git a/solidity-sdk/src/ExternalEthGetLogs.sol b/solidity-sdk/src/ExternalEthGetLogs.sol new file mode 100644 index 00000000..ba235120 --- /dev/null +++ b/solidity-sdk/src/ExternalEthGetLogs.sol @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +/// @dev An ethereum log object. +/// @param addr The address of the log's emitter. +/// @param topics The topics of the log, including the signature, if any. +/// @param data The raw data of the log. +/// @param blockNumber The block number. +/// @param transactionHash The transaction hash. +/// @param transactionIndex The transaction index in the block. +/// @param blockHash The block hash. +/// @param logIndex The log index. +/// @param removed Whether the log was removed. +struct RpcLog { + address addr; + bytes32[] topics; + bytes data; + bytes blockNumber; + bytes32 transactionHash; + bytes transactionIndex; + bytes32 blockHash; + bytes logIndex; + bool removed; +} + +/// @dev The arguments for `eth_getLogs`. +/// @param fromBlock The block number to start searching from. +/// @param toBlock The block number to stop searching at. +/// @param addr The address of the log's emitter. +/// @param blockHash The block hash to search within. +/// @param topics The topics of the log, including the signature, if any. +struct EthGetLogsArgs { + bytes fromBlock; + bytes toBlock; + address addr; + bytes32 blockHash; + bytes32[] topics; +} + +address constant EXTERNAL_ETH_GET_LOGS_PRECOMPILE = address(uint160(uint256(keccak256("POD_EXTERNAL_ETH_GET_LOGS")))); +uint256 constant ETH_CHAIN_ID = 1; + +/// @notice Returns an array of event logs matching the given filter criteria. +/// @param args The arguments for `eth_getLogs`. +/// @return logs The array of event logs. +/// @dev Builds the input data and delegates to the external-get-logs precompile. Reverts on failure. +function getLogs(EthGetLogsArgs memory args) view returns (RpcLog[] memory) { + bytes memory input = abi.encode(ETH_CHAIN_ID, args); + + (bool success, bytes memory data) = EXTERNAL_ETH_GET_LOGS_PRECOMPILE.staticcall(input); + if (!success) { + revert("ExternalEthGetLogs: call failed"); + } + + RpcLog[] memory logs = abi.decode(data, (RpcLog[])); + + return logs; +}