Lambda is a powerful framework for developers to create, optimize, and deploy smart contracts across multiple blockchains, currently supporting Solana and Ethereum. It simplifies the process of building Solana SPL token programs and Ethereum ERC-20 contracts, with a modular design that’s easy to extend. This guide walks you through setting up and using Lambda for your blockchain projects.
Prerequisites
Install the following tools to work with both Solana and Ethereum:
Node.js (v16+) : Drives the command-line interface. Install with nvm install 16
or your preferred method.
Rust : For Solana contract development. Install with:
Copy curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Solana CLI : For Solana blockchain interactions. Install via:
Copy sh -c "$(curl -sSfL https://release.solana.com/stable/install)"
Anchor : Solana development framework. Install with:
Copy cargo install --git https://github.com/coral-xyz/anchor anchor-cli --locked
Solidity Compiler (solc) : For Ethereum contract compilation. Install globally:
Configure Solana for Devnet:
Copy solana config set --url https://api.devnet.solana.com
solana-keygen new
For Ethereum, you’ll need an API key from a provider like Infura and a funded testnet wallet (e.g., Sepolia). Update your environment:
Copy export ETHEREUM_RPC_URL=https://sepolia.infura.io/v3/YOUR_INFURA_KEY
export ETHEREUM_PRIVATE_KEY=YOUR_PRIVATE_KEY
Installation
Set up Lambda with these steps:
Create a Project Directory :
Copy mkdir lambda && cd lambda
Initialize Node.js Project :
Copy npm init -y
npm install @solana/web3.js ethers commander
Add Core Files : Create these files with the code from the Code Reference section:
index.js:
Command-line entry point.
generator.js
: Generates contracts for Solana and Ethereum.
optimizer.js
: Applies basic optimization checks.
deployer.js
: Handles deployment to both chains.
Make Executable :
Usage
Lambda uses a command-line interface with generate
and deploy
commands, supporting both Solana and Ethereum.
Step 1: Generate a Contract
Create a Configuration File : Add a config.json
file in the root directory:
Copy {
"name": "MyToken",
"supply": 1000000,
"chains": ["solana", "ethereum"],
"symbol": "MTK"
}
name
: Token name (e.g., "MyToken").
supply
: Initial supply (whole units; Solana adjusts for 6 decimals, Ethereum for 18).
chains
: Array of target blockchains ("solana"
, "ethereum"
, or both).
symbol
: Token symbol (required for Ethereum ERC-20).
Run the Generate Command :
Copy node index.js generate
For Solana: Creates an Anchor-based SPL token project in contracts/mytoken/
.
For Ethereum: Generates a Solidity ERC-20 contract in contracts/MyToken_ethereum.sol
. Basic optimization checks run automatically.
Step 2: Deploy to Blockchains
Deploy the Contract : Specify the contract name or directory:
Solana:
Copy node index.js deploy MyToken
Ethereum:
Copy node index.js deploy MyToken_ethereum.sol
Solana deploys to Devnet; Ethereum deploys to Sepolia (configure RPC and key first).
Solana: Check logs for the program ID and verify with:
Copy solana account <program-id>
Ethereum: Logs show the contract address; verify on Sepolia Etherscan.
How It Works
Lambda’s modular design supports multi-chain development:
Generation :
Solana: Uses Anchor to scaffold an SPL token program, initializing a mint and minting tokens.
Ethereum: Creates an ERC-20 contract with basic transfer functionality.
Optimization :
Checks for common issues (e.g., excessive logging in Solana, public visibility in Ethereum).
Deployment :
Solana: Builds and deploys via Anchor and Solana CLI.
Ethereum: Compiles with solc
and deploys using ethers.js
.
This abstraction lets developers focus on customization rather than boilerplate.
Code Reference
Below are the core files for Lambda. Use these to set up your project.
index.js
Copy #!/usr/bin/env node
const { Command } = require('commander');
const { generateSolanaContract, generateEthereumContract } = require('./generator');
const { optimizeSolanaContract, optimizeEthereumContract } = require('./optimizer');
const { deploySolanaContract, deployEthereumContract } = require('./deployer');
const fs = require('fs');
const program = new Command();
program
.version('0.1.0')
.command('generate')
.action(() => {
const config = JSON.parse(fs.readFileSync('config.json', 'utf8'));
if (config.chains.includes('solana')) {
generateSolanaContract(config);
optimizeSolanaContract(`contracts/${config.name.toLowerCase()}`);
}
if (config.chains.includes('ethereum')) {
generateEthereumContract(config);
optimizeEthereumContract(`contracts/${config.name}_ethereum.sol`);
}
})
.command('deploy <target>')
.action(async (target) => {
if (target.endsWith('.sol')) {
await deployEthereumContract(`contracts/${target}`);
} else {
await deploySolanaContract(`contracts/${target.toLowerCase()}`);
}
});
program.parse(process.argv);
generator.js
Copy const fs = require('fs');
function generateSolanaContract({ name, supply }) {
const anchorToml = `
[provider]
cluster = "devnet"
wallet = "${process.env.HOME}/.config/solana/id.json"
[programs.devnet]
${name.toLowerCase()} = "GENERATED_PROGRAM_ID"
[scripts]
test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
`;
const cargoToml = `
[package]
name = "${name.toLowerCase()}"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib", "lib"]
name = "${name.toLowerCase()}"
[dependencies]
anchor-lang = "0.28.0"
anchor-spl = "0.28.0"
`;
const libRs = `
use anchor_lang::prelude::*;
use anchor_spl::token::{self, Mint, Token, TokenAccount};
declare_id!("GENERATED_PROGRAM_ID");
#[program]
pub mod ${name.toLowerCase()} {
use super::*;
pub fn initialize(ctx: Context<Initialize>, supply: u64) -> Result<()> {
let mint = &mut ctx.accounts.mint;
let authority = &ctx.accounts.authority;
token::initialize_mint(
ctx.accounts.token_program.to_account_info(),
mint.to_account_info(),
authority.to_account_info(),
None,
6,
)?;
token::mint_to(
CpiContext::new(
ctx.accounts.token_program.to_account_info(),
token::MintTo {
mint: mint.to_account_info(),
to: ctx.accounts.token_account.to_account_info(),
authority: authority.to_account_info(),
},
),
supply * 10u64.pow(6),
)?;
msg!("Initialized {} with supply {}", "${name}", supply);
Ok(())
}
}
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(init, payer = authority, space = 82)]
pub mint: Account<'info, Mint>,
#[account(init, payer = authority, space = 165)]
pub token_account: Account<'info, TokenAccount>,
#[account(mut)]
pub authority: Signer<'info>,
pub token_program: Program<'info, Token>,
pub rent: Sysvar<'info, Rent>,
pub system_program: Program<'info, System>,
}
`;
const dir = `contracts/${name.toLowerCase()}`;
fs.mkdirSync(dir, { recursive: true });
fs.writeFileSync(`${dir}/Anchor.toml`, anchorToml);
fs.writeFileSync(`${dir}/Cargo.toml`, cargoToml);
fs.writeFileSync(`${dir}/src/lib.rs`, libRs);
console.log(`Generated Solana Anchor project: ${dir}`);
}
function generateEthereumContract({ name, symbol, supply }) {
const code = `
pragma solidity ^0.8.0;
contract ${name} {
string public name = "${name}";
string public symbol = "${symbol}";
uint256 public totalSupply = ${supply} * 10**18;
mapping(address => uint256) public balanceOf;
constructor() {
balanceOf[msg.sender] = totalSupply;
}
function transfer(address to, uint256 amount) public returns (bool) {
require(balanceOf[msg.sender] >= amount, "Insufficient balance");
balanceOf[msg.sender] -= amount;
balanceOf[to] += amount;
return true;
}
}
`;
fs.writeFileSync(`contracts/${name}_ethereum.sol`, code);
console.log(`Generated Ethereum contract: ${name}_ethereum.sol`);
}
module.exports = { generateSolanaContract, generateEthereumContract };
optimizer.js
Copy const fs = require('fs');
function optimizeSolanaContract(dir) {
const code = fs.readFileSync(`${dir}/src/lib.rs`, 'utf8');
if (code.match(/msg!/g)?.length > 5) {
console.log(`Warning: Excessive logging in ${dir}/src/lib.rs may exceed compute budget.`);
}
if (!code.includes('space =')) {
console.log(`Error: Missing space allocation in account structs; deployment will fail.`);
}
}
function optimizeEthereumContract(filePath) {
const code = fs.readFileSync(filePath, 'utf8');
if (code.includes('mapping') && !code.includes('private')) {
console.log(`Warning: Public mapping in ${filePath} may increase gas costs. Consider 'private'.`);
}
}
module.exports = { optimizeSolanaContract, optimizeEthereumContract };
deployer.js
Copy const { Connection, Keypair } = require('@solana/web3.js');
const ethers = require('ethers');
const fs = require('fs');
const { execSync } = require('child_process');
async function deploySolanaContract(dir) {
execSync(`anchor build`, { cwd: dir });
execSync(`anchor deploy`, { cwd: dir });
const programId = execSync(`solana address -k ${dir}/target/deploy/${dir.split('/')[1]}-keypair.json`, { encoding: 'utf8' }).trim();
let anchorToml = fs.readFileSync(`${dir}/Anchor.toml`, 'utf8');
anchorToml = anchorToml.replace('GENERATED_PROGRAM_ID', programId);
fs.writeFileSync(`${dir}/Anchor.toml`, anchorToml);
let libRs = fs.readFileSync(`${dir}/src/lib.rs`, 'utf8');
libRs = libRs.replace('GENERATED_PROGRAM_ID', programId);
fs.writeFileSync(`${dir}/src/lib.rs`, libRs);
console.log(`Deployed to Solana Devnet: ${programId}`);
return programId;
}
async function deployEthereumContract(filePath) {
const provider = new ethers.JsonRpcProvider(process.env.ETHEREUM_RPC_URL);
const wallet = new ethers.Wallet(process.env.ETHEREUM_PRIVATE_KEY, provider);
const code = fs.readFileSync(filePath, 'utf8');
const compiled = JSON.parse(execSync(`solc --optimize --abi --bin ${filePath} -o build --overwrite`, { encoding: 'utf8' }));
const factory = new ethers.ContractFactory(compiled.abi, compiled.bin, wallet);
const contract = await factory.deploy();
await contract.deployed();
console.log(`Deployed to Ethereum Sepolia: ${contract.address}`);
return contract.address;
}
module.exports = { deploySolanaContract, deployEthereumContract };
Extending Lambda
Customize Lambda with these options:
New Contract Types : Add templates in generator.js
for staking, NFTs, or other programs.
Advanced Optimization : Integrate tools for compute budget analysis (Solana) or gas profiling (Ethereum).
Additional Chains : Extend to Binance Smart Chain, Polygon, etc., by updating generator and deployer logic.
Troubleshooting
Anchor Build Fails : Verify Rust and Anchor versions (rustc --version
, anchor --version
).
Solana Deployment Errors : Ensure your keypair has SOL (solana airdrop
2 on Devnet).
Ethereum Deployment Fails : Check ETHEREUM_RPC_URL
and ETHEREUM_PRIVATE_KEY
are set and funded.
Config Issues : Ensure config.json
is valid JSON.