Spaces:
luguog
/
No application file

Gucci3 / index.html
luguog's picture
Rename app.py to index.html
ff18f41 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>LLM Remix IDE — fixed alpha</title>
<!-- Core libs -->
<script src="https://cdn.jsdelivr.net/npm/ethers@6.13.2/dist/ethers.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/solc@0.8.24/soljson.js"></script>
<!-- Editor -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.12/codemirror.min.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.12/theme/dracula.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.12/codemirror.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.65.12/mode/clike/clike.min.js"></script>
<!-- Optional LLM (gracefully degrades if blocked) -->
<script src="https://cdn.jsdelivr.net/npm/@xenova/transformers@2.5.1"></script>
<style>
:root { --bg:#0a0a0a; --panel:#111; --accent:#ff6700; --ok:#19c37d; --err:#ff4d4f; }
body { background:var(--bg); color:#eee; font-family:system-ui, -apple-system, Segoe UI, Roboto, sans-serif; margin:0; }
header { background:#111; padding:10px 14px; color:var(--accent); display:flex; gap:8px; flex-wrap:wrap; align-items:center; }
button, input, select { background:#141414; color:#f8f8f8; border:none; border-radius:8px; padding:8px 12px; }
button { color:var(--accent); cursor:pointer; }
button:hover { background:var(--accent); color:#000; }
.wrap { padding:12px; display:grid; gap:12px; grid-template-columns: 1fr; }
.pane { background:#111; border-radius:10px; padding:12px; }
#status { font-weight:700; }
#output { white-space:pre-wrap; background:#0e0e0e; padding:12px; border-radius:8px; max-height:240px; overflow:auto; }
#editor { height:360px; }
.CodeMirror { height:360px; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size:13px; }
.row { display:flex; gap:8px; flex-wrap:wrap; align-items:center; }
.grid { display:grid; gap:10px; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.fn { background:#0e0e0e; padding:10px; border-radius:8px; }
.small { font-size:.85rem; color:#bbb; }
.ok { color:var(--ok); } .warn { color:var(--err); }
label { font-size:.85rem; color:#bbb; }
</style>
</head>
<body>
<header>
<strong>🤖 LLM Remix IDE — fixed alpha</strong>
<div class="row">
<button id="connectBtn">Connect Wallet</button>
<button id="switchSepoliaBtn" title="11155111">Switch → Sepolia</button>
<button id="generateBtn">Generate</button>
<button id="compileBtn">Compile</button>
<button id="deployBtn">Deploy</button>
</div>
</header>
<div class="wrap">
<div id="status" class="pane">Status: idle</div>
<div class="pane">
<div class="row">
<input id="prompt" type="text" style="flex:1" value="ERC20 token with daily rebase and transfer fee" />
<select id="preset">
<option value="code">code preset</option>
<option value="vanilla">vanilla</option>
</select>
<button id="sampleStorageBtn">Sample: Storage</button>
<button id="sampleERC20Btn">Sample: ERC20</button>
</div>
<div id="editor"></div>
<div class="small">Edits auto-save. LLM optional. Use samples if generation fails.</div>
</div>
<div class="pane">
<h3 style="margin:0 0 8px 0;">Compile</h3>
<div id="output">Output will appear here…</div>
</div>
<div class="pane">
<h3 style="margin:0 0 8px 0;">Deploy</h3>
<div class="row">
<label>Constructor + value (wei) set below. Mainnet prompts confirm.</label>
</div>
<div class="row">
<label>Attach existing:</label>
<input id="attachAddr" type="text" placeholder="0x... address" style="min-width:320px" />
<button id="attachBtn">Attach</button>
</div>
<div class="row">
<label>Payable value:</label>
<input id="deployValue" type="text" value="0" style="width:180px" />
</div>
<div id="ctorFields" class="row"></div>
<div>Deployed Address: <span id="contractAddr">-</span></div>
</div>
<div class="pane">
<h3 style="margin:0 0 8px 0;">Contract Functions <span id="fnSummary" class="small"></span></h3>
<div id="contractUI" class="grid"></div>
</div>
</div>
<script>
let provider, signer, chainId, generator = null;
let editor, abi = null, bytecode = null, contractMeta = null, instance = null;
// ---------- utils ----------
const el = (id)=>document.getElementById(id);
const setStatus = (t, cls="") => { const s=el("status"); s.textContent=t; s.className="pane "+cls; };
const log = (m)=> el("output").textContent = String(m);
const save = (k,v)=> localStorage.setItem(k,v);
const load = (k,d="")=> localStorage.getItem(k) ?? d;
function must(cond, msg){ if(!cond) throw new Error(msg); }
function parseArg(type, val){
if (val === "" || val === undefined || val === null) return val;
if (type.endsWith("[]")){
const inner = type.slice(0,-2);
return String(val).split(",").map(x=>parseArg(inner, x.trim()));
}
if (type.startsWith("uint") || type.startsWith("int")) return BigInt(val);
if (type === "bool") return (val===true || val==="true" || val==="1");
if (type === "address"){
must(/^0x[0-9a-fA-F]{40}$/.test(val), "Invalid address "+val);
return val;
}
return val;
}
function firstArtifact(contracts){
const names = Object.keys(contracts||{});
for(const n of names){
const art = contracts[n];
if (art?.evm?.bytecode?.object) return [n, art];
}
return [null,null];
}
// ---------- editor ----------
(function setupEditor(){
editor = CodeMirror(el("editor"), {
value: load("src", `// Example: Storage
pragma solidity ^0.8.24;
contract Storage {
uint public data;
function set(uint x) public { data = x; }
}`),
mode:"text/x-solidity",
theme:"dracula",
lineNumbers:true
});
editor.on("change",()=>save("src", editor.getValue()));
el("prompt").value = load("prompt", el("prompt").value);
el("prompt").addEventListener("change", e=>save("prompt", e.target.value));
})();
el("sampleStorageBtn").onclick = ()=>{
editor.setValue(`pragma solidity ^0.8.24;
contract Storage {
uint public data;
function set(uint x) public { data = x; }
}`);
};
el("sampleERC20Btn").onclick = ()=>{
editor.setValue(`// Minimal ERC20-like (unsafe for production)
pragma solidity ^0.8.24;
contract MiniERC20 {
string public name="Mini"; string public symbol="MINI"; uint8 public decimals=18;
uint public totalSupply; mapping(address=>uint) public balanceOf; mapping(address=>mapping(address=>uint)) public allowance;
event Transfer(address indexed from,address indexed to,uint value); event Approval(address indexed owner,address indexed spender,uint value);
constructor(uint supply){ totalSupply=supply; balanceOf[msg.sender]=supply; emit Transfer(address(0), msg.sender, supply); }
function transfer(address to, uint v) public returns(bool){ balanceOf[msg.sender]-=v; balanceOf[to]+=v; emit Transfer(msg.sender,to,v); return true; }
function approve(address s, uint v) public returns(bool){ allowance[msg.sender][s]=v; emit Approval(msg.sender,s,v); return true; }
function transferFrom(address f,address t,uint v) public returns(bool){ uint a=allowance[f][msg.sender]; allowance[f][msg.sender]=a-v; balanceOf[f]-=v; balanceOf[t]+=v; emit Transfer(f,t,v); return true; }
}`);
};
// ---------- wallet ----------
el("connectBtn").onclick = async ()=>{
try{
must(window.ethereum, "No wallet found");
provider = new ethers.BrowserProvider(window.ethereum);
signer = await provider.getSigner();
chainId = (await provider.getNetwork()).chainId; // BigInt
setStatus(`Wallet ${await signer.getAddress()} · chainId ${chainId}`, "ok");
}catch(e){ setStatus("Connect failed: "+(e.message||e), "warn"); }
};
el("switchSepoliaBtn").onclick = async ()=>{
try{
must(window.ethereum, "No wallet");
await window.ethereum.request({ method:"wallet_switchEthereumChain", params:[{ chainId:"0xaa36a7" }] });
provider = new ethers.BrowserProvider(window.ethereum);
signer = await provider.getSigner();
chainId = (await provider.getNetwork()).chainId;
setStatus(`Switched to chainId ${chainId}`, "ok");
}catch(e){ setStatus("Switch failed: "+(e.message||e), "warn"); }
};
// ---------- optional LLM ----------
(async ()=>{
try{
if (!window.transformers) { setStatus("LLM unavailable. Use samples.", "warn"); return; }
setStatus("Loading LLM…");
generator = await window.transformers.pipeline("text-generation","Xenova/distilgpt2");
setStatus("LLM ready", "ok");
}catch(e){ setStatus("LLM load failed. Use samples.", "warn"); generator=null; }
})();
function llmPrompt(preset, user){
const base = [
"Write ONLY valid Solidity. One file. No comments outside code.",
"Use pragma ^0.8.24.",
"Avoid deprecated/unsafe patterns."
].join("\n");
return preset==="code" ? `${base}\nTask: ${user}` : `Write a Solidity contract: ${user}`;
}
el("generateBtn").onclick = async ()=>{
try{
must(generator, "LLM not available");
const user = el("prompt").value;
const preset = el("preset").value;
setStatus("Generating…");
let attempt=0, code="";
while(attempt<3){
attempt++;
const out = await generator(llmPrompt(preset, user), { max_new_tokens: 400 });
const txt = out?.[0]?.generated_text || "";
const m = txt.match(/pragma[\s\S]*$/);
code = m ? m[0] : txt;
if (code.includes("pragma solidity") && code.includes("contract")) break;
}
editor.setValue(code);
setStatus(`Generated attempt ${attempt}`, "ok");
}catch(e){ setStatus("Generate failed: "+(e.message||e), "warn"); }
};
// ---------- compile ----------
el("compileBtn").onclick = async ()=>{
try{
must(window.solc, "solc not loaded");
const source = editor.getValue();
setStatus("Compiling…");
const input = {
language:"Solidity",
sources:{ "Contract.sol":{ content: source } },
settings:{ outputSelection:{ "*":{ "*":[ "abi","evm.bytecode","evm.deployedBytecode" ] } } }
};
const compiled = JSON.parse(solc.compile(JSON.stringify(input)));
if (compiled.errors?.length){
const msg = compiled.errors.map(e=>`${e.severity.toUpperCase()}: ${e.formattedMessage.trim()}`).join("\n");
log(msg);
if (compiled.errors.some(e=>e.severity==="error")) { setStatus("Compile errors", "warn"); return; }
}
const file = compiled.contracts["Contract.sol"];
const [name, art] = firstArtifact(file);
must(name, "No contract with bytecode found");
abi = art.abi; bytecode = art.evm.bytecode.object;
contractMeta = { name, abi, bytecode };
buildCtorUI(abi);
buildUI(null, abi);
log(`✅ Compiled ${name}\nFunctions: ${abi.filter(x=>x.type==="function").length}`);
setStatus("Compiled", "ok");
}catch(e){ setStatus("Compile failed: "+(e.message||e), "warn"); }
};
// ---------- deploy / attach ----------
el("deployBtn").onclick = async ()=>{
try{
must(signer, "Connect wallet");
must(abi && bytecode, "Compile first");
const net = await provider.getNetwork();
if (net.chainId === 1n){
const ok = confirm("Mainnet detected. Continue?");
if (!ok) return;
}
const ctor = abi.find(x=>x.type==="constructor")||{inputs:[]};
const args = [];
for (const inp of ctor.inputs){
const v = el(`ctor_${inp.name||"arg"}`)?.value ?? "";
args.push(parseArg(inp.type, v));
}
const valueStr = el("deployValue").value.trim() || "0";
const overrides = (valueStr !== "0") ? { value: BigInt(valueStr) } : {};
const factory = new ethers.ContractFactory(abi, bytecode, signer);
// try gas estimate, but continue if it fails
try {
const txReq = factory.getDeployTransaction(...args, overrides);
const est = await provider.estimateGas(txReq);
log(`Gas estimate: ${est.toString()}`);
} catch {}
setStatus("Deploying…");
instance = await factory.deploy(...args, overrides);
await instance.waitForDeployment();
const addr = await instance.getAddress();
el("contractAddr").textContent = addr;
buildUI(instance, abi);
setStatus("Deployed at "+addr, "ok");
}catch(e){ setStatus("Deploy failed: "+(e.message||e), "warn"); }
};
el("attachBtn").onclick = async ()=>{
try{
must(signer, "Connect wallet");
must(abi, "Compile to load ABI");
const addr = el("attachAddr").value.trim();
must(/^0x[0-9a-fA-F]{40}$/.test(addr), "Invalid address");
instance = new ethers.Contract(addr, abi, signer);
el("contractAddr").textContent = addr;
buildUI(instance, abi);
setStatus("Attached "+addr, "ok");
}catch(e){ setStatus("Attach failed: "+(e.message||e), "warn"); }
};
// ---------- dynamic UI ----------
function buildCtorUI(abi){
const box = el("ctorFields"); box.innerHTML = "";
const ctor = abi.find(x=>x.type==="constructor");
if (!ctor || !ctor.inputs?.length){ box.innerHTML = "<span class='small'>No constructor args</span>"; return; }
for (const inp of ctor.inputs){
const wrap = document.createElement("div"); wrap.className="row";
const lab = document.createElement("label"); lab.textContent = `${inp.name||"arg"} (${inp.type})`;
const input = document.createElement("input"); input.type="text"; input.id=`ctor_${inp.name||"arg"}`;
wrap.appendChild(lab); wrap.appendChild(input); box.appendChild(wrap);
}
}
function buildUI(inst, abi){
const div = el("contractUI"); div.innerHTML = "";
const fns = abi.filter(x=>x.type==="function");
el("fnSummary").textContent = `${fns.length} functions`;
for (const fn of fns){
const card = document.createElement("div"); card.className="fn";
const readOnly = (fn.stateMutability==="view" || fn.stateMutability==="pure");
const title = document.createElement("div");
title.innerHTML = `<b>${fn.name}</b> <span class="small">• ${readOnly?"read":"write"} · ${fn.stateMutability}</span>`;
card.appendChild(title);
const inputs = [];
for (const inp of fn.inputs){
const row = document.createElement("div"); row.className="row";
const lab = document.createElement("label"); lab.textContent = `${inp.name||"arg"} (${inp.type})`;
const input = document.createElement("input"); input.type="text";
row.appendChild(lab); row.appendChild(input); card.appendChild(row);
inputs.push({ def: inp, el: input });
}
let valueEl = null;
if (!readOnly && fn.stateMutability==="payable"){
const row = document.createElement("div"); row.className="row";
const lab = document.createElement("label"); lab.textContent = `value (wei)`;
const input = document.createElement("input"); input.type="text"; input.placeholder="0";
row.appendChild(lab); row.appendChild(input); card.appendChild(row);
valueEl = input;
}
const btn = document.createElement("button"); btn.textContent = "Run";
btn.onclick = async ()=>{
try{
if (!inst) throw new Error("Deploy or attach first");
const args = inputs.map(a=>parseArg(a.def.type, a.el.value));
if (readOnly){
const res = await inst[fn.name](...args);
log(`Result: ${res?.toString?.() ?? JSON.stringify(res)}`);
}else{
const ov = {};
if (valueEl && valueEl.value) ov.value = BigInt(valueEl.value);
const tx = await inst[fn.name](...args, ov);
log(`Tx: ${tx.hash}`);
const rc = await tx.wait();
log(`Mined: block ${rc.blockNumber}`);
}
}catch(e){ log("Error: "+(e.message||e)); }
};
card.appendChild(btn);
div.appendChild(card);
}
}
</script>
</body>
</html>