Deploy contratos
Ruby Chain corre EVM estándar (no hay opcodes custom). Cualquier contrato que funcione en Ethereum funciona acá.
Setup mínimo (Hardhat)
mkdir my-ruby-project && cd my-ruby-project
npm init -y
npm install --save-dev hardhat @nomicfoundation/hardhat-toolbox @openzeppelin/contracts dotenv
npx hardhat init # → "Create a TypeScript project"Editá hardhat.config.ts:
import "@nomicfoundation/hardhat-toolbox";
import { HardhatUserConfig } from "hardhat/config";
import * as dotenv from "dotenv";
dotenv.config();
const config: HardhatUserConfig = {
solidity: {
version: "0.8.24",
settings: { optimizer: { enabled: true, runs: 200 }, evmVersion: "cancun" },
},
networks: {
ruby: {
url: "https://rpc.ruby.testnet.finetry.win",
chainId: 1810,
accounts: [process.env.PRIVATE_KEY!],
},
},
};
export default config;.env:
PRIVATE_KEY=0x... # tu wallet con RUBY del faucetDeployar un ERC-20
contracts/MyToken.sol:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
contract MyToken is ERC20 {
constructor() ERC20("My Token", "MYT") {
_mint(msg.sender, 1_000_000 * 10**18);
}
}scripts/deploy.ts:
import { ethers } from "hardhat";
async function main() {
const T = await ethers.getContractFactory("MyToken");
const t = await T.deploy();
await t.waitForDeployment();
console.log("MyToken at:", await t.getAddress());
}
main().catch((e) => { console.error(e); process.exit(1); });npx hardhat compile
npx hardhat run scripts/deploy.ts --network rubyFoundry
forge init my-ruby
cd my-ruby
forge install OpenZeppelin/openzeppelin-contracts
cat > .env <<EOF
RPC=https://rpc.ruby.testnet.finetry.win
PK=0x...
EOF
source .env
forge create --rpc-url $RPC --private-key $PK src/MyToken.sol:MyTokenVerificación en Blockscout
Blockscout v8 soporta verificación standard solc-input + flattened.
Vía CLI:
npx hardhat verify --network ruby <CONTRACT_ADDRESS>Vía web:
- Andá a
https://explorer.ruby.testnet.finetry.win/address/<CONTRACT>/contract-verification - Pegá source + selecciona compiler version
- Submit
Cosas a considerar
- Gas precio: la chain corre con base fee dinámico EIP-1559. Casi siempre es de gwei microscópicos. No te preocupes por gas optimization extrema en testnet.
- Block size limit: 60M gas. Suficiente para casi cualquier contrato razonable.
- Hardforks activos: todos hasta Cancun (incluye blob txs en L1, EIP-4844). Tu Solidity puede usar
mcopyy similares. - Predeploys: usá los
0x4200...XXXXpara interactuar con el sistema OP Stack (bridge, fee vaults, etc.).
Patterns útiles
Receive deposits desde L1
Si tu contrato L1 quiere mandar mensajes/value a L2:
// L1 side
import { IL1CrossDomainMessenger } from "...";
IL1CrossDomainMessenger(L1_MESSENGER).sendMessage(
L2_TARGET,
abi.encodeWithSignature("doStuff(bytes)", data),
200_000 // gasLimit on L2
);// L2 side
import { IL2CrossDomainMessenger } from "...";
modifier onlyFromL1Sender(address l1Sender) {
IL2CrossDomainMessenger m = IL2CrossDomainMessenger(0x4200...0007);
require(msg.sender == address(m), "not messenger");
require(m.xDomainMessageSender() == l1Sender, "wrong L1 sender");
_;
}
function doStuff(bytes memory data) external onlyFromL1Sender(MY_L1_CONTROLLER) { ... }Más patterns en docs.optimism.io (opens in a new tab).