阿凡达DAPP(泰山众筹)是怎么运作的?全方位拆解Avatar合约代码
泰山众筹在2月份新上线了一个项目——SUN4.0,目前已经改名阿凡达(ANATAR),后文就以阿凡达来称呼。这个阿凡达项目运行在马蹄链上,本质上是一个资金盘。但是和过去的资金盘不同,阿凡达又是以智能合约运行的。代码完全公开,用户在没有前端的情况下,可以通过调用合约拿回自己的资金。显得非常去中心化,非常透明,非常可靠。
今天,我们就了解一下阿凡达项目的玩法和运作逻辑,以及智能合约代码的逻辑。
一、阿凡达是怎么玩的?
阿凡达(ANATAR)的玩法本身是一个存MATIC币,赚Matic币的逻辑,由合约智能执行,完全去中心化。
假设用户准备了800人民币用来投资,他需要先购买Matic代币,即马蹄币。按照8元一个马蹄币的价格算的话,他可以买到100个马蹄币。然后用户将这800个Matic以质押的形式存到ANATAR的智能合约里,大概是会进行如下的分配:
- 65%~进⼊保险合约(即任何⼈动不了,⽤来保障⽤户本⾦,合约到期⾃动返回)
- 6%~进⼊静态奖励池
- 6%~进⼊动态奖励池直接分配完毕
- 0.5%~进⼊后60名奖⾦池进⾏累计
- 0.5%~进⼊节点分红池
- 2%~进⼊平台盈利,这个是平台利润
例如: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; // 1000
uint256 public constant MIN_INVEST = 1e20; // 100uint256 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 info
mapping(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 info
UserGlobalInfo storage userGlobalInfo = userGlobalInfos[msg.sender];
// load global round info
RoundInfo storage roundInfo = roundInfos[ledgerType][targetEpoch];
// placeholder for user round info
UserRoundInfo 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 referrer
require(referrer != address(0) && referrer != msg.sender, “Invalid referrer”);
// make sure referrer is registered already
require(
userGlobalInfos[referrer].referrer != address(0) || children[referrer].length > 0,
“Invalid referrer”
);// update storage
userGlobalInfo.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() 函数:
- 允许只有 operator 能够调用,以设置游戏的暂停状态。
- 如果要取消暂停,函数会检查 tempAdmin 是否已被删除。如果没有被删除,函数会抛出异常。
transferOperator() 函数:
- 允许只有 operator 能够调用,以转移操作者的身份。
- 函数会检查新的操作者地址是否为0地址,如果是,就会抛出异常。
dropTempAdmin() 函数:
- 允许只有 tempAdmin 能够调用,以删除临时管理员的身份。
- 使用 require 语句检查调用该函数的地址是否为临时管理员地址,若不是则会抛出异常。
- 将临时管理员地址设置为 0
batchSetReferrerInfo 函数:
- 此函数用于为多个用户设置推荐人信息。
- 函数接受三个数组类型的参数:users、referrers 和 salesLevels,分别表示需要设置推荐人信息的用户、他们的推荐人和销售级别。
- 使用 require 语句检查调用该函数的地址是否为临时管理员地址,若不是则会抛出异常。
- 使用 require 语句检查 users、referrers 和 salesLevels 数组的长度是否相等,若不相等则会抛出异常。
三、开发一个类似阿凡达的项目难不难
阿凡达项目的开发,主要是在两个方面:前端页面和后端的合约。DAPP前端的页面,包括设计、交互、操作等等,相对来说不是非常的复杂。但是后端的这个合约,就比较困难了。这个合约的设计极为复杂,且具有一定水平。光是拆解,几千字都写不完。大家如果有兴趣,欢迎联系我讨论。电报:@btc6540 微信:btc6540