Subscribe to halo92.eth
Subscribe to halo92.eth
Share Dialog
Share Dialog
<100 subscribers
<100 subscribers
功能:将NFT存入Vault铸造为vToken(1个NFT可换少于1个vToken),vToken可在sushiswap上交易。
铸造:NFT-> vToken 赎回:vToken -> NFT
闪电贷服务:任意铸造vToken。
闪电贷目前免费
从NFT铸造vToken费用(mintFee)为0.1
从vToken赎回NFT的的费用分为两种: -随机赎回NFT,费用为randomRedeemFee 0.04; -指定NFT tokenID赎回,费用为targetRedeemFee 0.06
mintFee:NFT->vToken redeemFee:vToken->NFT
手续费计算: 凭空借随机1个NFT的费用为mintFee + randomRedeemFee= 0.14个vToken。vToken在sushi中可获取价格。
NFTXVault:本合约存放了NFT,同时该合约为ERC20,即vToken。该合约提供闪电贷服务,提供铸造vToken和赎回NFT的功能。Vault需要通过代理访问,代理地址可通过NFTXVaultFactory.vaultsForAsset(nftAddress)得到。 NFTXVaultFactory:负责创造各种NFTVault。通过该合约可以查询到NFTXVault的地址。
NFTXVaultFactory:0xBE86f647b167567525cCAAfcd6f881F1Ee558216
tx: https://etherscan.io/tx/0xeb8c3bebed11e2e4fcd30cbfc2fb3c55c4ca166003c7f7d319e78eaab9747098
闪电借5.2 个vToken
通过借到的5.2个vToke赎回5个BAYC,这里费用为randomRedeemFee为0.04,所以 5* 0.04 = 0.2个vToken交给FeeDistributor进行分配。到此时,0x77有6个BAYC。
用6个BAYC领取$APE空投。
将6个BAYC铸造为vToken,这里因为有mintFee 0.1,所以0.6个vToken再次被分配。最终得到5.4个vToken。
将5.2个vToken归还闪电贷,0.2个vToken在sushi上卖出得到14个eth。
套利: 投入:1 BAYC 100eth 产出:14eth 60000 个$APE(213 eth)利润: 227eth - 100eth = 127 eth
无BAYC操作套利: 套利3个:61 eth -> 30000 套利1个:14eth -> 10000 (35 eth)
const sushiRouterV2Addr = '0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F';
const weth_addr = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2';
const vaultFactoryAddr = '0xBE86f647b167567525cCAAfcd6f881F1Ee558216';
const getFeeByNFTAddress = async (nftaddr) => {
// console.log(`get `)
let provider = ethers.getDefaultProvider();
let nft = new ethers.Contract(nftaddr,erc721_abi,provider);
let factory = new ethers.Contract(vaultFactoryAddr,vault_factory_abi,provider);
let vaultAddrList = await factory.vaultsForAsset(nftaddr);
if (vaultAddrList.length > 1) {
console.log(`more vaults found`);
} else if (vaultAddrList.length == 0) {
console.log('no vaults');
return;
}
let vaultAddr = vaultAddrList[0];
let vault = new ethers.Contract(vaultAddr,vault_abi,provider);
const redeemFee = await vault.randomRedeemFee();
const mintFee = await vault.mintFee()
const totalFee = redeemFee.add(mintFee);
const router = new ethers.Contract(sushiRouterV2Addr,router_abi,provider);
// const amountOutMin;
let [amountIn, _] = await router.getAmountsIn(totalFee,[weth_addr,vaultAddr]);
console.log(`NFTx flashloan: borrow 1 * ${await nft.name()} NFT need fee ${ethers.utils.formatEther(amountIn)} e`);
return amountIn;
}
async function main() {
await getFeeByNFTAddress('0x7Bd29408f11D2bFC23c34f18275bBf23bB716Bc7');
}
功能:将NFT存入Vault铸造为vToken(1个NFT可换少于1个vToken),vToken可在sushiswap上交易。
铸造:NFT-> vToken 赎回:vToken -> NFT
闪电贷服务:任意铸造vToken。
闪电贷目前免费
从NFT铸造vToken费用(mintFee)为0.1
从vToken赎回NFT的的费用分为两种: -随机赎回NFT,费用为randomRedeemFee 0.04; -指定NFT tokenID赎回,费用为targetRedeemFee 0.06
mintFee:NFT->vToken redeemFee:vToken->NFT
手续费计算: 凭空借随机1个NFT的费用为mintFee + randomRedeemFee= 0.14个vToken。vToken在sushi中可获取价格。
NFTXVault:本合约存放了NFT,同时该合约为ERC20,即vToken。该合约提供闪电贷服务,提供铸造vToken和赎回NFT的功能。Vault需要通过代理访问,代理地址可通过NFTXVaultFactory.vaultsForAsset(nftAddress)得到。 NFTXVaultFactory:负责创造各种NFTVault。通过该合约可以查询到NFTXVault的地址。
NFTXVaultFactory:0xBE86f647b167567525cCAAfcd6f881F1Ee558216
tx: https://etherscan.io/tx/0xeb8c3bebed11e2e4fcd30cbfc2fb3c55c4ca166003c7f7d319e78eaab9747098
闪电借5.2 个vToken
通过借到的5.2个vToke赎回5个BAYC,这里费用为randomRedeemFee为0.04,所以 5* 0.04 = 0.2个vToken交给FeeDistributor进行分配。到此时,0x77有6个BAYC。
用6个BAYC领取$APE空投。
将6个BAYC铸造为vToken,这里因为有mintFee 0.1,所以0.6个vToken再次被分配。最终得到5.4个vToken。
将5.2个vToken归还闪电贷,0.2个vToken在sushi上卖出得到14个eth。
套利: 投入:1 BAYC 100eth 产出:14eth 60000 个$APE(213 eth)利润: 227eth - 100eth = 127 eth
无BAYC操作套利: 套利3个:61 eth -> 30000 套利1个:14eth -> 10000 (35 eth)
const sushiRouterV2Addr = '0xd9e1cE17f2641f24aE83637ab66a2cca9C378B9F';
const weth_addr = '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2';
const vaultFactoryAddr = '0xBE86f647b167567525cCAAfcd6f881F1Ee558216';
const getFeeByNFTAddress = async (nftaddr) => {
// console.log(`get `)
let provider = ethers.getDefaultProvider();
let nft = new ethers.Contract(nftaddr,erc721_abi,provider);
let factory = new ethers.Contract(vaultFactoryAddr,vault_factory_abi,provider);
let vaultAddrList = await factory.vaultsForAsset(nftaddr);
if (vaultAddrList.length > 1) {
console.log(`more vaults found`);
} else if (vaultAddrList.length == 0) {
console.log('no vaults');
return;
}
let vaultAddr = vaultAddrList[0];
let vault = new ethers.Contract(vaultAddr,vault_abi,provider);
const redeemFee = await vault.randomRedeemFee();
const mintFee = await vault.mintFee()
const totalFee = redeemFee.add(mintFee);
const router = new ethers.Contract(sushiRouterV2Addr,router_abi,provider);
// const amountOutMin;
let [amountIn, _] = await router.getAmountsIn(totalFee,[weth_addr,vaultAddr]);
console.log(`NFTx flashloan: borrow 1 * ${await nft.name()} NFT need fee ${ethers.utils.formatEther(amountIn)} e`);
return amountIn;
}
async function main() {
await getFeeByNFTAddress('0x7Bd29408f11D2bFC23c34f18275bBf23bB716Bc7');
}
//SPDX-License-Identifier: Unlicense
import "@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol";
import "./interface/INFTXVaultFactory.sol";
import "./interface/INFTXVault.sol";
import "./interface/IERC3156Upgradeable.sol";
import "./IClaim.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/interfaces/IERC721Receiver.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "hardhat/console.sol";
// IERC3156FlashBorrower 保证可使用闪电贷
// IERC721Receiver 是因为要将借到的vToken赎回为NFT,所以需要可以接收NFT
contract NFTxFlashLoanExample is IERC3156FlashBorrower ,IERC721Receiver{
bytes32 constant private RETURN_VALUE = keccak256("ERC3156FlashBorrower.onFlashLoan");
INFTXVaultFactory public factory;
struct FlashLoanParams {
address nft; // NFT合约地址
uint256 amount; // num of nft
address claim; // 领取空投的合约地址
uint256[] ids; // 可指定从金库Vault赎回的NFT
}
struct FlashLoanCallbackParams {
address nft;
address claim;
address vault;
uint256 amount; // 赎回几个nft
uint256[] ids;
}
constructor(address _factory) {
factory = INFTXVaultFactory(_factory);
}
function initFlashLoan(FlashLoanParams memory params) external {
// factory.vaultsForAsset(nft);
require(!factory.isLocked(4), "flashloan locked"); // 保证NFTx未关闭闪电贷
address[] memory addrs = factory.vaultsForAsset(params.nft); // 查找对应NFT的zVault
address token = addrs[0];
IERC3156FlashLenderUpgradeable lender = IERC3156FlashLenderUpgradeable(token);
lender.flashLoan(IERC3156FlashBorrowerUpgradeable(address(this)),
token, // token即为NFTVault vToken
params.amount * 10 ** 18, // 一个nft需要1个vtoken
abi.encode(FlashLoanCallbackParams({
nft:params.nft,
claim:params.claim,
amount:params.amount,
vault:token,
ids:params.ids // 不指定id的话手续费会低
})));
}
function onFlashLoan(address initiator, address token, uint256 amount, uint256 fee, bytes memory data) external override
returns (bytes32)
{
console.log("onFlashLoan called");
FlashLoanCallbackParams memory params = abi.decode(data,(FlashLoanCallbackParams));
INFTXVault vault = INFTXVault(params.vault);
uint256[] memory ids = vault.redeem(params.amount, params.ids); // 从vToken 换为NFT,返回得到的tokenId
uint256[] memory amounts;
for (uint i = 0; i < ids.length; i++) {
IClaim(params.claim).claimTokens(); // 领取$APE空投
IERC721(params.nft).approve(address(vault), ids[i]); // 授权Vault可将NFT从this转移到Vault
}
vault.mint(ids, amounts); // 铸造vToken,转移NFT到Valut
IERC20(params.vault).approve(msg.sender, amount + fee); //授权保证闪电贷结束后可以_burn销毁,即归还vToken
return RETURN_VALUE; // 返回该值才可成功进行闪电贷
}
function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external override returns (bytes4){
console.log(string(abi.encodePacked('received ',tokenId, ' from ', from)));
return IERC721Receiver.onERC721Received.selector;
}
}
//SPDX-License-Identifier: Unlicense
import "@openzeppelin/contracts/interfaces/IERC3156FlashBorrower.sol";
import "./interface/INFTXVaultFactory.sol";
import "./interface/INFTXVault.sol";
import "./interface/IERC3156Upgradeable.sol";
import "./IClaim.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/interfaces/IERC721Receiver.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "hardhat/console.sol";
// IERC3156FlashBorrower 保证可使用闪电贷
// IERC721Receiver 是因为要将借到的vToken赎回为NFT,所以需要可以接收NFT
contract NFTxFlashLoanExample is IERC3156FlashBorrower ,IERC721Receiver{
bytes32 constant private RETURN_VALUE = keccak256("ERC3156FlashBorrower.onFlashLoan");
INFTXVaultFactory public factory;
struct FlashLoanParams {
address nft; // NFT合约地址
uint256 amount; // num of nft
address claim; // 领取空投的合约地址
uint256[] ids; // 可指定从金库Vault赎回的NFT
}
struct FlashLoanCallbackParams {
address nft;
address claim;
address vault;
uint256 amount; // 赎回几个nft
uint256[] ids;
}
constructor(address _factory) {
factory = INFTXVaultFactory(_factory);
}
function initFlashLoan(FlashLoanParams memory params) external {
// factory.vaultsForAsset(nft);
require(!factory.isLocked(4), "flashloan locked"); // 保证NFTx未关闭闪电贷
address[] memory addrs = factory.vaultsForAsset(params.nft); // 查找对应NFT的zVault
address token = addrs[0];
IERC3156FlashLenderUpgradeable lender = IERC3156FlashLenderUpgradeable(token);
lender.flashLoan(IERC3156FlashBorrowerUpgradeable(address(this)),
token, // token即为NFTVault vToken
params.amount * 10 ** 18, // 一个nft需要1个vtoken
abi.encode(FlashLoanCallbackParams({
nft:params.nft,
claim:params.claim,
amount:params.amount,
vault:token,
ids:params.ids // 不指定id的话手续费会低
})));
}
function onFlashLoan(address initiator, address token, uint256 amount, uint256 fee, bytes memory data) external override
returns (bytes32)
{
console.log("onFlashLoan called");
FlashLoanCallbackParams memory params = abi.decode(data,(FlashLoanCallbackParams));
INFTXVault vault = INFTXVault(params.vault);
uint256[] memory ids = vault.redeem(params.amount, params.ids); // 从vToken 换为NFT,返回得到的tokenId
uint256[] memory amounts;
for (uint i = 0; i < ids.length; i++) {
IClaim(params.claim).claimTokens(); // 领取$APE空投
IERC721(params.nft).approve(address(vault), ids[i]); // 授权Vault可将NFT从this转移到Vault
}
vault.mint(ids, amounts); // 铸造vToken,转移NFT到Valut
IERC20(params.vault).approve(msg.sender, amount + fee); //授权保证闪电贷结束后可以_burn销毁,即归还vToken
return RETURN_VALUE; // 返回该值才可成功进行闪电贷
}
function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data) external override returns (bytes4){
console.log(string(abi.encodePacked('received ',tokenId, ' from ', from)));
return IERC721Receiver.onERC721Received.selector;
}
}
No activity yet