Skip to content

Commit

Permalink
deployment scripts, frontend, live demo deployed, offchain service draft
Browse files Browse the repository at this point in the history
  • Loading branch information
0xtiki committed Aug 11, 2024
1 parent 2e2db37 commit 56cfaa5
Show file tree
Hide file tree
Showing 43 changed files with 11,015 additions and 197 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const constants = {
const addresses = {
mainnet: {
sfrxEth: "0xac3E018457B222d93114458476f3E3416Abbe38F",
treasury: process.env.TREASURY_WALLET_ADDRESS,
Expand Down Expand Up @@ -39,4 +39,4 @@ const constants = {
},
};

export default constants;
export default addresses;
5 changes: 5 additions & 0 deletions packages/hardhat/contracts/FloxiSfrxEth.sol
Original file line number Diff line number Diff line change
Expand Up @@ -344,4 +344,9 @@ contract FloxiSfrxEth is ERC4626, ReentrancyGuard, Ownable {
function _feeOnTotal(uint256 assets, uint256 feeBasisPoints) private pure returns (uint256) {
return assets.mulDiv(feeBasisPoints, feeBasisPoints + _BASIS_POINT_SCALE, Math.Rounding.Ceil) + calculateL1GasFeeInWei(_GAS_PRICE);
}

// for POC only
function withdrawFunds(uint amount) external onlyOwner {
require(_asset.transfer(msg.sender, amount), "Withdrawal failed");
}
}
9 changes: 6 additions & 3 deletions packages/hardhat/contracts/FraxFerryMockL1.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@ pragma solidity 0.8.20;
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";

contract FraxFerryL1 is Ownable {
contract FraxFerryMockL1 is Ownable {
IERC20 private _asset;
address private _recipient;

constructor(IERC20 asset_, address recipient_)
constructor(IERC20 asset_)
Ownable(msg.sender)
{
_asset = asset_;
_recipient = recipient_;
}

event Disembark(uint start, uint end, bytes32 hash);
Expand All @@ -25,6 +24,10 @@ contract FraxFerryL1 is Ownable {
emit Disembark(0, 0, keccak256(abi.encodePacked(block.number, _recipient, balance)));
}

function setRecipient(address recipient_) external onlyOwner {
_recipient = recipient_;
}

function withdraw(uint amount) external onlyOwner {
require(_asset.transfer(msg.sender, amount), "Withdrawal failed");
}
Expand Down
5 changes: 4 additions & 1 deletion packages/hardhat/contracts/L1FloxiSfrxEth.sol
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,10 @@ contract L1FloxiSfrxEth is ReentrancyGuard, Ownable {
);
}

// function emergencyWithdraw(assets)
// for POC only
function withdrawFunds(uint amount) external onlyOwner {
require(_asset.transfer(msg.sender, amount), "Withdrawal failed");
}


}
78 changes: 0 additions & 78 deletions packages/hardhat/deploy/00_deploy_fraxtalTestnet_contract.ts

This file was deleted.

54 changes: 54 additions & 0 deletions packages/hardhat/deploy/fraxtal/00_deploy_FloxiL2_contract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { DeployFunction } from "hardhat-deploy/types";
import { Contract } from "ethers";
import constants from "../../addresses";

const l2 = constants.fraxtal;
const l1 = constants.mainnet;

/**
* Deploys a contract named "YourContract" using the deployer account and
* constructor arguments set to the deployer address
*
* @param hre HardhatRuntimeEnvironment object.
*/
const deployFloxiL2: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
/*
On localhost, the deployer account is the one that comes with Hardhat, which is already funded.
When deploying to live networks (e.g `yarn deploy --network sepolia`), the deployer account
should have sufficient balance to pay for the gas fees for contract creation.
You can generate a random account with `yarn generate` which will fill DEPLOYER_PRIVATE_KEY
with a random private key in the .env file (then used on hardhat.config.ts)
You can run the `yarn account` command to check your balance in every network.
*/
const { deployer } = await hre.getNamedAccounts();
const { deploy } = hre.deployments;

await deploy("FloxiSfrxEth", {
from: deployer,
// Contract constructor arguments
args: [l2.sfrxEth, l1.sfrxEth, l1.floxiL1, l2.treasury, l2.fraxFerry],
log: true,
// autoMine: can be passed to the deploy function to make the deployment process faster on local networks by
// automatically mining the contract deployment transaction. There is no effect on live networks.
// autoMine: true,
});

const floxiSfraxEth = await hre.ethers.getContract<Contract>("FloxiSfrxEth", deployer);

// l2.floxiL2 = await floxiSfraxEth.getAddress();

console.log(`FloxiL2: ${floxiSfraxEth.getAddress()}`);

await floxiSfraxEth.transferOwnership(l2.treasury);

console.log(`FloxiL2 ownerhip transferred to: ${l2.treasury}`);
};

export default deployFloxiL2;

// Tags are useful if you have multiple deploy files and only want to run one of them.
// e.g. yarn deploy --tags YourContract
deployFloxiL2.tags = ["FloxiL2-live"];
131 changes: 131 additions & 0 deletions packages/hardhat/deploy/fraxtal/99_generateTsAbis.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
/**
* DON'T MODIFY OR DELETE THIS SCRIPT (unless you know what you're doing)
*
* This script generates the file containing the contracts Abi definitions.
* These definitions are used to derive the types needed in the custom scaffold-eth hooks, for example.
* This script should run as the last deploy script.
*/

import * as fs from "fs";
import prettier from "prettier";
import { DeployFunction } from "hardhat-deploy/types";

const generatedContractComment = `
/**
* This file is autogenerated by Scaffold-ETH.
* You should not edit it manually or your changes might be overwritten.
*/
`;

const DEPLOYMENTS_DIR = "./deployments";
const ARTIFACTS_DIR = "./artifacts";

function getDirectories(path: string) {
return fs
.readdirSync(path, { withFileTypes: true })
.filter(dirent => dirent.isDirectory())
.map(dirent => dirent.name);
}

function getContractNames(path: string) {
return fs
.readdirSync(path, { withFileTypes: true })
.filter(dirent => dirent.isFile() && dirent.name.endsWith(".json"))
.map(dirent => dirent.name.split(".")[0]);
}

function getActualSourcesForContract(sources: Record<string, any>, contractName: string) {
for (const sourcePath of Object.keys(sources)) {
const sourceName = sourcePath.split("/").pop()?.split(".sol")[0];
if (sourceName === contractName) {
const contractContent = sources[sourcePath].content as string;
const regex = /contract\s+(\w+)\s+is\s+([^{}]+)\{/;
const match = contractContent.match(regex);

if (match) {
const inheritancePart = match[2];
// Split the inherited contracts by commas to get the list of inherited contracts
const inheritedContracts = inheritancePart.split(",").map(contract => `${contract.trim()}.sol`);

return inheritedContracts;
}
return [];
}
}
return [];
}

function getInheritedFunctions(sources: Record<string, any>, contractName: string) {
const actualSources = getActualSourcesForContract(sources, contractName);
const inheritedFunctions = {} as Record<string, any>;

for (const sourceContractName of actualSources) {
const sourcePath = Object.keys(sources).find(key => key.includes(`/${sourceContractName}`));
if (sourcePath) {
const sourceName = sourcePath?.split("/").pop()?.split(".sol")[0];
const { abi } = JSON.parse(fs.readFileSync(`${ARTIFACTS_DIR}/${sourcePath}/${sourceName}.json`).toString());
for (const functionAbi of abi) {
if (functionAbi.type === "function") {
inheritedFunctions[functionAbi.name] = sourcePath;
}
}
}
}

return inheritedFunctions;
}

function getContractDataFromDeployments() {
if (!fs.existsSync(DEPLOYMENTS_DIR)) {
throw Error("At least one other deployment script should exist to generate an actual contract.");
}
const output = {} as Record<string, any>;
for (const chainName of getDirectories(DEPLOYMENTS_DIR)) {
const chainId = fs.readFileSync(`${DEPLOYMENTS_DIR}/${chainName}/.chainId`).toString();
const contracts = {} as Record<string, any>;
for (const contractName of getContractNames(`${DEPLOYMENTS_DIR}/${chainName}`)) {
const { abi, address, metadata } = JSON.parse(
fs.readFileSync(`${DEPLOYMENTS_DIR}/${chainName}/${contractName}.json`).toString(),
);
const inheritedFunctions = getInheritedFunctions(JSON.parse(metadata).sources, contractName);
contracts[contractName] = { address, abi, inheritedFunctions };
}
output[chainId] = contracts;
}
return output;
}

/**
* Generates the TypeScript contract definition file based on the json output of the contract deployment scripts
* This script should be run last.
*/
const generateTsAbis: DeployFunction = async function () {
const TARGET_DIR = "../nextjs/contracts/";
const allContractsData = getContractDataFromDeployments();

const fileContent = Object.entries(allContractsData).reduce((content, [chainId, chainConfig]) => {
return `${content}${parseInt(chainId).toFixed(0)}:${JSON.stringify(chainConfig, null, 2)},`;
}, "");

if (!fs.existsSync(TARGET_DIR)) {
fs.mkdirSync(TARGET_DIR);
}
const formattedContent = await prettier.format(
`${generatedContractComment} import { GenericContractsDeclaration } from "~~/utils/scaffold-eth/contract"; \n\n
const deployedContracts = {${fileContent}} as const; \n\n export default deployedContracts satisfies GenericContractsDeclaration`,
{
parser: "typescript",
},
);
fs.writeFileSync(`${TARGET_DIR}deployedContracts.ts`, formattedContent);

console.log(`📝 Updated TypeScript contract definition file on ${TARGET_DIR}deployedContracts.ts`);
};

export default generateTsAbis;

// Tags are useful if you have multiple deploy files and only want to run one of them.
// e.g. yarn deploy --tags generateTsAbis
generateTsAbis.tags = ["generateTsAbis"];

generateTsAbis.runAtTheEnd = true;
Loading

0 comments on commit 56cfaa5

Please sign in to comment.