泰山众筹在 2 月份新上线了一个项目——SUN4.0,目前已经改名阿凡达(ANATAR),后文就以阿凡达来称呼。这个阿凡达项目运行在马蹄链上,代码完全公开,用户在没有前端的情况下,可以通过调用合约拿回自己的资金。显得非常去中心化,非常透明,非常可靠。
今天,我们就了解一下阿凡达项目的玩法和运作逻辑,以及智能合约代码的逻辑。
一、阿凡达是怎么玩的?
阿凡达(ANATAR)的玩法本身是一个存 MATIC 币,赚 Matic 币的逻辑,由合约智能执行,完全去中心化。
假设用户准备了 800 人民币用来投资,他需要先购买 Matic 代币,即马蹄币。按照 8 元一个马蹄币的价格算的话,他可以买到 100 个马蹄币。然后用户将这 800 个 Matic 以质押的形式存到 ANATAR 的智能合约里,大概是会进行如下的分配:
例如:100 个 MATIC 进场,其中 65%进入返本池直接锁死,6%动态,2%平台,1%后 60 名爆仓奖励,26%进入收益池,也就是静态提现池,收益池提现提空了就爆仓,爆仓后 65%回本,35%出局,合约接着重启,生生不息!35%损失的,在第二次放大投资金额两倍,优先盈利,重启静态给到 1.5%的收益。
静态每天 0.3-1%,动态最高 4.8% 分六个个合约池
1,自由合约(随进随出)24 小时一次
2,超短合约(3-7 天)系统匹配
3,短合约(8-15 天)系统匹配
4,中合约(16-30 天)系统匹配
5,长合约(31-90 天)
6,超长合约(91-180 天)
*动态:十二个级别,V1-V12,极差 0.4%
二、阿凡达的合约代码拆解
从区块链浏览器可以发现,阿凡达项目部署了了多个合约,我们直接拆解主合约 ANATAR.sol
contract Avatar is ReentrancyGuard, Bucket {uint256 public constant PRINCIPAL_RATIO = 650000; // 65%uint256 public constant INVEST_RATIO = 260000; // 26%uint256 public constant PLATFORM_RATIO = 20000; // 2%uint256 public constant REFERRER_RATIO = 60000; // 6%uint256 public constant INCENTIVE_RATIO = 10000; // 1%uint256 public constant PRICE_PRECISION = 1e6;
uint256 public constant DEFAULT_INVEST_RETURN_RATE = 10000; // 1%uint256 public constant BOOST_INVEST_RETURN_RATE = 5000; // 0.5%
uint256 public constant MAX_INVEST = 1e21; // 1000uint256 public constant MIN_INVEST = 1e20; // 100
uint256 public constant TIME_UNIT = 1 days;uint256[6] public DEFAULT_TARGET_AMOUNTS = [13e22, 25e22, 35e22, 50e22, 75e22, 125e22];
uint256 public constant MAX_SEARCH_DEPTH = 50;uint256 public constant RANKED_INCENTIVE = 60;
address public platformAddress; // will be paymentsplitter contract address
uint256[6] public currentEpochs;
// ledge type => round epoch => address => position index => position infomapping(uint256 => mapping(address => PositionInfo[]))[6] public roundLedgers;//mapping(uint256 => RoundInfo)[6] public roundInfos;//mapping(address => UserRoundInfo[])[6] public userRoundsInfos;
mapping(address => UserGlobalInfo) public userGlobalInfos;
mapping(address => address[]) public children; // used for easily retrieve the referrer tree structure from front-end
复制代码
复制代码
该合约定义了一些常量,包括资金分配比例、价格精度、最大/最小投资金额、时间单位等。它还包含了一些结构体,例如 FundTarget、UserGlobalInfo、PositionInfo、LinkedPosition、RoundInfo 和 UserRoundInfo。
truct FundTarget 用于记录本轮筹资目标的情况,包括上次检查时间、目标金额和已经实现的金额。
struct UserGlobalInfo 记录了用户的全局信息,包括他的推荐人、推荐奖励总额、已领取的推荐奖励、加速积分、销售记录、总头寸金额、报告的销售额和销售级别。
struct PositionInfo 记录了用户头寸的详细信息,包括头寸金额、开仓时间、到期时间、投资回报率、已取回的金额、激励金额、投资回报金额、位置索引和是否可以领取激励。
struct LinkedPosition 记录了与某个回合相关联的某个头寸的地址和索引。
struct RoundInfo 记录了回合信息,包括筹资目标、所有头寸的总金额、当前的主要金额、当前的投资金额、所有头寸的总数、当前开放头寸的总数、当前的激励金额、激励快照、上次 N 个头寸的总数、链表中最后 N 个头寸的头节点、用户回合信息列表的本回合索引以及是否停止亏损。
struct UserRoundInfo 记录了用户在某个回合中的信息,包括当前的回合、总头寸金额、当前主要金额、总提取金额、总领取激励金额、总关闭头寸数和加速回报的金额。
function setStock(uint256 ledgerType,uint8[] calldata typeDays,uint16[] calldata stock) external {require(ledgerType > 0, "Invalid ledger type");require(ledgerType < 6, "Invalid ledger type");require(msg.sender == tempAdmin, "Only admin");require(stock.length > 0, "Invalid stock array");require(typeDays.length == stock.length, "Invalid params");
_setStock(ledgerType, typeDays, stock);}
function openPosition(uint256 ledgerType,uint256 targetEpoch,uint256 targetRate,address referrer,bool useBoost) external payable notContract nonReentrant {require(ledgerType < 6, "Invalid ledger type");require(targetEpoch == currentEpochs[ledgerType], "Invalid epoch");require(msg.value >= MIN_INVEST, "Too small");require(msg.value <= MAX_INVEST, "Too large");require(!gamePaused, "Paused");
// load user global infoUserGlobalInfo storage userGlobalInfo = userGlobalInfos[msg.sender];// load global round infoRoundInfo storage roundInfo = roundInfos[ledgerType][targetEpoch];// placeholder for user round infoUserRoundInfo storage userRoundInfo;
// determine referrer{address _referrer = userGlobalInfo.referrer;// if referrer is already set or msg.sender is the root user whose referrer is address(0)if (_referrer == address(0) && children[msg.sender].length == 0) {// if referrer is not set, set it and make sure it is a valid referrerrequire(referrer != address(0) && referrer != msg.sender, "Invalid referrer");// make sure referrer is registered alreadyrequire(userGlobalInfos[referrer].referrer != address(0) || children[referrer].length > 0,"Invalid referrer");
// update storageuserGlobalInfo.referrer = referrer;children[referrer].push(msg.sender);emit NewReferrer(msg.sender, referrer);}}
复制代码
复制代码
构造函数:
初始化合约时被调用,设置了三个参数:_platformAddress、_tempAdmin、_operator。
对于每个参数,函数会检查它是否为 0 地址,如果是,就会抛出异常。
然后,它会通过 emit NewRound() 函数发出六个事件,分别为 0 到 5,用于初始化所有轮次。
最后,它会将 tempAdmin 设置为 _tempAdmin,将 operator 设置为 _operator,将 platformAddress 设置为 _platformAddress,将 gamePaused 设置为 true。
setPause() 函数:
transferOperator() 函数:
dropTempAdmin() 函数:
batchSetReferrerInfo 函数:
此函数用于为多个用户设置推荐人信息。
函数接受三个数组类型的参数:users、referrers 和 salesLevels,分别表示需要设置推荐人信息的用户、他们的推荐人和销售级别。
使用 require 语句检查调用该函数的地址是否为临时管理员地址,若不是则会抛出异常。
使用 require 语句检查 users、referrers 和 salesLevels 数组的长度是否相等,若不相等则会抛出异常。
三、开发一个类似阿凡达的项目难不难
阿凡达项目的开发,主要是在两个方面:前端页面和后端的合约。DAPP 前端的页面,包括设计、交互、操作等等,相对来说不是非常的复杂。但是后端的这个合约,就比较困难了。这个合约的设计极为复杂,且具有一定水平。光是拆解,几千字都写不完。大家如果有兴趣,欢迎联系我讨论。
评论