Comprehensive guide for Polygon PoS blockchain development. Use when deploying smart contracts to Polygon, testing on Amoy testnet, getting test tokens from faucets, or verifying contracts on Polygonscan. Supports Foundry framework with deployment scripts and testing strategies.
End-to-end guide for developing and deploying smart contracts on Polygon PoS blockchain using Foundry.
Polygon PoS is an EVM-compatible Proof-of-Stake sidechain for Ethereum with:
Default Network: Amoy Testnet (Chain ID: 80002) - Use for all testing before mainnet.
For Agents/Fast Deployment: Jump to Quick Start Path (5-10 min)
For Production/Thorough Testing: Jump to Complete Development Path (30-60 min)
For Reference: See sections below for Network Configuration, Faucets, Troubleshooting
Choose based on your needs:
| Aspect | Quick Start Path | Complete Development Path |
|---|---|---|
| Time | 5-10 minutes | 30-60 minutes |
| Best for | Prototypes, demos, simple contracts | Production, complex systems, mainnet |
| Testing | Basic compilation check | Unit tests, integration tests, fork tests |
| Scripts Used | None (direct forge commands) | Direct forge commands with all options |
| Documentation | Minimal | Full reference guides |
| Verification | Automatic during deploy | Multiple methods with troubleshooting |
| Agent-Friendly | ✅ Optimized for speed | ⚠️ Comprehensive but slower |
Best for: Fast deployment, simple contracts, prototyping Time: 5-10 minutes What you get: Contract deployed and verified on testnet
Skip to Quick Start Path below.
Best for: Production contracts, complex systems, thorough testing Time: 30-60 minutes What you get: Fully tested, optimized, and production-ready deployment
Skip to Complete Development Path below.
Goal: Deploy a contract to Polygon Amoy testnet in minimal steps.
curl -L https://foundry.paradigm.xyz | bash && foundryupforge init my-polygon-project
cd my-polygon-project
Create .env file:
PRIVATE_KEY=your_private_key_without_0x_prefix
# Deploy to Amoy testnet
forge script script/Counter.s.sol:CounterScript \
--rpc-url https://rpc-amoy.polygon.technology \
--private-key $PRIVATE_KEY \
--broadcast
Done! Your contract is deployed and verified on Amoy testnet.
View at: https://amoy.polygonscan.com/address/YOUR_CONTRACT_ADDRESS
Goal: Production-ready deployment with comprehensive testing and optimization.
curl -L https://foundry.paradigm.xyz | bash
foundryup
forge init my-polygon-project
cd my-polygon-project
Update foundry.toml with Polygon settings:
[profile.default]
src = "src"
out = "out"
libs = ["lib"]
solc_version = "0.8.24"
optimizer = true
optimizer_runs = 200
[rpc_endpoints]
amoy = "https://rpc-amoy.polygon.technology"
polygon = "https://polygon-rpc.com"
[etherscan]
amoy = { key = "${POLYGONSCAN_API_KEY}", url = "https://api-amoy.polygonscan.com/api" }
polygon = { key = "${POLYGONSCAN_API_KEY}", url = "https://api.polygonscan.com/api" }
Create .env file:
PRIVATE_KEY=your_private_key
WALLET_ADDRESS=0xYourAddress
POLYGONSCAN_API_KEY=your_api_key
Write Contract (or use assets/sample-contracts/HelloWorld.sol as template)
Write Tests:
// test/MyContract.t.sol
import "forge-std/Test.sol";
import "../src/MyContract.sol";
contract MyContractTest is Test {
MyContract public myContract;
function setUp() public {
myContract = new MyContract();
}
function testDeployment() public {
assertEq(myContract.owner(), address(this));
}
}
forge test -vvv # Run tests
forge test --gas-report # Check gas usage
forge coverage # Check coverage
# Test against real Polygon state
forge test --fork-url https://polygon-rpc.com
See references/testing-strategies.md for comprehensive testing patterns.
Visit one of these faucets:
Alchemy (recommended - no auth): https://www.alchemy.com/faucets/polygon-amoy QuickNode: https://faucet.quicknode.com/polygon/amoy GetBlock: https://getblock.io/faucet/matic-amoy/ Chainlink: https://faucets.chain.link/polygon-amoy LearnWeb3: https://learnweb3.io/faucets/polygon_amoy/
forge script script/Deploy.s.sol \
--rpc-url amoy \
--private-key $PRIVATE_KEY \
--broadcast \
--verify \
--etherscan-api-key $POLYGONSCAN_API_KEY
Create a deployment script in script/Deploy.s.sol:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "forge-std/Script.sol";
import "../src/YourContract.sol";
contract DeployScript is Script {
function run() external {
uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY");
vm.startBroadcast(deployerPrivateKey);
// Deploy your contract
YourContract yourContract = new YourContract();
vm.stopBroadcast();
console.log("Contract deployed to:", address(yourContract));
}
}
See references/foundry-deployment.md for advanced deployment patterns.
If not verified during deployment:
forge verify-contract \
CONTRACT_ADDRESS \
src/MyContract.sol:MyContract \
--chain-id 80002 \
--etherscan-api-key $POLYGONSCAN_API_KEY
See references/contract-verification.md for troubleshooting verification issues.
⚠️ IMPORTANT: Complete mainnet deployment checklist first!
See Mainnet Deployment Checklist below.
forge script script/Deploy.s.sol \
--rpc-url polygon \
--private-key $PRIVATE_KEY \
--broadcast \
--verify \
--etherscan-api-key $POLYGONSCAN_API_KEY
End of Complete Development Path ✅
| Property | Value |
|---|---|
| Network Name | Polygon Amoy |
| Chain ID | 80002 |
| Currency | POL |
| RPC URL | https://rpc-amoy.polygon.technology |
| WebSocket | wss://polygon-amoy.drpc.org |
| Explorer | https://amoy.polygonscan.com |
| Faucets | Multiple (see below) |
| Property | Value |
|---|---|
| Network Name | Polygon |
| Chain ID | 137 |
| Currency | POL |
| RPC URL | https://polygon-rpc.com |
| WebSocket | wss://polygon.drpc.org |
| Explorer | https://polygonscan.com |
Multiple faucets available for Amoy testnet POL tokens.
Run the faucet helper script:
./scripts/get-testnet-tokens.sh
Alchemy Faucet (Recommended - No auth required)
QuickNode Faucet
GetBlock Faucet
Chainlink Faucet
LearnWeb3 Faucet
Tips:
Create .env file (see assets/sample-contracts/.env.example):
PRIVATE_KEY=your_private_key_here
WALLET_ADDRESS=0xYourAddress
POLYGONSCAN_API_KEY=your_api_key_here
Add to .gitignore:
.env
broadcast/
deployments/
Option 1: Use helper script (recommended)
./scripts/deploy-foundry.sh
Option 2: Manual deployment
forge script script/Deploy.s.sol \
--rpc-url amoy \
--private-key $PRIVATE_KEY \
--broadcast \
--verify
Option 3: Deploy without verification
forge script script/Deploy.s.sol \
--rpc-url amoy \
--private-key $PRIVATE_KEY \
--broadcast
⚠️ IMPORTANT: Test thoroughly on Amoy first!
# Use deployment script and select mainnet option
./scripts/deploy-foundry.sh
For detailed deployment patterns, see references/foundry-deployment.md.
Write tests in test/ directory:
// test/MyContract.t.sol
import "forge-std/Test.sol";
import "../src/MyContract.sol";
contract MyContractTest is Test {
MyContract public myContract;
function setUp() public {
myContract = new MyContract();
}
function testFunction() public {
// Test logic
}
}
Run tests:
forge test # Run all tests
forge test -vvv # Verbose output
forge test --gas-report # Show gas usage
Test against real Polygon state:
forge test --fork-url https://polygon-rpc.com
Deploy to Amoy and test with real transactions. See references/testing-strategies.md for comprehensive testing patterns.
Verification makes your contract code public and trustworthy.
forge script script/Deploy.s.sol \
--rpc-url amoy \
--private-key $PRIVATE_KEY \
--broadcast \
--verify \
--etherscan-api-key $POLYGONSCAN_API_KEY
Option 1: Use helper script
./scripts/verify-contract.sh
Option 2: Manual verification
forge verify-contract \
CONTRACT_ADDRESS \
src/MyContract.sol:MyContract \
--chain-id 80002 \
--etherscan-api-key $POLYGONSCAN_API_KEY \
--verifier-url https://api-amoy.polygonscan.com/api
forge verify-contract \
CONTRACT_ADDRESS \
src/MyContract.sol:MyContract \
--chain-id 80002 \
--etherscan-api-key $POLYGONSCAN_API_KEY \
--constructor-args $(cast abi-encode "constructor(address,uint256)" 0x123... 1000)
For troubleshooting verification issues, see references/contract-verification.md.
Use Quick Start Path when:
Use Complete Development Path when:
Before deploying to mainnet:
forge test)Example smart contract structure for Polygon:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
contract HelloWorld {
address public owner;
string public message;
uint256 public updateCount;
event MessageUpdated(address indexed updater, string newMessage);
error NotOwner();
error EmptyMessage();
constructor(string memory initialMessage) {
owner = msg.sender;
message = initialMessage;
}
modifier onlyOwner() {
if (msg.sender != owner) revert NotOwner();
_;
}
function setMessage(string calldata newMessage) external {
if (bytes(newMessage).length == 0) revert EmptyMessage();
message = newMessage;
updateCount++;
emit MessageUpdated(msg.sender, newMessage);
}
}
Key patterns:
Error: insufficient funds for gas * price + value
Solution: Get testnet POL from faucets (run ./scripts/get-testnet-tokens.sh)
Error: src/MyContract.sol:MyContract not found
Solution: Check file path and contract name match exactly
Error: failed to get chain id
Solution:
Error: bytecode does not match
Solution:
Error: gas estimation failed
Solution:
Foundry Documentation
Polygon Documentation
Block Explorers
RPC Providers
Community
For detailed information:
references/foundry-deployment.md - Complete deployment guidereferences/testing-strategies.md - Testing best practicesreferences/contract-verification.md - Verification troubleshooting