Goal: use MetaMask (connected to Ganache) as the signer in Remix to deploy and interact with a contract. Then test with a tiny HTML/JS page via ethers.js.
Create SimpleStorage.sol in Remix:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract SimpleStorage {
uint256 private storedData;
event ValueChanged(uint256 oldValue, uint256 newValue, address setter);
function set(uint256 x) public {
uint256 oldVal = storedData; storedData = x;
emit ValueChanged(oldVal, x, msg.sender);
}
function get() public view returns (uint256) { return storedData; }
}
0
. Call set(123) → Confirm → get() → 123
.Open Remix’s bottom terminal and click the tx to see the ValueChanged
event log.
Gas estimation failed? Fund the selected account (import from Ganache) and confirm the network is your Localhost.
Save this as simple_storage_frontend.html, then fill in your address and ABI from step 4.
<!DOCTYPE html>
<html><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>SimpleStorage Frontend</title></head>
<body>
<button id="connect">Connect MetaMask</button>
<div>
Address: <input id="addr" style="width:360px" value="PASTE_CONTRACT_ADDRESS"/>
</div>
<div>
ABI:<br/>
<textarea id="abi" rows="6" style="width:100%">PASTE_ABI_JSON_ARRAY</textarea>
</div>
<div>
<button id="get">get()</button> <span id="out"></span>
</div>
<div>
<input id="val" type="number" placeholder="value"/>
<button id="set">set(x)</button> <span id="status"></span>
</div>
<script src="https://cdn.jsdelivr.net/npm/ethers@6.13.2/dist/ethers.min.js"></script>
<script>
let provider, signer, c;
async function mk(){
const addr=document.getElementById('addr').value.trim();
const abi=JSON.parse(document.getElementById('abi').value.trim());
c=new ethers.Contract(addr, abi, signer);
}
document.getElementById('connect').onclick=async()=>{
if(!window.ethereum){ alert('MetaMask not found'); return; }
provider=new ethers.BrowserProvider(window.ethereum);
await provider.send('eth_requestAccounts', []);
signer=await provider.getSigner();
await mk();
};
document.getElementById('get').onclick=async()=>{
if(!c) await mk();
const v=await c.get(); document.getElementById('out').textContent=v.toString();
};
document.getElementById('set').onclick=async()=>{
if(!c) await mk();
const x=document.getElementById('val').value; if(x===''){alert('enter a number');return}
const tx=await c.set(ethers.toBigInt(x));
document.getElementById('status').textContent='Pending '+tx.hash;
const rc=await tx.wait();
document.getElementById('status').textContent='Mined in block '+rc.blockNumber;
};
</script>
</body></html>
Keep MetaMask on your Ganache network so calls go to localhost.
set(123)
+ get()
.get()
and a mined set()
tx.Next: ICE 5 – Tokens (ERC‑20 or ERC‑721) using OpenZeppelin and Hardhat/Foundry.