Interface | Params |
---|---|
claim | [
"project_name"
] |
init | [] |
postRequest | [
"account_id",
"project_name",
"action_name",
"data"
] |
processClaim | [
"project_name"
] |
processRequest | [] |
revokeRequest | [
"id"
] |
Method | Caller | Call time | Transaction |
---|---|---|---|
claim |
2020-10-10 12:29:04
| ||
claim |
2020-10-10 12:23:18
| ||
claim |
2020-10-10 12:23:10
| ||
claim |
2020-10-10 12:23:00
| ||
claim |
2020-10-10 12:17:52
| ||
claim |
2020-10-10 12:16:50
| ||
claim |
2020-10-10 11:56:36
| ||
claim |
2020-10-10 11:54:22
| ||
claim |
2020-10-10 11:37:12
| ||
claim |
2020-10-10 11:19:38
| ||
claim |
2020-10-10 11:19:00
| ||
claim |
2020-10-10 11:17:02
| ||
claim |
2020-10-10 11:16:46
| ||
claim |
2020-10-10 11:16:24
| ||
claim |
2020-10-10 11:16:10
| ||
claim |
2020-10-10 11:15:56
| ||
claim |
2020-10-10 11:15:50
| ||
claim |
2020-10-10 11:07:48
| ||
claim |
2020-10-10 11:06:06
| ||
claim |
2020-10-10 11:04:28
|
local ACCOUNT_PROCESSOR = "1.2.1253844" -- 处理请求的发起者
local CONTRACT_MORTGAGE_TOKEN = "1.16.198" -- 请求发起合约
local CONTRACT_MORTGAGE_LP = "" --TODO 暂无
local CONTRACT_CROSWAP = "1.16.165"
local CONTRACT_CFS = "contract.coswap"
local CONTRACT_36K_COCOS = "contract.cocosmining36k"
local CONTRACT_36K_KKKK = "contract.kkkkmining36k"
local CONTRACT_36K_LP_KKKK = "contract.lpmortgage36k"
local TOKEN_SYMBOL_COCOS = "COCOS"
local TOKEN_SYMBOL_LWT = "LWT"
local TOKEN_SYMBOL_CFS = "CFS"
local TOKEN_SYMBOL_KKKK = "KKKK"
local SETTLE_RATIO = 0.95
local PROJECT_CFS_COCOS = "CFS_COCOS"
local PROJECT_CFS_CFS = "CFS_CFS"
local PROJECT_CFS_LP_CFS = "CFS_LP_CFS"
local PROJECT_CFS_LP_LWT = "CFS_LP_LWT"
local PROJECT_36K_COCOS = "36K_COCOS"
local PROJECT_36K_KKKK = "36K_KKKK"
local PROJECT_36K_LP_KKKK = "36K_LP_KKKK"
local ACTION_SHOOT = "shoot"
local ACTION_UNSHOOT = "unshoot"
local MORT_TYPE_TOKEN = "token"
local MORT_TYPE_LP = "lp"
---------------------------------------------------------------- util function
local function _checkAccountId(account_id)
assert(type(account_id) == "string",
"invalid type of account_id")
assert(string.sub(account_id, 1, 4) == "1.2.",
"account_id should starts with 1.2.")
end
local function _checkTokenAmount(token_amount)
assert(type(token_amount) == "number" or type(token_amount) == "string",
"invalid type of token_amount")
token_amount = tonumber(token_amount)
assert(token_amount and math.floor(token_amount) == token_amount,
"token_amount should be integer")
assert(token_amount > 0, "too little amount")
assert(token_amount <= 1000000000000000, "too much amount")
return token_amount
end
local function _encodeValueType(value)
local tp = type(value)
return tp == "number" and 1
or tp == "string" and 2
or tp == "boolean" and 3
or tp == "table" and 4
or tp == "function" and 5
or 2
end
local function _invokeContractFunction(contract_name, function_name, ...)
local args = {...}
local value_list = {}
for i = 1, #args do
local value = args[i]
if type(value) == "table" then
value = cjson.encode(value)
end
table.insert(value_list, {
_encodeValueType(value),
{v = value},
})
end
if next(value_list) then
value_list = cjson.encode(value_list)
else
value_list = "[]"
end
chainhelper:invoke_contract_function(contract_name, function_name, value_list)
end
local function _checkLP(lp_id)
_invokeContractFunction(CONTRACT_CROSWAP, "checkLP", lp_id)
end
local function _getLPBaseDescribe(lp_id, key)
local lp = cjson.decode(chainhelper:get_nft_asset(lp_id))
local describe = cjson.decode(lp.base_describe)
return describe[key]
end
local function _getLPContractDescribe(lp_id, key)
local lp = cjson.decode(chainhelper:get_nft_asset(lp_id))
for _, contract in pairs(lp.describe_with_contract) do
if contract[1] == CONTRACT_CROSWAP then
for _, describe in pairs(contract[2]) do
if describe[1] == key then
return describe[2]
end
end
end
end
return nil
end
local function _mergeLP(lp_ids)
_invokeContractFunction(CONTRACT_CROSWAP, "mergeLP", lp_ids)
return _getLPContractDescribe(lp_ids[1], "target_id")
end
local function _splitLP(lp_id, liquidity)
_invokeContractFunction(CONTRACT_CROSWAP, "splitLP", lp_id, liquidity)
return cjson.decode(_getLPContractDescribe(lp_id, "target_ids"))
end
local PROJECT_CONFIG = {
[PROJECT_CFS_COCOS] = {
mortgage_type = MORT_TYPE_TOKEN,
mortgage_symbol = TOKEN_SYMBOL_COCOS,
reward_symbol = TOKEN_SYMBOL_CFS,
check = function(action_name, token_amount)
end,
redeem = function(data)
_invokeContractFunction(CONTRACT_CFS,
"draw_cash", 1, 1)
end,
mortgage = function(token_amount)
_invokeContractFunction(CONTRACT_CFS,
"stake_cash", 1, token_amount / 100000, 0)
end,
claim = function()
_invokeContractFunction(CONTRACT_CFS,
"draw_cash", 1, 0)
end,
},
[PROJECT_CFS_CFS] = {
mortgage_type = MORT_TYPE_TOKEN,
mortgage_symbol = TOKEN_SYMBOL_CFS,
reward_symbol = TOKEN_SYMBOL_COCOS,
check = function(action_name, token_amount)
end,
redeem = function(data)
_invokeContractFunction(CONTRACT_CFS,
"draw_cfs", 1)
end,
mortgage = function(token_amount)
_invokeContractFunction(CONTRACT_CFS,
"stake_cfs", token_amount / 100000)
end,
claim = function()
_invokeContractFunction(CONTRACT_CFS,
"draw_cfs", 0)
end,
},
[PROJECT_CFS_LP_LWT] = {
mortgage_type = MORT_TYPE_LP,
lp_symbol = TOKEN_SYMBOL_LWT,
reward_symbol = TOKEN_SYMBOL_CFS,
check = function(action_name, lp_id)
end,
redeem = function(data)
_invokeContractFunction(CONTRACT_CFS,
"draw_cros_mine", 1, 1)
end,
mortgage = function(lp_id)
_invokeContractFunction(CONTRACT_CFS,
"stake_cros_lp", lp_id)
end,
claim = function()
_invokeContractFunction(CONTRACT_CFS,
"draw_cros_mine", 1, 0)
end,
},
[PROJECT_CFS_LP_CFS] = {
mortgage_type = MORT_TYPE_LP,
lp_symbol = TOKEN_SYMBOL_CFS,
reward_symbol = TOKEN_SYMBOL_CFS,
check = function(action_name, lp_id)
end,
redeem = function(data)
_invokeContractFunction(CONTRACT_CFS,
"draw_cros_mine", 2, 1)
end,
mortgage = function(lp_id)
_invokeContractFunction(CONTRACT_CFS,
"stake_cros_lp", lp_id)
end,
claim = function()
_invokeContractFunction(CONTRACT_CFS,
"draw_cros_mine", 2, 0)
end,
},
[PROJECT_36K_COCOS] = {
mortgage_type = MORT_TYPE_TOKEN,
mortgage_symbol = TOKEN_SYMBOL_COCOS,
reward_symbol = TOKEN_SYMBOL_KKKK,
check = function(action_name, token_amount)
if action_name == ACTION_SHOOT then
assert(token_amount >= 10000 * 100000, "mortgage not enough")
end
end,
redeem = function(data)
_invokeContractFunction(CONTRACT_36K_COCOS,
"claim")
_invokeContractFunction(CONTRACT_36K_COCOS,
"redeem", data.amount_total)
end,
mortgage = function(token_amount)
_invokeContractFunction(CONTRACT_36K_COCOS,
"mortgage", token_amount)
end,
claim = function()
_invokeContractFunction(CONTRACT_36K_COCOS,
"claim")
end,
},
[PROJECT_36K_KKKK] = {
mortgage_type = MORT_TYPE_TOKEN,
mortgage_symbol = TOKEN_SYMBOL_KKKK,
reward_symbol = TOKEN_SYMBOL_KKKK,
check = function(action_name, token_amount)
if action_name == ACTION_SHOOT then
assert(token_amount >= 10 * 100000, "mortgage not enough")
end
end,
redeem = function(data)
_invokeContractFunction(CONTRACT_36K_KKKK, "claim")
_invokeContractFunction(CONTRACT_36K_KKKK,
"redeem", data.amount_total)
end,
mortgage = function(token_amount)
_invokeContractFunction(CONTRACT_36K_KKKK,
"mortgage", token_amount)
end,
claim = function()
_invokeContractFunction(CONTRACT_36K_KKKK, "claim")
end,
},
[PROJECT_36K_LP_KKKK] = {
mortgage_type = MORT_TYPE_LP,
lp_symbol = TOKEN_SYMBOL_KKKK,
reward_symbol = TOKEN_SYMBOL_KKKK,
check = function(action_name, lp_id)
if action_name == ACTION_SHOOT then
local liquidity = _getLPBaseDescribe(lp_id, "liquidity")
assert(liquidity >= 10000000, "mortgage not enough")
end
end,
redeem = function(data)
_invokeContractFunction(CONTRACT_36K_LP_KKKK, "claim")
_invokeContractFunction(CONTRACT_36K_LP_KKKK,
"redeem", data.lp_id)
end,
mortgage = function(lp_id)
_invokeContractFunction(CONTRACT_36K_LP_KKKK,
"mortgage", lp_id)
end,
claim = function()
_invokeContractFunction(CONTRACT_36K_LP_KKKK, "claim")
end,
},
}
---------------------------------------------------------------- internal function
local function _redeem(data, config)
if data.amount_total <= 0 then
return
end
local balanceOld = chainhelper:get_account_balance(
contract_base_info.caller, config.reward_symbol)
config.redeem(data)
local balanceNew = chainhelper:get_account_balance(
contract_base_info.caller, config.reward_symbol)
local reward = balanceNew - balanceOld
if config.reward_symbol == config.mortgage_symbol then
reward = reward - data.amount_total
end
if reward <= 0 then
return
end
chainhelper:transfer_from_caller(contract_base_info.owner,
reward, config.reward_symbol, true)
local reward_user = math.floor(reward * SETTLE_RATIO)
data.reward_platform = data.reward_platform + (reward - reward_user)
if reward_user <= 0 then
return
end
local reward_ratio = reward_user / data.amount_total
for account_id, amount in pairs(data.amounts) do
local rwd = math.floor(reward_ratio * amount)
data.rewards[account_id] = (data.rewards[account_id] or 0) + rwd
end
end
local function _shootToken(data, account_id, token_amount)
data.amounts[account_id] = (data.amounts[account_id] or 0) + token_amount
data.amount_total = data.amount_total + token_amount
end
local function _unshootToken(data, account_id, token_symbol)
local token_amount = data.amounts[account_id]
assert(token_amount and token_amount > 0,
"you have no shoot")
data.amounts[account_id] = 0
data.amount_total = data.amount_total - token_amount
chainhelper:transfer_from_caller(contract_base_info.owner,
token_amount, token_symbol, true)
_invokeContractFunction(CONTRACT_MORTGAGE_TOKEN,
"unshootCallback", account_id, token_symbol, token_amount)
end
local function _shootLP(data, account_id, lp_id)
local liquidity = _getLPBaseDescribe(lp_id, "liquidity")
data.amounts[account_id] = (data.amounts[account_id] or 0) + liquidity
data.amount_total = data.amount_total + liquidity
end
local function _unshootLP(data, account_id)
local liquidity = data.amounts[account_id]
assert(liquidity and liquidity > 0, "you have no shoot")
data.amounts[account_id] = 0
data.amount_total = data.amount_total - liquidity
return liquidity
end
---------------------------------------------------------------- public function
function init()
assert(chainhelper:is_owner(), "owner only")
chainhelper:read_chain()
public_data.requests = public_data.requests or {}
for project_name, config in pairs(PROJECT_CONFIG) do
if not public_data[project_name] then
public_data[project_name] = {
amounts = {},
amount_total = 0,
rewards = {},
reward_platform = 0,
}
end
end
chainhelper:write_chain()
end
function postRequest(account_id, project_name, action_name, data)
assert(contract_base_info.invoker_contract_id == CONTRACT_MORTGAGE_TOKEN
or contract_base_info.invoker_contract_id == CONTRACT_MORTGAGE_LP,
"can not be called by other contracts")
read_list = {
public_data = {
requests = true,
[project_name] = true,
},
}
chainhelper:read_chain()
for i, request in pairs(public_data.requests) do
assert(request.ai ~= account_id or request.pn ~= project_name,
"too much request")
end
local config = PROJECT_CONFIG[project_name]
config.check(action_name, data)
if config.mortgage_type == MORT_TYPE_TOKEN then
if action_name == ACTION_SHOOT then
chainhelper:transfer_from_owner(ACCOUNT_PROCESSOR,
data, config.mortgage_symbol, true)
elseif action_name == ACTION_UNSHOOT then
local amount = public_data[project_name].amounts[account_id]
assert(amount and amount > 0, "you have no shoot")
else
assert(false, "action not found")
end
elseif config.mortgage_type == MORT_TYPE_LP then
if action_name == ACTION_SHOOT then
local lp_id = data
_checkLP(lp_id)
local token_symbol = _getLPBaseDescribe(lp_id, "token_symbol")
assert(token_symbol == config.lp_symbol, "invalid lp type")
chainhelper:transfer_nht_from_owner(ACCOUNT_PROCESSOR, lp_id, true)
elseif action_name == ACTION_UNSHOOT then
local amount = public_data[project_name].amounts[account_id]
assert(amount and amount > 0, "you have no shoot")
else
assert(false, "action not found")
end
end
table.insert(public_data.requests, {
id = chainhelper:real_time(),
ai = account_id,
pn = project_name,
an = action_name,
dt = data,
})
write_list = {
public_data = {
requests = true,
},
}
chainhelper:write_chain()
end
function processRequest()
assert(contract_base_info.caller == ACCOUNT_PROCESSOR,
"processor only")
read_list = {
public_data = {},
}
chainhelper:read_chain()
local requests = {
}
for project_name, config in pairs(PROJECT_CONFIG) do
requests[project_name] = {}
end
for i, request in pairs(public_data.requests) do
table.insert(requests[request.pn], request)
end
for project_name, list in pairs(requests) do
if #list > 0 then
local config = PROJECT_CONFIG[project_name]
local data = public_data[project_name]
_redeem(data, config)
local merges = {}
if data.lp_id then
table.insert(merges, data.lp_id)
end
local splits = {}
local split_total = 0
for i, request in pairs(list) do
if config.mortgage_type == MORT_TYPE_TOKEN then
if request.an == ACTION_SHOOT then
_shootToken(data, request.ai, request.dt)
elseif request.an == ACTION_UNSHOOT then
_unshootToken(data, request.ai, config.mortgage_symbol)
end
elseif config.mortgage_type == MORT_TYPE_LP then
if request.an == ACTION_SHOOT then
_shootLP(data, request.ai, request.dt)
table.insert(merges, request.dt)
elseif request.an == ACTION_UNSHOOT then
local liquidity = _unshootLP(data, request.ai)
table.insert(splits, {
account_id = request.ai,
liquidity = liquidity,
})
split_total = split_total + liquidity
end
end
end
if #merges > 1 then
data.lp_id = _mergeLP(merges)
elseif #merges == 1 then
data.lp_id = merges[1]
end
if split_total > 0 then
if data.amount_total <= 0 then
local lp_callback = data.lp_id
data.lp_id = nil
else
local lp_ids = _splitLP(data.lp_id, split_total)
local liquidity = _getLPBaseDescribe(lp_ids[1], "liquidity")
if split_total == liquidity then
lp_callback = lp_ids[1]
data.lp_id = lp_ids[2]
else
lp_callback = lp_ids[2]
data.lp_id = lp_ids[1]
end
end
chainhelper:transfer_nht_from_caller(contract_base_info.owner, lp_callback, true)
_invokeContractFunction(CONTRACT_MORTGAGE_LP,
"unshootCallback", lp_callback, splits)
end
if data.amount_total > 0 then
if config.mortgage_type == MORT_TYPE_TOKEN then
config.mortgage(data.amount_total)
elseif config.mortgage_type == MORT_TYPE_LP then
config.mortgage(data.lp_id)
end
end
end
end
public_data.requests = {}
write_list = {
public_data = {},
}
chainhelper:write_chain()
end
function processClaim(project_name)
assert(contract_base_info.caller == ACCOUNT_PROCESSOR,
"processor only")
read_list = {
public_data = {
[project_name] = true,
},
}
chainhelper:read_chain()
local data = public_data[project_name]
local config = PROJECT_CONFIG[project_name]
if data.amount_total <= 0 then
return
end
local balanceOld = chainhelper:get_account_balance(
contract_base_info.caller, config.reward_symbol)
config.claim()
local balanceNew = chainhelper:get_account_balance(
contract_base_info.caller, config.reward_symbol)
local reward = balanceNew - balanceOld
if config.reward_symbol == config.mortgage_symbol then
reward = reward - data.amount_total
end
if reward <= 0 then
return
end
chainhelper:transfer_from_caller(contract_base_info.owner,
reward, config.reward_symbol, true)
local reward_user = math.floor(reward * SETTLE_RATIO)
data.reward_platform = data.reward_platform + (reward - reward_user)
write_list = {
public_data = {
[project_name] = true,
},
}
chainhelper:write_chain()
end
function revokeRequest(id)
assert(contract_base_info.caller == ACCOUNT_PROCESSOR,
"processor only")
read_list = {
public_data = {
requests = true,
},
}
chainhelper:read_chain()
local request = nil
for i, req in pairs(public_data.requests) do
if req.id == id then
request = req
table.remove(public_data.requests, i)
break
end
end
assert(request, "request no found")
local config = PROJECT_CONFIG[request.pn]
if config.mortgage_type == MORT_TYPE_TOKEN then
if request.an == ACTION_SHOOT then
chainhelper:transfer_from_caller(contract_base_info.owner,
request.dt, config.mortgage_symbol, true)
_invokeContractFunction(CONTRACT_MORTGAGE_TOKEN,
"unshootCallback", request.ai, config.mortgage_symbol, request.dt)
end
elseif config.mortgage_type == MORT_TYPE_LP then
if request.an == ACTION_SHOOT then
chainhelper:transfer_nht_from_caller(contract_base_info.owner, request.dt, true)
_invokeContractFunction(CONTRACT_MORTGAGE_LP,
"unshootCallback", request.ai, request.dt)
end
end
write_list = {
public_data = {
requests = true,
},
}
chainhelper:write_chain()
end
function claim(project_name)
assert(type(project_name) == "string",
"invalid type of project_name")
local config = PROJECT_CONFIG[project_name]
assert(config, "project not found")
read_list = {
public_data = {
[project_name] = true,
},
}
chainhelper:read_chain()
local data = public_data[project_name]
local account_id = contract_base_info.caller
local reward = data.rewards[account_id]
assert(reward and reward > 0, "you have no reward")
chainhelper:transfer_from_owner(account_id,
reward, config.reward_symbol, true)
data.rewards[account_id] = 0
write_list = {
public_data = {
[project_name] = true,
},
}
chainhelper:write_chain()
end