use std::env;
use std::fs::{self, File};
use std::io::{self, ErrorKind};
use std::path::PathBuf;
pub fn build_index_content() -> &'static str {
r#"
// Execution step
// Read inputs from stdin
const stfInputs = readInput();
var newState = run(stfInputs.currentState, stfInputs.actions);
// Write the result to stdout
writeOutput(newState);
// Read input from stdin
function readInput() {
const chunkSize = 1024;
const inputChunks = [];
let totalBytes = 0;
// Read all the available bytes
while (1) {
const buffer = new Uint8Array(chunkSize);
// Stdin file descriptor
const fd = 0;
const bytesRead = Javy.IO.readSync(fd, buffer);
totalBytes += bytesRead;
if (bytesRead === 0) {
break;
}
inputChunks.push(buffer.subarray(0, bytesRead));
}
// Assemble input into a single Uint8Array
const { finalBuffer } = inputChunks.reduce(
(context, chunk) => {
context.finalBuffer.set(chunk, context.bufferOffset);
context.bufferOffset += chunk.length;
return context;
},
{ bufferOffset: 0, finalBuffer: new Uint8Array(totalBytes) },
);
return JSON.parse(new TextDecoder().decode(finalBuffer));
}
function writeOutput(output) {
const encodedOutput = new TextEncoder().encode(JSON.stringify(output));
const buffer = new Uint8Array(encodedOutput);
// Stdout file descriptor
const fd = 1;
Javy.IO.writeSync(fd, buffer);
}"#
}
pub fn index_content() -> &'static str {
r#"import {
ActionSchema,
ExecutorEvents,
FIFOStrategy,
MicroRollup,
StateMachine,
actionEventsEmitter,
builderEventsEmitter,
executorEventsEmitter,
ActionEvents
} from "@stackr/stackr-js";
import bodyParser from "body-parser";
import express, { Request, Response } from "express";
import { mockStackrConfig } from "../stackr.config";
import { CounterActionInput, CounterRollup, counterSTF } from "./state";
import { ZeroAddress } from "ethers";
const rollup = async () => {
const counterRollup = new CounterRollup(0);
const counterFsm = new StateMachine({
state: counterRollup,
stf: counterSTF,
});
const actionInput = new ActionSchema<CounterActionInput>("update-counter");
const buildStrategy = new FIFOStrategy();
const { state, actions } = await MicroRollup({
config: mockStackrConfig,
useState: counterFsm,
useAction: actionInput,
useBuilder: { strategy: buildStrategy, autorun: true },
});
return { state, actions };
};
const app = express();
app.use(bodyParser.json());
const { actions, state } = await rollup();
app.get("/", (req: Request, res: Response) => {
res.send({ currentCount: state.get().state.getState() });
});
app.post("/", async (req: Request, res: Response) => {
const schema = actions.getSchema("update-counter");
if (!schema) {
res.status(400).send({ message: "error" });
return;
}
const newAction = schema.newAction(req.body);
const ack = await actions.submit(newAction);
res.status(201).send({ ack });
});
app.listen(3000, () => {
console.log("listening on port 3000");
});
actionEventsEmitter.on(ActionEvents.SUBMIT_ACTION, (data) => {
console.log("submit_action - Event triggered : ", data.payload);
});
executorEventsEmitter.on(ExecutorEvents.EXECUTE_SINGLE, (data) => {
console.log("execute_single - Event triggered : ", data);
});
"#
}
pub fn state_content() -> &'static str {
r#"import { RollupState, STF } from "@stackr/stackr-js/execution";
import { BytesLike, solidityPackedKeccak256 } from "ethers";
import MerkleTree from "merkletreejs";
export type StateVariable = {
address: string;
balance: number;
}[];
export interface TransferInput {
to: string;
from: string;
amount: number;
}
class BetterMerkleTree {
public merkleTree: MerkleTree;
public leaves: any[];
constructor(leaves: any[]) {
this.merkleTree = this.createTree(leaves);
this.leaves = leaves;
}
createTree(leaves: any[]) {
const hashedLeaves = leaves.map((leaf: any) => {
return solidityPackedKeccak256(
["address", "uint"],
[leaf.address, leaf.balance],
);
});
return new MerkleTree(hashedLeaves);
}
}
export class AccountsRollup extends RollupState<
StateVariable,
BetterMerkleTree>
{
constructor(leaves: StateVariable) {
super(leaves);
}
createTransport(state: StateVariable): BetterMerkleTree {
const newTree = new BetterMerkleTree(state);
return newTree;
}
getState(): StateVariable {
return this.transport.leaves;
}
calculateRoot(): BytesLike {
return this.transport.merkleTree.getHexRoot();
}
}
export const transferSTF: STF<AccountsRollup, TransferInput> = {
identifier: "tokenTransfer",
apply(inputs: TransferInput, state: AccountsRollup): void {
let newState = state.getState();
const indexTo = newState.findIndex((leaf) => leaf.address === inputs.to);
const indexFrom = newState.findIndex(
(leaf) => leaf.address === inputs.from,
);
newState[indexTo].balance += inputs.amount;
newState[indexFrom].balance -= inputs.amount;
state.transport.leaves = newState;
// TODO : consider better approach
},
};
"#
}
pub fn utils_content() -> &'static str {
r#"import { Domain, EIP712Types } from "@stackr/stackr-js";
import { ethers } from "ethers";
const getUserInput = async (types: EIP712Types, domain: Domain) => {
const w = ethers.Wallet.createRandom();
const addr1 = ethers.hexlify(ethers.randomBytes(20));
const payload = { type: "increment" };
const signature = await w.signTypedData(domain, types, payload);
return {
data: {
msgSender: w.address,
payload,
signature,
},
};
};
"#
}
pub fn tsconfig_content() -> &'static str {
r#"{
"compilerOptions": {
"lib": ["ES2020"],
"module": "ES2020",
"target": "ES2020",
"moduleResolution": "bundler",
"moduleDetection": "force",
"allowImportingTsExtensions": true,
"noEmit": true,
"composite": true,
"strict": true,
"downlevelIteration": true,
"skipLibCheck": true,
"jsx": "react-jsx",
"allowSyntheticDefaultImports": true,
"forceConsistentCasingInFileNames": true,
"allowJs": true,
"types": [
"bun-types" // add Bun global
]
}
}
"#
}
pub fn filewriter(project_name: &str) -> io::Result<()> {
let current_dir = env::current_dir()?;
let destination_file_path = current_dir.join(format!("{}/src/state.ts", &project_name));
let destination_file_path1 = current_dir.join(format!("{}/src/index.ts", &project_name));
let _ = fs::copy(
"./src/filehandler/examples/state.ts",
&destination_file_path,
)?;
let _ = fs::copy(
"./src/filehandler/examples/index.ts",
&destination_file_path1,
)?;
println!("Setting up example project completed");
Ok(())
}