Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# Fraxiversarry
# Fraxiversary

A composable, ERC20-backed, cross-chain ERC721 collection for the Frax ecosystem intended to commemorate the 5th anniversary of Frax Finance.

## High-level overview

Fraxiversarry is an ERC721-based collection with four core behaviors:
Fraxiversary is an ERC721-based collection with four core behaviors:

1. **BASE minting**
- Users mint NFTs by paying with an allowlisted Frax ERC20.
Expand Down Expand Up @@ -54,8 +54,8 @@ flowchart TB
O[Owner / Admin]
end

subgraph Fraxiversarry_Contract
C["Fraxiversarry
subgraph Fraxiversary_Contract
C["Fraxiversary
ERC721 + Enumerable + Pausable + Burnable
IERC6454 + IERC7590 + ONFT721Core"]
end
Expand All @@ -68,7 +68,7 @@ IERC6454 + IERC7590 + ONFT721Core"]
subgraph LayerZero
LZ[Endpoint + ONFT721 libraries]
D["Destination Chain
Fraxiversarry instance"]
Fraxiversary instance"]
end

U1 -->|paidMint| C
Expand Down Expand Up @@ -175,7 +175,7 @@ stateDiagram-v2

## ERC20 tokenization model (IERC7590-like semantics)

Fraxiversarry tracks ERC20 deposits using internal accounting:
Fraxiversary tracks ERC20 deposits using internal accounting:

- `erc20Balances[tokenId][erc20]`
- `underlyingAssets[tokenId][index]`
Expand Down Expand Up @@ -203,7 +203,7 @@ Fraxiversarry tracks ERC20 deposits using internal accounting:
```mermaid
flowchart LR
U[User] -->|approve| ERC20[ERC20]
U -->|mint| C[Fraxiversarry]
U -->|mint| C[Fraxiversary]
C -->|transferFrom amount + fee| ERC20
C -->|credit amount to tokenId| BAL[erc20Balances]
C -->|record fee| FEES[collectedFees]
Expand Down Expand Up @@ -252,7 +252,7 @@ Owner-only.
```mermaid
sequenceDiagram
participant U as User
participant C as Fraxiversarry
participant C as Fraxiversary

U->>C: fuseTokens(t1,t2,t3,t4)
C->>C: verify ownership of all 4
Expand All @@ -269,7 +269,7 @@ sequenceDiagram
```mermaid
sequenceDiagram
participant U as User
participant C as Fraxiversarry
participant C as Fraxiversary

U->>C: unfuseTokens(premiumTokenId)
C->>C: verify owner
Expand Down Expand Up @@ -313,7 +313,7 @@ flowchart TB

## Cross-chain behavior (LayerZero ONFT721)

Fraxiversarry extends `ONFT721Core`.
Fraxiversary extends `ONFT721Core`.

### Outbound (source chain)
- `_debit(from, tokenId, ...)`
Expand All @@ -334,9 +334,9 @@ Fraxiversarry extends `ONFT721Core`.

```mermaid
sequenceDiagram
participant S as Source Fraxiversarry
participant S as Source Fraxiversary
participant LZ as LayerZero Endpoint
participant D as Destination Fraxiversarry
participant D as Destination Fraxiversary

Note over S: User initiates send
S->>S: _buildMsgAndOptions\n(encodes tokenUri + soulbound flag)
Expand Down
4 changes: 2 additions & 2 deletions assets/metadata/FPI.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Fraxiversarry Base — FPI",
"description": "Fraxiversarry BASE token backed by 1000 FPI deposit.",
"name": "Fraxiversary Base — FPI",
"description": "Fraxiversary BASE token backed by 1000 FPI deposit.",
"external_url": "https://frax.com/nft",
"image": "https://arweave.net/MWrhim4WIYtyfTunYE-QMlpLGHlxVksjBe2G3JAo6rc",
"content": [
Expand Down
4 changes: 2 additions & 2 deletions assets/metadata/WFRAX.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Fraxiversarry Base — WFRAX",
"description": "Fraxiversarry BASE token backed by 1000 WFRAX deposit.",
"name": "Fraxiversary Base — WFRAX",
"description": "Fraxiversary BASE token backed by 1000 WFRAX deposit.",
"external_url": "https://frax.com/nft",
"image": "https://arweave.net/VeSSglLJzT4zAaxGMq-CFV21rki0jV4qHJ1-qbrkqUQ",
"content": [
Expand Down
4 changes: 2 additions & 2 deletions assets/metadata/fused.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Fraxiversarry Fused",
"description": "A FUSED Fraxiversarry token created by fusing four distinct BASE tokens.",
"name": "Fraxiversary Fused",
"description": "A FUSED Fraxiversary token created by fusing four distinct BASE tokens.",
"external_url": "https://frax.com/nft",
"image": "https://arweave.net/T8RKSnK2zTvw-T6TWMwkJOQM0YhHLN-LI9J2wTJWM-o",
"content": [
Expand Down
4 changes: 2 additions & 2 deletions assets/metadata/gift.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Fraxiversarry Gift",
"description": "Fraxiversarry GIFT token backed by 50 WFRAX.",
"name": "Fraxiversary Gift",
"description": "Fraxiversary GIFT token backed by 50 WFRAX.",
"external_url": "https://frax.com/nft",
"image": "https://arweave.net/JsdJJ5r5re4mBmaUHkOjAOxbQIiaqDzFTYYeCKaud_E",
"content": [
Expand Down
4 changes: 2 additions & 2 deletions assets/metadata/sfrxETH.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Fraxiversarry Base — sfrxETH",
"description": "Fraxiversarry BASE token backed by a 1 sfrxETH deposit.",
"name": "Fraxiversary Base — sfrxETH",
"description": "Fraxiversary BASE token backed by a 1 sfrxETH deposit.",
"external_url": "https://frax.com/nft",
"image": "https://arweave.net/N_t7pvdS187n7MMFxaNyV2umBU76MJYzDUBDE8OzroY",
"content": [
Expand Down
4 changes: 2 additions & 2 deletions assets/metadata/sfrxUSD.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Fraxiversarry Base — sfrxUSD",
"description": "Fraxiversarry BASE token backed by 1000 sfrxUSD deposit.",
"name": "Fraxiversary Base — sfrxUSD",
"description": "Fraxiversary BASE token backed by 1000 sfrxUSD deposit.",
"external_url": "https://frax.com/nft",
"image": "https://arweave.net/_J6Loggg2IU0stq32JyfMghmx4oNJ8nih0pedU2glPs",
"content": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@
pragma solidity ^0.8.30;

import {Script, console} from "forge-std/Script.sol";
import {Fraxiversarry} from "../src/Fraxiversarry.sol";
import {Fraxiversary} from "../src/Fraxiversary.sol";

contract FraxiversarryDeployScript is Script {
Fraxiversarry public fraxiversarry;
contract FraxiversaryDeployScript is Script {
Fraxiversary public fraxiversary;
address constant LZ_ENDPOINT = 0x1a44076050125825900e736c501f859c50fE728c;

function run() public {
vm.startBroadcast();

fraxiversarry = new Fraxiversarry(msg.sender, LZ_ENDPOINT);
fraxiversary = new Fraxiversary(msg.sender, LZ_ENDPOINT);

console.log("Fraxiversarry deployed at:", address(fraxiversarry));
console.log("Fraxiversary deployed at:", address(fraxiversary));
console.log("Owner and delegate set to:", msg.sender);
console.log("LayerZero Endpoint set to:", LZ_ENDPOINT);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@
pragma solidity ^0.8.30;

import {Script, console} from "forge-std/Script.sol";
import {Fraxiversarry} from "../src/FraxiversarryEthereum.sol";
import {Fraxiversary} from "../src/FraxiversaryEthereum.sol";

contract FraxiversarryDeployScript is Script {
Fraxiversarry public fraxiversarry;
contract FraxiversaryDeployScript is Script {
Fraxiversary public fraxiversary;
address constant LZ_ENDPOINT = 0x1a44076050125825900e736c501f859c50fE728c;

function run() public {
vm.startBroadcast();

fraxiversarry = new Fraxiversarry(msg.sender, LZ_ENDPOINT);
fraxiversary = new Fraxiversary(msg.sender, LZ_ENDPOINT);

console.log("Ethereum Fraxiversarry deployed at:", address(fraxiversarry));
console.log("Ethereum Fraxiversary deployed at:", address(fraxiversary));
console.log("Owner and delegate set to:", msg.sender);
console.log("LayerZero Endpoint set to:", LZ_ENDPOINT);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
pragma solidity ^0.8.30;

import {Script, console} from "forge-std/Script.sol";
import {Fraxiversarry} from "../src/Fraxiversarry.sol";
import {Fraxiversary} from "../src/Fraxiversary.sol";
import {OptionsBuilder} from "@layerzerolabs/oapp-evm/contracts/oapp/libs/OptionsBuilder.sol";

interface IOAppCore {
Expand Down Expand Up @@ -40,7 +40,7 @@ interface IMessageLibManager {
function setConfig(address _oapp, address _lib, uint32 _eid, uint32 _configType, bytes calldata _config) external;
}

contract FraxiversarryLzConfigScript is Script {
contract FraxiversaryLzConfigScript is Script {
using OptionsBuilder for bytes;

uint256 constant CHAINID_ETHEREUM = 1;
Expand All @@ -52,8 +52,8 @@ contract FraxiversarryLzConfigScript is Script {
uint32 constant EID_ETHEREUM = 30101;
uint32 constant EID_FRAXTAL = 30255;

address constant FRAXIVERSARRY_ETHEREUM = address(0); // TODO
address constant FRAXIVERSARRY_FRAXTAL = address(0); // TODO
address constant FRAXIversary_ETHEREUM = address(0); // TODO
address constant FRAXIversary_FRAXTAL = address(0); // TODO

address constant SEND_LIB_302_ETHEREUM = 0xbB2Ea70C9E858123480642Cf96acbcCE1372dCe1;
address constant RECEIVE_LIB_302_ETHEREUM = 0xc02Ab410f0734EFa3F14628780e6e695156024C2;
Expand Down Expand Up @@ -83,10 +83,10 @@ contract FraxiversarryLzConfigScript is Script {
function _configureEthereumSide() internal {
console.log("Configuring Ethereum connections...");

address localOnft = FRAXIVERSARRY_ETHEREUM;
address localOnft = FRAXIversary_ETHEREUM;
address endpoint = ENDPOINT_ETHEREUM;
uint32 remoteEid = EID_FRAXTAL;
address remoteOnft = FRAXIVERSARRY_FRAXTAL;
address remoteOnft = FRAXIversary_FRAXTAL;
address sendLib302 = SEND_LIB_302_ETHEREUM;
address recvLib302 = RECEIVE_LIB_302_ETHEREUM;
address templateOapp = TEMPLATE_OFT_ETHEREUM;
Expand All @@ -97,10 +97,10 @@ contract FraxiversarryLzConfigScript is Script {
function _configureFraxtalSide() internal {
console.log("Configuring Fraxtal connections...");

address localOnft = FRAXIVERSARRY_FRAXTAL;
address localOnft = FRAXIversary_FRAXTAL;
address endpoint = ENDPOINT_FRAXTAL;
uint32 remoteEid = EID_ETHEREUM;
address remoteOnft = FRAXIVERSARRY_ETHEREUM;
address remoteOnft = FRAXIversary_ETHEREUM;
address sendLib302 = SEND_LIB_302_FRAXTAL;
address recvLib302 = RECEIVE_LIB_302_FRAXTAL;
address templateOapp = TEMPLATE_OFT_FRAXTAL;
Expand Down
32 changes: 16 additions & 16 deletions src/Fraxiversarry.sol → src/Fraxiversary.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ pragma solidity ^0.8.30;
* | /_/ /_/ \__,_/_/|_| /_/ /_/_/ /_/\__,_/_/ /_/\___/\___/ |
* | |
* ====================================================================
* ========================= Fraxiversarry ============================
* ========================= Fraxiversary ============================
* ====================================================================
* Fraxiversarry NFT contract for the 5th anniversary of Frax Finance
* Fraxiversary NFT contract for the 5th anniversary of Frax Finance
* Frax Finance: https://github.com/FraxFinance
*/

Expand All @@ -24,8 +24,8 @@ import {ERC721Enumerable} from "openzeppelin-contracts/contracts/token/ERC721/ex
import {ERC721Pausable} from "openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721Pausable.sol";
import {ERC721URIStorage} from "openzeppelin-contracts/contracts/token/ERC721/extensions/ERC721URIStorage.sol";

import {IFraxiversarryErrors} from "./interfaces/IFraxiversarryErrors.sol";
import {IFraxiversarryEvents} from "./interfaces/IFraxiversarryEvents.sol";
import {IFraxiversaryErrors} from "./interfaces/IFraxiversaryErrors.sol";
import {IFraxiversaryEvents} from "./interfaces/IFraxiversaryEvents.sol";
import {IERC6454} from "./interfaces/IERC6454.sol";
import {IERC7590} from "./interfaces/IERC7590.sol";
import {IERC4906} from "openzeppelin-contracts/contracts/interfaces/IERC4906.sol";
Expand All @@ -38,9 +38,9 @@ import {IOAppMsgInspector} from "@layerzerolabs/oapp-evm/contracts/oapp/interfac
import {Origin} from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol";

/**
* @title Fraxiversarry
* @title Fraxiversary
* @author Frax Finance
* @notice Fraxiversarry is a composable ERC721 that tokenizes ERC20 deposits and supports cross-chain movement
* @notice Fraxiversary is a composable ERC721 that tokenizes ERC20 deposits and supports cross-chain movement
* @dev The contract supports BASE mints funded by approved Frax ERC20s, GIFT mints funded by WFRAX,
* SOULBOUND mints for curated distribution, and FUSED tokens created from four BASE tokens
* @dev Minting for BASE and GIFT is time-boxed by mintingCutoffBlock which is calculated assuming Fraxtal 2s blocks
Expand All @@ -51,16 +51,16 @@ import {Origin} from "@layerzerolabs/oapp-evm/contracts/oapp/OApp.sol";
* Sam Kazemian: https://github.com/samkazemian
* Bjirke (honorary mention for the original idea)
*/
contract Fraxiversarry is
contract Fraxiversary is
ERC721,
ERC721Enumerable,
ERC721URIStorage,
ERC721Pausable,
ERC721Burnable,
IERC6454,
IERC7590,
IFraxiversarryErrors,
IFraxiversarryEvents,
IFraxiversaryErrors,
IFraxiversaryEvents,
ONFT721Core
{
using ONFT721MsgCodec for bytes;
Expand Down Expand Up @@ -94,18 +94,18 @@ contract Fraxiversarry is
mapping(uint256 index => address erc20) public supportedErc20s;

/// @notice Stores the underlying ERC20 asset addresses attached to each tokenId
/// @dev tokenId Fraxiversarry token ID that holds underlying assets
/// @dev tokenId Fraxiversary token ID that holds underlying assets
/// @dev index Position of the underlying asset for the tokenId
/// @dev assets ERC20 token address stored at a given index for the tokenId
mapping(uint256 tokenId => address[] assets) public underlyingAssets;

/// @notice Stores the outbound ERC20 transfer nonce for each tokenId
/// @dev tokenId Fraxiversarry token ID that holds underlying assets
/// @dev tokenId Fraxiversary token ID that holds underlying assets
/// @dev transferOutNonce Number of successful ERC20 withdrawals triggered by burn
mapping(uint256 tokenId => uint256 transferOutNonce) public transferOutNonces;

/// @notice Stores the internal ERC20 balance credited to each tokenId per ERC20
/// @dev tokenId Fraxiversarry token ID that holds underlying assets
/// @dev tokenId Fraxiversary token ID that holds underlying assets
/// @dev erc20 ERC20 token address for which the internal balance is tracked
/// @dev balance Internal accounting balance for the ERC20 held by the tokenId
mapping(uint256 tokenId => mapping(address erc20 => uint256 balance)) public erc20Balances;
Expand All @@ -117,12 +117,12 @@ contract Fraxiversarry is
mapping(uint256 tokenId => mapping(uint256 index => uint256 underlyingTokenId)) public underlyingTokenIds;

/// @notice Marks whether a tokenId is non-transferable under IERC6454 rules
/// @dev tokenId Fraxiversarry token ID to check
/// @dev tokenId Fraxiversary token ID to check
/// @dev nonTransferable True if the token is soulbound
mapping(uint256 tokenId => bool nonTransferable) public isNonTransferrable;

/// @notice Stores the TokenType classification for each tokenId
/// @dev tokenId Fraxiversarry token ID to classify
/// @dev tokenId Fraxiversary token ID to classify
/// @dev tokenType Current type for the tokenId
mapping(uint256 tokenId => TokenType tokenType) public tokenTypes;

Expand Down Expand Up @@ -179,15 +179,15 @@ contract Fraxiversarry is
string private premiumTokenUri;

/**
* @notice Initializes Fraxiversarry with supply caps, fee settings, and ONFT configuration
* @notice Initializes Fraxiversary with supply caps, fee settings, and ONFT configuration
* @dev The mintingCutoffBlock is calculated assuming a fixed 2 second Fraxtal block time
* @dev nextGiftTokenId starts immediately after the BASE tokenId range
* @dev nextPremiumTokenId starts immediately after the GIFT tokenId range
* @param _initialOwner Address that will own the contract and control admin functions
* @param _lzEndpoint LayerZero endpoint used by ONFT721Core
*/
constructor(address _initialOwner, address _lzEndpoint)
ERC721("Fraxiversarry", "FRAX5Y")
ERC721("Fraxiversary", "FRAX5Y")
ONFT721Core(_lzEndpoint, _initialOwner)
{
mintingLimit = 12_000;
Expand Down
Loading