+
+
+
+```JavaScript
+import { ethers } from "ethers";
+import {
+ getAddress,
+} from "viem";
+
+const rollup_server = process.env.ROLLUP_HTTP_SERVER_URL;
+console.log("HTTP rollup_server url is " + rollup_server);
+
+const PORTAL_ADDRESS = "0xc700D6aDd016eECd59d989C028214Eaa0fCC0051";
+
+
+function parseDepositPayload(payload) {
+ const tokenData = ethers.dataSlice(payload, 0, 20);
+ const senderData = ethers.dataSlice(payload, 20, 40);
+ const amountData = ethers.dataSlice(payload, 40, 72);
+
+ if (!tokenData) {
+ throw new Error("Invalid deposit payload");
+ }
+ return [getAddress(tokenData), getAddress(senderData), BigInt(amountData)];
+ }
+
+async function handle_advance(data) {
+ console.log("Received advance request data " + JSON.stringify(data));
+ let payload = data.payload;
+ const sender = data["metadata"]["msg_sender"];
+
+ if (sender.toLowerCase() === PORTAL_ADDRESS.toLowerCase()) {
+ console.log("Handling portal deposit");
+ const [token, depositor, amount] = parseDepositPayload(payload);
+ console.log(`Token: ${token}, Depositor: ${depositor}, Amount: ${amount}`);
+
+ // Handle deposit logic here
+ } else {
+ // Handle Transaction request like a regular transaction
+ }
+
+ return "accept";
+}
+
+async function handle_inspect(data) {
+ console.log("Received inspect request data " + JSON.stringify(data));
+ return "accept";
+}
+
+var handlers = {
+ advance_state: handle_advance,
+ inspect_state: handle_inspect,
+};
+
+var finish = { status: "accept" };
+
+(async () => {
+ while (true) {
+ const finish_req = await fetch(rollup_server + "/finish", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ status: "accept" }),
+ });
+
+ console.log("Received finish status " + finish_req.status);
+
+ if (finish_req.status == 202) {
+ console.log("No pending rollup request, trying again");
+ } else {
+ const rollup_req = await finish_req.json();
+ var handler = handlers[rollup_req["request_type"]];
+ finish["status"] = await handler(rollup_req["data"]);
+ }
+ }
+})();
+```
+
+
+
+
+
+
+
+```Rust
+use json::{object, JsonValue};
+use primitive_types::{H160, U256};
+use std::env;
+use hex::FromHex;
+use std::error::Error;
+use std::io;
+
+pub async fn parse_deposit_payload(
+ payload: &str
+) -> Result<(String, String, U256), Box> {
+
+ let clean = payload.trim().trim_start_matches("0x");
+
+ let bytes: Vec = Vec::from_hex(clean).map_err(|e| -> Box { e.into() })?;
+
+ const TOKEN_ADDR_LEN: usize = 20;
+ const DEPOSITOR_ADDR_LEN: usize = 20;
+ const AMOUNT_LEN: usize = 32;
+ const MIN_LEN: usize = TOKEN_ADDR_LEN + DEPOSITOR_ADDR_LEN + AMOUNT_LEN;
+
+ if bytes.len() < MIN_LEN {
+ return Err(io::Error::new(io::ErrorKind::InvalidData, "payload too short").into());
+ }
+
+ let token_addr_bytes = bytes.get(0..20)
+ .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "token address slice"))?;
+ let depositor_addr_bytes = bytes.get(20..40)
+ .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "depositor address slice"))?;
+ let token_amount_32 = bytes.get(40..72)
+ .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "token id slice"))?;
+
+ let token_address = format!("0x{}", hex::encode(token_addr_bytes));
+ let depositor_address = format!("0x{}", hex::encode(depositor_addr_bytes));
+
+ let token_amount = U256::from_big_endian(token_amount_32);
+
+ Ok((token_address, depositor_address, token_amount))
+}
+
+pub fn format_erc20_18(amount: U256) -> String {
+ let base = U256::from(10).pow(U256::from(18));
+ let int = amount / base;
+ let frac = amount % base;
+ format!("{}.{:018}", int, frac)
+}
+
+pub async fn handle_advance(
+ _client: &hyper::Client,
+ _server_addr: &str,
+ request: JsonValue,
+) -> Result<&'static str, Box> {
+ println!("Received advance request data {}", &request);
+ let _payload = request["data"]["payload"]
+ .as_str()
+ .ok_or("Missing payload")?;
+
+ let sender = request["data"]["metadata"]["msg_sender"]
+ .as_str()
+ .ok_or("Missing sender")?;
+
+ let erc20_portal_address: &str = "0xc700D6aDd016eECd59d989C028214Eaa0fCC0051";
+
+ if sender.to_lowercase() == erc20_portal_address.to_lowercase() {
+ println!("Received a message from the ERC20 Portal contract");
+ match parse_deposit_payload(_payload).await {
+ Ok((token, depositor, token_amount)) => {
+ let formatted_amount = format_erc20_18(token_amount);
+ println!("Token: {token}, Depositor: {depositor}, token_amount: {formatted_amount}");
+ }
+ Err(e) => {
+ eprintln!("Failed to parse deposit payload: {}", e);
+ return Err("reject".into());
+ }
+ }
+ }
+
+ // TODO: add application logic here
+ Ok("accept")
+}
+
+pub async fn handle_inspect(
+ _client: &hyper::Client,
+ _server_addr: &str,
+ request: JsonValue,
+) -> Result<&'static str, Box> {
+ println!("Received inspect request data {}", &request);
+ let _payload = request["data"]["payload"]
+ .as_str()
+ .ok_or("Missing payload")?;
+ // TODO: add application logic here
+ Ok("accept")
+}
+
+#[tokio::main]
+async fn main() -> Result<(), Box> {
+ let client = hyper::Client::new();
+ let server_addr = env::var("ROLLUP_HTTP_SERVER_URL")?;
+
+ let mut status = "accept";
+ loop {
+ println!("Sending finish");
+ let response = object! {"status" => status};
+ let request = hyper::Request::builder()
+ .method(hyper::Method::POST)
+ .header(hyper::header::CONTENT_TYPE, "application/json")
+ .uri(format!("{}/finish", &server_addr))
+ .body(hyper::Body::from(response.dump()))?;
+ let response = client.request(request).await?;
+ println!("Received finish status {}", response.status());
+
+ if response.status() == hyper::StatusCode::ACCEPTED {
+ println!("No pending rollup request, trying again");
+ } else {
+ let body = hyper::body::to_bytes(response).await?;
+ let utf = std::str::from_utf8(&body)?;
+ let req = json::parse(utf)?;
+
+ let request_type = req["request_type"]
+ .as_str()
+ .ok_or("request_type is not a string")?;
+ status = match request_type {
+ "advance_state" => handle_advance(&client, &server_addr[..], req).await?,
+ "inspect_state" => handle_inspect(&client, &server_addr[..], req).await?,
+ &_ => {
+ eprintln!("Unknown request type");
+ "reject"
+ }
+ };
+ }
+ }
+}
+
+```
+
+
+
+
+
+
+
+```python
+from os import environ
+import logging
+import requests
+
+logging.basicConfig(level="INFO")
+logger = logging.getLogger(__name__)
+
+rollup_server = environ["ROLLUP_HTTP_SERVER_URL"]
+logger.info(f"HTTP rollup_server url is {rollup_server}")
+
+def parse_deposit_payload(payload: str):
+
+ clean = payload.strip().removeprefix("0x")
+
+ bytes_data = bytes.fromhex(clean)
+
+ TOKEN_ADDR_LEN = 20
+ DEPOSITOR_ADDR_LEN = 20
+ TOKEN_ID_LEN = 32
+ EXPECTED_LEN = TOKEN_ADDR_LEN + DEPOSITOR_ADDR_LEN + TOKEN_ID_LEN
+ if len(bytes_data) < EXPECTED_LEN:
+ raise ValueError(f"Invalid payload length: expected {EXPECTED_LEN}, got {len(bytes_data)}")
+
+ token_addr_bytes = bytes_data[0:TOKEN_ADDR_LEN]
+ depositor_addr_bytes = bytes_data[TOKEN_ADDR_LEN:TOKEN_ADDR_LEN + DEPOSITOR_ADDR_LEN]
+ token_amount_32 = bytes_data[TOKEN_ADDR_LEN + DEPOSITOR_ADDR_LEN:EXPECTED_LEN]
+
+ token_address = "0x" + token_addr_bytes.hex()
+ depositor_address = "0x" + depositor_addr_bytes.hex()
+
+ token_amount = int.from_bytes(token_amount_32, byteorder="big")
+
+ return [token_address, depositor_address, token_amount]
+
+def format_erc20_18(amount: int) -> str:
+ base = 10 ** 18
+ integer_part = amount // base
+ fractional_part = amount % base
+ return f"{integer_part}.{fractional_part:018d}"
+
+def handle_advance(data):
+ logger.info(f"Received advance request data {data}")
+ sender = data["metadata"]["msg_sender"]
+ payload = data["payload"]
+ ERC20_PORTAL_ADDRESS = "0xc700D6aDd016eECd59d989C028214Eaa0fCC0051";
+
+ if sender.lower() == ERC20_PORTAL_ADDRESS.lower():
+ try:
+ [token, depositor, token_amount] = parse_deposit_payload(payload)
+ formated_token = format_erc20_18(token_amount)
+ logger.info(f"Token: {token}, Depositor: {depositor}, token_amount: {formated_token}")
+ except ValueError as e:
+ logger.error(f"Failed to parse deposit payload: {e}")
+
+ return "accept"
+
+
+def handle_inspect(data):
+ logger.info(f"Received inspect request data {data}")
+ return "accept"
+
+
+handlers = {
+ "advance_state": handle_advance,
+ "inspect_state": handle_inspect,
+}
+
+finish = {"status": "accept"}
+
+while True:
+ logger.info("Sending finish")
+ response = requests.post(rollup_server + "/finish", json=finish)
+ logger.info(f"Received finish status {response.status_code}")
+ if response.status_code == 202:
+ logger.info("No pending rollup request, trying again")
+ else:
+ rollup_request = response.json()
+ data = rollup_request["data"]
+ handler = handlers[rollup_request["request_type"]]
+ finish["status"] = handler(rollup_request["data"])
+
+```
+
+
+
+
+
+
+- Install necessary dependencies for rust or javasctipt by running the command:
+
+
+
+
+
+```javascript
+import { ethers } from "ethers";
+import {
+ getAddress,
+} from "viem";
+
+const rollup_server = process.env.ROLLUP_HTTP_SERVER_URL;
+console.log("HTTP rollup_server url is " + rollup_server);
+
+const ERC721_PORTAL_ADDRESS = "0xc700d52f5290e978e9cae7d1e092935263b60051";
+
+
+function parseDepositPayload(payload) {
+ const tokenData = ethers.dataSlice(payload, 0, 20);
+ const senderData = ethers.dataSlice(payload, 20, 40);
+ const tokenIdData = ethers.dataSlice(payload, 40, 72);
+
+ if (!tokenData) {
+ throw new Error("Invalid deposit payload");
+ }
+ return [getAddress(tokenData), getAddress(senderData), BigInt(tokenIdData)];
+ }
+
+async function handle_advance(data) {
+ console.log("Received advance request data " + JSON.stringify(data));
+ let payload = data.payload;
+ const sender = data["metadata"]["msg_sender"];
+
+ if (sender.toLowerCase() === ERC721_PORTAL_ADDRESS.toLowerCase()) {
+ console.log("Handling portal deposit");
+ const [token, depositor, amount] = parseDepositPayload(payload);
+ console.log(`Token: ${token}, Depositor: ${depositor}, Amount: ${amount}`);
+
+ // Handle deposit logic here
+ } else {
+ // Handle Transaction request like a regular transaction
+ }
+
+ return "accept";
+}
+
+async function handle_inspect(data) {
+ console.log("Received inspect request data " + JSON.stringify(data));
+ return "accept";
+}
+
+var handlers = {
+ advance_state: handle_advance,
+ inspect_state: handle_inspect,
+};
+
+var finish = { status: "accept" };
+
+(async () => {
+ while (true) {
+ const finish_req = await fetch(rollup_server + "/finish", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ status: "accept" }),
+ });
+
+ console.log("Received finish status " + finish_req.status);
+
+ if (finish_req.status == 202) {
+ console.log("No pending rollup request, trying again");
+ } else {
+ const rollup_req = await finish_req.json();
+ var handler = handlers[rollup_req["request_type"]];
+ finish["status"] = await handler(rollup_req["data"]);
+ }
+ }
+})();
+
+```
+
+
+
+
+
+
+
+```Rust
+use json::{object, JsonValue};
+use std::env;
+use hex::FromHex;
+use std::error::Error;
+use std::io;
+
+pub async fn parse_deposit_payload(
+ payload: &str
+) -> Result<(String, String, u32), Box> {
+
+ let clean = payload.trim().trim_start_matches("0x");
+
+ let bytes: Vec = Vec::from_hex(clean).map_err(|e| -> Box { e.into() })?;
+
+ const TOKEN_ADDR_LEN: usize = 20;
+ const DEPOSITOR_ADDR_LEN: usize = 20;
+ const TOKEN_ID_LEN: usize = 32;
+ const MIN_LEN: usize = TOKEN_ADDR_LEN + DEPOSITOR_ADDR_LEN + TOKEN_ID_LEN;
+
+ if bytes.len() < MIN_LEN {
+ return Err(io::Error::new(io::ErrorKind::InvalidData, "payload too short").into());
+ }
+
+ let token_addr_bytes = bytes.get(0..20)
+ .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "token address slice"))?;
+ let depositor_addr_bytes = bytes.get(20..40)
+ .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "depositor address slice"))?;
+ let token_id_32 = bytes.get(40..72)
+ .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "token id slice"))?;
+
+ let token_address = format!("0x{}", hex::encode(token_addr_bytes));
+ let depositor_address = format!("0x{}", hex::encode(depositor_addr_bytes));
+
+ let last4: [u8; 4] = token_id_32[28..32].try_into().unwrap();
+ let token_id = u32::from_be_bytes(last4);
+
+ Ok((token_address, depositor_address, token_id))
+}
+
+pub async fn handle_advance(
+ _client: &hyper::Client,
+ _server_addr: &str,
+ request: JsonValue,
+) -> Result<&'static str, Box> {
+ println!("Received advance request data {}", &request);
+ let _payload = request["data"]["payload"]
+ .as_str()
+ .ok_or("Missing payload")?;
+
+ let sender = request["data"]["metadata"]["msg_sender"]
+ .as_str()
+ .ok_or("Missing sender")?;
+
+ let erc721_portal_address: &str = "0xc700d52f5290e978e9cae7d1e092935263b60051";
+
+ if sender.to_lowercase() == erc721_portal_address.to_lowercase() {
+ println!("Received a message from the ERC721 Portal contract");
+ match parse_deposit_payload(_payload).await {
+ Ok((token, depositor, token_id)) => {
+ println!("Token: {token}, Depositor: {depositor}, Token_id: {token_id}");
+ }
+ Err(e) => {
+ eprintln!("Failed to parse deposit payload: {}", e);
+ return Err("reject".into());
+ }
+ }
+ }
+
+ // TODO: add application logic here
+ Ok("accept")
+}
+
+pub async fn handle_inspect(
+ _client: &hyper::Client,
+ _server_addr: &str,
+ request: JsonValue,
+) -> Result<&'static str, Box> {
+ println!("Received inspect request data {}", &request);
+ let _payload = request["data"]["payload"]
+ .as_str()
+ .ok_or("Missing payload")?;
+ // TODO: add application logic here
+ Ok("accept")
+}
+
+#[tokio::main]
+async fn main() -> Result<(), Box> {
+ let client = hyper::Client::new();
+ let server_addr = env::var("ROLLUP_HTTP_SERVER_URL")?;
+
+ let mut status = "accept";
+ loop {
+ println!("Sending finish");
+ let response = object! {"status" => status};
+ let request = hyper::Request::builder()
+ .method(hyper::Method::POST)
+ .header(hyper::header::CONTENT_TYPE, "application/json")
+ .uri(format!("{}/finish", &server_addr))
+ .body(hyper::Body::from(response.dump()))?;
+ let response = client.request(request).await?;
+ println!("Received finish status {}", response.status());
+
+ if response.status() == hyper::StatusCode::ACCEPTED {
+ println!("No pending rollup request, trying again");
+ } else {
+ let body = hyper::body::to_bytes(response).await?;
+ let utf = std::str::from_utf8(&body)?;
+ let req = json::parse(utf)?;
+
+ let request_type = req["request_type"]
+ .as_str()
+ .ok_or("request_type is not a string")?;
+ status = match request_type {
+ "advance_state" => handle_advance(&client, &server_addr[..], req).await?,
+ "inspect_state" => handle_inspect(&client, &server_addr[..], req).await?,
+ &_ => {
+ eprintln!("Unknown request type");
+ "reject"
+ }
+ };
+ }
+ }
+}
+
+```
+
+
+
+
+
+
+
+```python
+from os import environ
+import logging
+import requests
+
+logging.basicConfig(level="INFO")
+logger = logging.getLogger(__name__)
+
+rollup_server = environ["ROLLUP_HTTP_SERVER_URL"]
+logger.info(f"HTTP rollup_server url is {rollup_server}")
+
+def parse_deposit_payload(payload: str):
+
+ clean = payload.strip().removeprefix("0x")
+
+ bytes_data = bytes.fromhex(clean)
+
+ TOKEN_ADDR_LEN = 20
+ DEPOSITOR_ADDR_LEN = 20
+ TOKEN_ID_LEN = 32
+ EXPECTED_LEN = TOKEN_ADDR_LEN + DEPOSITOR_ADDR_LEN + TOKEN_ID_LEN
+ if len(bytes_data) < EXPECTED_LEN:
+ raise ValueError(f"Invalid payload length: expected {EXPECTED_LEN}, got {len(bytes_data)}")
+
+ token_addr_bytes = bytes_data[0:TOKEN_ADDR_LEN]
+ depositor_addr_bytes = bytes_data[TOKEN_ADDR_LEN:TOKEN_ADDR_LEN + DEPOSITOR_ADDR_LEN]
+ token_id_32 = bytes_data[TOKEN_ADDR_LEN + DEPOSITOR_ADDR_LEN:EXPECTED_LEN]
+
+ token_address = "0x" + token_addr_bytes.hex()
+ depositor_address = "0x" + depositor_addr_bytes.hex()
+
+ token_id = int.from_bytes(token_id_32[28:32], byteorder="big")
+
+ return [token_address, depositor_address, token_id]
+
+def handle_advance(data):
+ logger.info(f"Received advance request data {data}")
+ sender = data["metadata"]["msg_sender"]
+ payload = data["payload"]
+ ERC721_PORTAL_ADDRESS = "0xc700d52f5290e978e9cae7d1e092935263b60051";
+
+ if sender.lower() == ERC721_PORTAL_ADDRESS.lower():
+ try:
+ [token, depositor, token_id] = parse_deposit_payload(payload)
+ logger.info(f"Token: {token}, Depositor: {depositor}, Token_id: {token_id}")
+ except ValueError as e:
+ logger.error(f"Failed to parse deposit payload: {e}")
+
+ return "accept"
+
+
+def handle_inspect(data):
+ logger.info(f"Received inspect request data {data}")
+ return "accept"
+
+
+handlers = {
+ "advance_state": handle_advance,
+ "inspect_state": handle_inspect,
+}
+
+finish = {"status": "accept"}
+
+while True:
+ logger.info("Sending finish")
+ response = requests.post(rollup_server + "/finish", json=finish)
+ logger.info(f"Received finish status {response.status_code}")
+ if response.status_code == 202:
+ logger.info("No pending rollup request, trying again")
+ else:
+ rollup_request = response.json()
+ data = rollup_request["data"]
+ handler = handlers[rollup_request["request_type"]]
+ finish["status"] = handler(rollup_request["data"])
+
+```
+
+
+
+
+
+
+- Install necessary dependencies for rust or javascript by running the command:
+
+
+
+
+
+```Javascript
+import { ethers } from "ethers";
+import {
+ getAddress,
+} from "viem";
+
+const rollup_server = process.env.ROLLUP_HTTP_SERVER_URL;
+console.log("HTTP rollup_server url is " + rollup_server);
+
+const ERC1155_SINGLE_PORTAL_ADDRESS = "0xc700A261279aFC6F755A3a67D86ae43E2eBD0051";
+
+
+function parseDepositPayload(payload) {
+ const tokenData = ethers.dataSlice(payload, 0, 20);
+ const senderData = ethers.dataSlice(payload, 20, 40);
+ const tokenIdData = ethers.dataSlice(payload, 40, 72);
+ const amountData = ethers.dataSlice(payload, 72, 104);
+
+ if (!tokenData) {
+ throw new Error("Invalid deposit payload");
+ }
+ return [getAddress(tokenData), getAddress(senderData), BigInt(tokenIdData), BigInt(amountData)];
+ }
+
+async function handle_advance(data) {
+ console.log("Received advance request data " + JSON.stringify(data));
+ let payload = data.payload;
+ const sender = data["metadata"]["msg_sender"];
+
+ if (sender.toLowerCase() === ERC1155_SINGLE_PORTAL_ADDRESS.toLowerCase()) {
+ console.log("Handling portal deposit");
+ const [token, depositor, tokenId, amount] = parseDepositPayload(payload);
+ console.log(`Token: ${token}, Depositor: ${depositor}, Token ID: ${tokenId}, Amount: ${amount}`);
+
+ // Handle deposit logic here
+ } else {
+ // Handle Transaction request like a regular transaction
+ }
+
+ return "accept";
+}
+
+async function handle_inspect(data) {
+ console.log("Received inspect request data " + JSON.stringify(data));
+ return "accept";
+}
+
+var handlers = {
+ advance_state: handle_advance,
+ inspect_state: handle_inspect,
+};
+
+var finish = { status: "accept" };
+
+(async () => {
+ while (true) {
+ const finish_req = await fetch(rollup_server + "/finish", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({ status: "accept" }),
+ });
+
+ console.log("Received finish status " + finish_req.status);
+
+ if (finish_req.status == 202) {
+ console.log("No pending rollup request, trying again");
+ } else {
+ const rollup_req = await finish_req.json();
+ var handler = handlers[rollup_req["request_type"]];
+ finish["status"] = await handler(rollup_req["data"]);
+ }
+ }
+})();
+```
+
+
+
+
+
+
+
+```Rust
+use json::{object, JsonValue};
+use primitive_types::{H160, U256};
+use std::env;
+use hex::FromHex;
+use std::error::Error;
+use std::io;
+
+pub async fn parse_deposit_payload(
+ payload: &str
+) -> Result<(String, String, U256, U256), Box> {
+
+ let clean = payload.trim().trim_start_matches("0x");
+
+ let bytes: Vec = Vec::from_hex(clean).map_err(|e| -> Box { e.into() })?;
+
+ const TOKEN_ADDR_LEN: usize = 20;
+ const DEPOSITOR_ADDR_LEN: usize = 20;
+ const TOKEN_ID_LEN: usize = 32;
+ const AMOUNT_LEN: usize = 32;
+ const MIN_LEN: usize = TOKEN_ADDR_LEN + DEPOSITOR_ADDR_LEN + AMOUNT_LEN + TOKEN_ID_LEN;
+
+ if bytes.len() < MIN_LEN {
+ return Err(io::Error::new(io::ErrorKind::InvalidData, "payload too short").into());
+ }
+
+ let token_addr_bytes = bytes.get(0..20)
+ .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "token address slice"))?;
+ let depositor_addr_bytes = bytes.get(20..40)
+ .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "depositor address slice"))?;
+ let token_id_32 = bytes.get(40..72)
+ .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "token id slice"))?;
+ let token_amount_32 = bytes.get(72..104)
+ .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "token id slice"))?;
+
+ let token_address = format!("0x{}", hex::encode(token_addr_bytes));
+ let depositor_address = format!("0x{}", hex::encode(depositor_addr_bytes));
+ let token_id = U256::from_big_endian(token_id_32);
+ let token_amount = U256::from_big_endian(token_amount_32);
+
+ Ok((token_address, depositor_address, token_id, token_amount))
+}
+
+pub async fn handle_advance(
+ _client: &hyper::Client,
+ _server_addr: &str,
+ request: JsonValue,
+) -> Result<&'static str, Box> {
+ println!("Received advance request data {}", &request);
+ let _payload = request["data"]["payload"]
+ .as_str()
+ .ok_or("Missing payload")?;
+
+ let sender = request["data"]["metadata"]["msg_sender"]
+ .as_str()
+ .ok_or("Missing sender")?;
+
+ let erc1155_portal_address: &str = "0xc700A261279aFC6F755A3a67D86ae43E2eBD0051";
+
+ if sender.to_lowercase() == erc1155_portal_address.to_lowercase() {
+ println!("Received a message from the ERC20 Portal contract");
+ match parse_deposit_payload(_payload).await {
+ Ok((token, depositor, token_id, token_amount)) => {
+ println!("Token: {token}, Depositor: {depositor}, token_id: {token_id}, token_amount: {token_amount}");
+ }
+ Err(e) => {
+ eprintln!("Failed to parse deposit payload: {}", e);
+ return Err("reject".into());
+ }
+ }
+ }
+ // TODO: add application logic here
+ Ok("accept")
+}
+
+pub async fn handle_inspect(
+ _client: &hyper::Client,
+ _server_addr: &str,
+ request: JsonValue,
+) -> Result<&'static str, Box> {
+ println!("Received inspect request data {}", &request);
+ let _payload = request["data"]["payload"]
+ .as_str()
+ .ok_or("Missing payload")?;
+ // TODO: add application logic here
+ Ok("accept")
+}
+
+#[tokio::main]
+async fn main() -> Result<(), Box> {
+ let client = hyper::Client::new();
+ let server_addr = env::var("ROLLUP_HTTP_SERVER_URL")?;
+
+ let mut status = "accept";
+ loop {
+ println!("Sending finish");
+ let response = object! {"status" => status};
+ let request = hyper::Request::builder()
+ .method(hyper::Method::POST)
+ .header(hyper::header::CONTENT_TYPE, "application/json")
+ .uri(format!("{}/finish", &server_addr))
+ .body(hyper::Body::from(response.dump()))?;
+ let response = client.request(request).await?;
+ println!("Received finish status {}", response.status());
+
+ if response.status() == hyper::StatusCode::ACCEPTED {
+ println!("No pending rollup request, trying again");
+ } else {
+ let body = hyper::body::to_bytes(response).await?;
+ let utf = std::str::from_utf8(&body)?;
+ let req = json::parse(utf)?;
+
+ let request_type = req["request_type"]
+ .as_str()
+ .ok_or("request_type is not a string")?;
+ status = match request_type {
+ "advance_state" => handle_advance(&client, &server_addr[..], req).await?,
+ "inspect_state" => handle_inspect(&client, &server_addr[..], req).await?,
+ &_ => {
+ eprintln!("Unknown request type");
+ "reject"
+ }
+ };
+ }
+ }
+}
+```
+
+
+
+
+
+
+
+```python
+from os import environ
+import logging
+import requests
+
+logging.basicConfig(level="INFO")
+logger = logging.getLogger(__name__)
+
+rollup_server = environ["ROLLUP_HTTP_SERVER_URL"]
+logger.info(f"HTTP rollup_server url is {rollup_server}")
+
+def parse_deposit_payload(payload: str):
+
+ clean = payload.strip().removeprefix("0x")
+
+ bytes_data = bytes.fromhex(clean)
+
+ TOKEN_ADDR_LEN = 20
+ DEPOSITOR_ADDR_LEN = 20
+ TOKEN_ID_LEN = 32
+ AMOUNT_LEN = 32
+ EXPECTED_LEN = TOKEN_ADDR_LEN + DEPOSITOR_ADDR_LEN + TOKEN_ID_LEN + AMOUNT_LEN
+ if len(bytes_data) < EXPECTED_LEN:
+ raise ValueError(f"Invalid payload length: expected {EXPECTED_LEN}, got {len(bytes_data)}")
+
+ token_addr_bytes = bytes_data[0:20]
+ depositor_addr_bytes = bytes_data[20:40]
+ token_id_32 = bytes_data[40:72]
+ token_amount_32 = bytes_data[72:104]
+
+ token_address = "0x" + token_addr_bytes.hex()
+ depositor_address = "0x" + depositor_addr_bytes.hex()
+ token_id= int.from_bytes(token_id_32, byteorder="big")
+ token_amount = int.from_bytes(token_amount_32, byteorder="big")
+
+ return [token_address, depositor_address, token_id, token_amount]
+
+def handle_advance(data):
+ logger.info(f"Received advance request data {data}")
+ sender = data["metadata"]["msg_sender"]
+ payload = data["payload"]
+ ERC1155_PORTAL_ADDRESS = "0xc700A261279aFC6F755A3a67D86ae43E2eBD0051";
+
+ if sender.lower() == ERC1155_PORTAL_ADDRESS.lower():
+ try:
+ [token, depositor, token_id, token_amount] = parse_deposit_payload(payload)
+ logger.info(f"Token: {token}, Depositor: {depositor}, token ID: {token_id} token_amount: {token_amount}")
+ except ValueError as e:
+ logger.error(f"Failed to parse deposit payload: {e}")
+ return "accept"
+
+def handle_inspect(data):
+ logger.info(f"Received inspect request data {data}")
+ return "accept"
+
+handlers = {
+ "advance_state": handle_advance,
+ "inspect_state": handle_inspect,
+}
+
+finish = {"status": "accept"}
+
+while True:
+ logger.info("Sending finish")
+ response = requests.post(rollup_server + "/finish", json=finish)
+ logger.info(f"Received finish status {response.status_code}")
+ if response.status_code == 202:
+ logger.info("No pending rollup request, trying again")
+ else:
+ rollup_request = response.json()
+ data = rollup_request["data"]
+ handler = handlers[rollup_request["request_type"]]
+ finish["status"] = handler(rollup_request["data"])
+```
+
+
+
+
+
+
+- Install necessary dependencies for rust or javasctipt by running the command:
+
+