Files
smom-dbis-138/scripts/chain138/deploy-sushiswap-native.js

189 lines
7.0 KiB
JavaScript

const fs = require("fs");
const path = require("path");
const hre = require("hardhat");
const DEFAULTS = {
weth: "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
usdt: "0x004b63A7B5b0E06f6bB6adb4a5F9f590BF3182D1",
usdc: "0x71D6687F38b93CCad569Fa6352c876eea967201b",
cusdt: "0x93E66202A11B1772E55407B32B44e5Cd8eda7f22",
cusdc: "0xf22258f57794CC8E06237084b353Ab30fFfa640b",
};
function envAddress(name, fallback) {
const value = String(process.env[name] || fallback || "").trim();
if (!value) {
throw new Error(`Missing required address env ${name}`);
}
return value;
}
function envUnits(name, fallback, decimals) {
return hre.ethers.parseUnits(String(process.env[name] || fallback), decimals);
}
async function ensureAllowance(token, owner, spender, amount) {
const allowance = await token.allowance(owner, spender);
if (allowance >= amount) return;
const tx = await token.approve(spender, hre.ethers.MaxUint256);
await tx.wait();
}
async function transferIfNeeded(token, to, amount) {
if (amount <= 0n) return;
const tx = await token.transfer(to, amount);
await tx.wait();
}
async function main() {
const signers = await hre.ethers.getSigners();
const deployer = signers[0];
const feeTo = signers[5] || deployer;
const currentBlock = await hre.ethers.provider.getBlockNumber();
const gasPrice = BigInt(process.env.CHAIN138_SUSHISWAP_GAS_PRICE || (await hre.ethers.provider.send("eth_gasPrice", [])));
const deployOverrides = {
type: 0,
gasPrice,
gasLimit: BigInt(process.env.CHAIN138_SUSHISWAP_DEPLOY_GAS_LIMIT || "9000000"),
};
const liquidityOverrides = {
type: 0,
gasPrice,
gasLimit: BigInt(process.env.CHAIN138_SUSHISWAP_LIQUIDITY_GAS_LIMIT || "3000000"),
};
const weth = envAddress("CHAIN138_NATIVE_WETH9", process.env.WETH9 || DEFAULTS.weth);
const usdt = envAddress("CHAIN138_NATIVE_USDT", process.env.OFFICIAL_USDT_ADDRESS || DEFAULTS.usdt);
const usdc = envAddress("CHAIN138_NATIVE_USDC", process.env.OFFICIAL_USDC_ADDRESS || DEFAULTS.usdc);
const cusdt = envAddress("CHAIN138_COMPLIANT_USDT", process.env.COMPLIANT_USDT_ADDRESS || DEFAULTS.cusdt);
const cusdc = envAddress("CHAIN138_COMPLIANT_USDC", process.env.COMPLIANT_USDC_ADDRESS || DEFAULTS.cusdc);
const Factory = await hre.ethers.getContractFactory(
"contracts/vendor/sushiswap-v2/UniswapV2Factory.sol:UniswapV2Factory"
);
const Router = await hre.ethers.getContractFactory(
"contracts/vendor/sushiswap-v2/UniswapV2Router02.sol:UniswapV2Router02"
);
const Pair = await hre.ethers.getContractFactory(
"contracts/vendor/sushiswap-v2/UniswapV2Pair.sol:UniswapV2Pair"
);
let factory;
let router;
const existingFactory = process.env.CHAIN138_SUSHISWAP_EXISTING_FACTORY?.trim();
const existingRouter = process.env.CHAIN138_SUSHISWAP_EXISTING_ROUTER?.trim();
if (existingFactory && existingRouter) {
factory = Factory.attach(existingFactory);
router = Router.attach(existingRouter);
console.log(`[reuse] factory=${existingFactory}`);
console.log(`[reuse] router=${existingRouter}`);
} else {
console.log(`[deploy] SushiSwapFactory gasPrice=${gasPrice}`);
factory = await Factory.deploy(feeTo.address, deployOverrides);
await factory.waitForDeployment();
console.log(`[ok] factory=${await factory.getAddress()}`);
console.log(`[deploy] SushiSwapRouter02`);
router = await Router.deploy(await factory.getAddress(), weth, deployOverrides);
await router.waitForDeployment();
console.log(`[ok] router=${await router.getAddress()}`);
}
const erc20Abi = [
"function transfer(address to,uint256 amount) returns (bool)",
"function approve(address spender,uint256 amount) returns (bool)",
"function allowance(address owner,address spender) view returns (uint256)",
"function balanceOf(address account) view returns (uint256)",
];
const tokenByAddress = {
[weth.toLowerCase()]: new hre.ethers.Contract(weth, erc20Abi, deployer),
[usdt.toLowerCase()]: new hre.ethers.Contract(usdt, erc20Abi, deployer),
[usdc.toLowerCase()]: new hre.ethers.Contract(usdc, erc20Abi, deployer),
[cusdt.toLowerCase()]: new hre.ethers.Contract(cusdt, erc20Abi, deployer),
[cusdc.toLowerCase()]: new hre.ethers.Contract(cusdc, erc20Abi, deployer),
};
const seedSpecs = [
{
key: "wethUsdt",
tokenA: weth,
tokenB: usdt,
amountA: envUnits("CHAIN138_SUSHISWAP_SEED_WETH_USDT_WETH", "25", 18),
amountB: envUnits("CHAIN138_SUSHISWAP_SEED_WETH_USDT_STABLE", "52915", 6),
},
{
key: "wethUsdc",
tokenA: weth,
tokenB: usdc,
amountA: envUnits("CHAIN138_SUSHISWAP_SEED_WETH_USDC_WETH", "25", 18),
amountB: envUnits("CHAIN138_SUSHISWAP_SEED_WETH_USDC_STABLE", "52915", 6),
},
{
key: "cusdtCusdc",
tokenA: cusdt,
tokenB: cusdc,
amountA: envUnits("CHAIN138_SUSHISWAP_SEED_CUSDT_CUSDC_CUSDT", "250000", 6),
amountB: envUnits("CHAIN138_SUSHISWAP_SEED_CUSDT_CUSDC_CUSDC", "250000", 6),
},
];
const deployedPairs = {};
for (const spec of seedSpecs) {
console.log(`[seed] ${spec.key}`);
let pairAddress = await factory.getPair(spec.tokenA, spec.tokenB);
if (pairAddress === hre.ethers.ZeroAddress) {
const tx = await factory.createPair(spec.tokenA, spec.tokenB, liquidityOverrides);
await tx.wait();
pairAddress = await factory.getPair(spec.tokenA, spec.tokenB);
}
const pair = Pair.attach(pairAddress);
const [reserve0, reserve1] = await pair.getReserves();
if (reserve0 > 0n || reserve1 > 0n) {
deployedPairs[spec.key] = pairAddress;
console.log(`[skip] ${spec.key} already seeded ${pairAddress}`);
continue;
}
const currentABalance = await tokenByAddress[spec.tokenA.toLowerCase()].balanceOf(pairAddress);
const currentBBalance = await tokenByAddress[spec.tokenB.toLowerCase()].balanceOf(pairAddress);
const topUpA = spec.amountA > currentABalance ? spec.amountA - currentABalance : 0n;
const topUpB = spec.amountB > currentBBalance ? spec.amountB - currentBBalance : 0n;
await transferIfNeeded(tokenByAddress[spec.tokenA.toLowerCase()], pairAddress, topUpA);
await transferIfNeeded(tokenByAddress[spec.tokenB.toLowerCase()], pairAddress, topUpB);
const mintTx = await pair.mint(deployer.address, liquidityOverrides);
await mintTx.wait();
deployedPairs[spec.key] = pairAddress;
console.log(`[ok] ${spec.key}=${deployedPairs[spec.key]}`);
}
const output = {
chainId: 138,
deployer: deployer.address,
feeToSetter: feeTo.address,
deployedAtBlock: currentBlock,
factory: await factory.getAddress(),
router: await router.getAddress(),
weth,
usdt,
usdc,
cusdt,
cusdc,
pairs: deployedPairs,
};
const outputPath = path.resolve(__dirname, "../../deployments/chain138/sushiswap-native.json");
fs.mkdirSync(path.dirname(outputPath), { recursive: true });
fs.writeFileSync(outputPath, JSON.stringify(output, null, 2) + "\n");
console.log(JSON.stringify(output, null, 2));
}
main().catch((error) => {
console.error(error);
process.exit(1);
});