Commit f9ba9fce authored by shajiaiming's avatar shajiaiming

Merge branch 'feature/airdrop' into 'master'

Feature/airdrop See merge request !318
parents d425bb69 951f5a2f
This diff is collapsed.
<?php
namespace common\models\psources;
use Yii;
use yii\db\Expression;
class AirDrop extends CommonActiveRecord
{
//定义场景
const SCENARIOS_CREATE = 'create';
const SCENARIOS_UPDATE = 'update';
public static function getDb()
{
return Yii::$app->get('p_sources');
}
public static function tableName()
{
return '{{%wallet_airdrop_apply}}';
}
public function rules()
{
return [
[['identifier', 'wallet_address', 'miner_address'], 'required'],
[['reach_times'], 'integer'],
[['create_time', 'finish_time'], 'safe'],
[['identifier'], 'string', 'length' => [5, 50]],
[['wallet_address', 'miner_address'], 'string', 'length' => [10, 50]],
['identifier', 'unique', 'message' => '树莓派编号已存在'],
['miner_address', 'unique', 'message' => '矿工地址已存在'],
];
}
public function scenarios()
{
$scenarios = [
self:: SCENARIOS_CREATE => ['identifier', 'miner_address', 'reach_times', 'create_time'],
self:: SCENARIOS_UPDATE => ['wallet_address'],
];
return array_merge(parent:: scenarios(), $scenarios);
}
public function attributeLabels()
{
return [
'identifier' => '树莓派编号',
'wallet_address' => '矿主地址',
'miner_address' => '矿工地址',
'reach_times' => '达标次数',
'create_time' => '开始时间',
'finish_time' => '结束时间'
];
}
public function attributes()
{
return array_merge(parent::attributes(), ['reach', 'draw_success', 'income', 'un_draw']);
}
public function getRecord()
{
return $this->hasMany(AirDropApplyRecord::className(), ['apply_id' => 'id'])->all();
}
}
\ No newline at end of file
<?php
namespace common\models\psources;
use Yii;
use yii\db\Expression;
class AirDropApplyRecord extends CommonActiveRecord
{
const REACH_NO = 0; //未达标
const REACH_YES = 1; //已达标
const STATUS_UNDRAW = 0; //未领取
const STATUS_DRAWING = 1; // 领取中
const STATUS_DRAW_SUEEESS = 2; //领取成功
const STATUS_DRAW_FAIL = 3; // 领取失败
//定义场景
const SCENARIOS_CREATE = 'create';
const SCENARIOS_UPDATE = 'update';
public static function getDb()
{
return Yii::$app->get('p_sources');
}
public static function tableName()
{
return '{{%wallet_airdrop_apply_record}}';
}
public function rules()
{
return [
];
}
public function scenarios()
{
$scenarios = [
];
return array_merge(parent:: scenarios(), $scenarios);
}
public function attributeLabels()
{
return [
'apply_id' => '申请ID',
'reach' => '达标情况',
'bonus_token' => '奖励单位',
'draw_status' => '领取情况',
'create_time' => '创建时间',
];
}
public function getApply()
{
return $this->hasOne(AirDrop::className(), ['id' => 'apply_id'])->one();
}
}
\ No newline at end of file
<?php
namespace common\models\psources;
use Yii;
use yii\db\Expression;
class AirDropApplyTransferRecord extends CommonActiveRecord
{
//定义场景
const SCENARIOS_CREATE = 'create';
public static function getDb()
{
return Yii::$app->get('p_sources');
}
public static function tableName()
{
return '{{%wallet_airdrop_apply_transfer_record}}';
}
public function rules()
{
return [
[['apply_record_id', 'create_result', 'sign_result', 'send_result'], 'safe'],
[['apply_record_id'], 'integer'],
];
}
public function scenarios()
{
$scenarios = [
self:: SCENARIOS_CREATE => ['apply_record_id', 'create_result', 'sign_result', 'send_result'],
];
return array_merge(parent:: scenarios(), $scenarios);
}
public function attributeLabels()
{
return [
'apply_record_id' => '申请记录id',
'create_result' => '构造失败原因',
'sign_result' => '签名失败原因',
'send_result' => '发送失败原因',
'create_time' => '创建时间',
];
}
public function getRecord()
{
return $this->hasOne(AirDropApplyRecord::className(), ['id' => 'apply_record_id'])->all();
}
}
\ No newline at end of file
<?php
namespace common\models\psources;
use Yii;
use yii\db\Expression;
class AirDropRule extends CommonActiveRecord
{
//定义场景
const SCENARIOS_CREATE = 'create';
public static function getDb()
{
return Yii::$app->get('p_sources');
}
public static function tableName()
{
return '{{%wallet_airdrop_rule}}';
}
public function rules()
{
return [
[['token', 'amount', 'duration'], 'required'],
[['amount', 'duration'], 'integer'],
[['token'], 'string', 'length' => [2, 10]],
];
}
public function scenarios()
{
$scenarios = [
self:: SCENARIOS_CREATE => ['token', 'amount', 'duration'],
];
return array_merge(parent:: scenarios(), $scenarios);
}
public function attributeLabels()
{
return [
'token' => '空投币种单位',
'amount' => '每次空投数量',
'duration' => '空投周期'
];
}
public function getRecord()
{
return $this->hasMany(AirDropRulePool::className(), ['rule_id' => 'id'])->all();
}
}
\ No newline at end of file
<?php
namespace common\models\psources;
use Yii;
use yii\db\Expression;
class AirDropRulePool extends CommonActiveRecord
{
//定义场景
const SCENARIOS_CREATE = 'create';
public static function getDb()
{
return Yii::$app->get('p_sources');
}
public static function tableName()
{
return '{{%wallet_airdrop_rule_pool}}';
}
public function rules()
{
return [
[['rule_id', 'identifier'], 'required'],
[['identifier'], 'string', 'length' => [5, 50]],
['identifier', 'unique', 'message' => '树莓派编号已存在'],
];
}
public function scenarios()
{
$scenarios = [
self:: SCENARIOS_CREATE => ['rule_id', 'identifier'],
];
return array_merge(parent:: scenarios(), $scenarios);
}
public function attributeLabels()
{
return [
'identifier' => '树莓派编号',
'rule_id' => '所属规则'
];
}
public function getRule()
{
return $this->hasOne(AirDropRule::className(), ['id' => 'rule_id'])->one();
}
}
\ No newline at end of file
...@@ -211,7 +211,6 @@ class Chain33Service ...@@ -211,7 +211,6 @@ class Chain33Service
"fee" => $fee, "fee" => $fee,
"note" => $note, "note" => $note,
"execer" => $execer, "execer" => $execer,
]; ];
return $this->send($params, 'Chain33.CreateRawTransaction'); return $this->send($params, 'Chain33.CreateRawTransaction');
} }
...@@ -259,7 +258,7 @@ class Chain33Service ...@@ -259,7 +258,7 @@ class Chain33Service
public function getBalance($address, $execer = "") public function getBalance($address, $execer = "")
{ {
$params = [ $params = [
'addresses' => $address, 'addresses' => [$address],
'execer' => $execer, 'execer' => $execer,
]; ];
return $this->send($params, 'Chain33.GetBalance'); return $this->send($params, 'Chain33.GetBalance');
......
...@@ -4,15 +4,190 @@ namespace console\controllers; ...@@ -4,15 +4,190 @@ namespace console\controllers;
use Yii; use Yii;
use yii\console\Controller; use yii\console\Controller;
use common\models\psources\AirDrop;
use common\service\chain33\Chain33Service; use common\service\chain33\Chain33Service;
use common\models\psources\AirDropApplyRecord;
use common\models\psources\CoinAirDropTransfer; use common\models\psources\CoinAirDropTransfer;
use common\models\psources\AirDropApplyTransferRecord;
class AirDropController extends Controller class AirDropController extends Controller
{ {
/** /**
* 统计每个树莓派达标次数,已领取,未领取
* @return
*/
public function actionStatistics()
{
$expiry_date = date("Y-m-d", strtotime("+1 day"));
$apply = AirDrop::find()->select('id, identifier, finish_time')->all();
if (empty($apply)) {
return 0;
}
$redis = Yii::$app->redis_app;
foreach ($apply as $val) {
go(function () use ($val, $redis, $expiry_date) {
\Co::sleep(0.5);
if (!empty($val->record)) {
//达标次数
$reach = AirDropApplyRecord::find()
->where(['apply_id' => $val['id'], 'reach' => AirDropApplyRecord::REACH_YES])
->andWhere(['<', 'create_time', $expiry_date])
->sum('reach');
$reach = empty($reach) ? 0 : (int)$reach;
//已领取
$draw_success = AirDropApplyRecord::find()
->where(['apply_id' => $val['id'], 'draw_status' => AirDropApplyRecord::STATUS_DRAW_SUEEESS])
->andWhere(['<', 'create_time', $expiry_date])
->sum('bonus_token');
$draw_success = empty($draw_success) ? 0 : (int)$draw_success;
//总收益
$income = AirDropApplyRecord::find()
->where(['apply_id' => $val['id'], 'reach' => AirDropApplyRecord::REACH_YES])
->andWhere(['<', 'create_time', $expiry_date])
->sum('bonus_token');
$income = empty($income) ? 0 : (int)$income;
//未领取
$un_draw = $income - $draw_success;
$redis->hmset('airdrop:' . $val->identifier, 'reach', $reach, 'draw_success', $draw_success, 'income', $income, 'un_draw', $un_draw);
}
});
}
return 0;
}
/**
* 获取矿工地址的对应的冷钱包地址
* @return
*/
public function actionMinerSourceList()
{
$model = AirDrop::find()->where(['wallet_address' => ''])->asArray()->all();
if (empty($model)) {
return 0;
}
$service = new Chain33Service();
foreach ($model as $key => $val) {
go(function () use ($val, $service) {
\Co::sleep(0.5);
$playload = [
'data' => $val['miner_address']
];
$result = $service->chainQuery('ticket', 'MinerSourceList', $playload);
if (0 == $result['code']) {
$wallet_address = isset($result['result']['datas'][0]) ? $result['result']['datas'][0] : '';
if (!empty($wallet_address)) {
$current_model = AirDrop::findOne($val['id']);
$current_model->wallet_address = $wallet_address;
$current_model->save();
}
}
});
}
}
/**
* 查询地址余额
* 通过矿主地址查询是否有冻结资金,有BTY代表达标
* @return
*/
public function actionReach()
{
$begin = date("Y-m-d", time()) . " 00:00:00";
$end = date("Y-m-d", time()) . " 23:59:59";
$record = AirDropApplyRecord::find()
->where(['reach' => AirDropApplyRecord::REACH_NO])
->andWhere(['between', 'create_time', $begin, $end])
->all();
if (empty($record)) return 0;
$service = new Chain33Service();
$execer = 'ticket';
foreach ($record as $val) {
go(function () use ($val, $service, $execer) {
\Co::sleep(0.5);
$result = $service->getBalance($val->apply->wallet_address, $execer);
if (0 == $result['code']) {
$frozen = $result['result'][0]['frozen'] ?? 0;
if ($frozen > 0) {
$val->reach = AirDropApplyRecord::REACH_YES;
$val->save();
}
}
});
}
}
/**
* 领取符合条件的记录
* @return
*/
public function actionDraw()
{
$record = AirDropApplyRecord::find()->where(['reach' => AirDropApplyRecord::REACH_YES, 'draw_status' => AirDropApplyRecord::STATUS_DRAWING])->all();
if (empty($record)) {
return 0;
}
foreach ($record as $val) {
go(function () use ($val) {
\Co::sleep(0.5);
$amount = $val->amount;
$fee = 1;
$note = '';
$execer = 'token';
$isToken = true;
$tokenSymbol = $val->token;
$val->draw_status = AirDropApplyRecord::STATUS_DRAW_SUEEESS;
$service = new Chain33Service();
$createTokenRawTransaction = $service->createTokenRawTransaction($val->apply->wallet_address, $amount, $isToken, $tokenSymbol, $fee, $note, $execer);
if (0 != $createTokenRawTransaction['code']) {
$val->draw_status = AirDropApplyRecord::STATUS_DRAW_FAIL;
$transfer_record['create_result'] = $createTokenRawTransaction['msg'];
goto doEnd;
}
$privkey = '4ab1b1253e8984acf95797eed52ad9d8247ee96bd9bb49bb08a742d2c4477c0b';
$expire = '1m';
$signRawTx = $service->signRawTx($privkey, $createTokenRawTransaction['result'], $expire);
if (0 != $signRawTx['code']) {
$val->draw_status = AirDropApplyRecord::STATUS_DRAW_FAIL;
$transfer_record['sign_result'] = $signRawTx['msg'];
goto doEnd;
}
$sendTransaction = $service->sendTransaction($signRawTx['result']);
if (0 != $sendTransaction['code']) {
$val->draw_status = AirDropApplyRecord::STATUS_DRAW_FAIL;
$transfer_record['send_result'] = $sendTransaction['msg'];
goto doEnd;
}
doEnd :
if ($val->draw_status == AirDropApplyRecord::STATUS_DRAW_FAIL) {
$transfer_record_model = new AirDropApplyTransferRecord();
$transfer_record['apply_record_id'] = $val->id;
$transfer_record_model->load($transfer_record, '');
$transfer_record_model->save();
}
$val->save();
});
}
return 0;
}
/**
* 获取游戏状态 * 获取游戏状态
* * @return
* @return array
*/ */
public function actionAutoAirDrop() public function actionAutoAirDrop()
{ {
......
<?php
namespace wallet\controllers;
use common\models\psources\AirDropApplyRecord;
use common\service\chain33\Chain33Service;
use Yii;
use wallet\base\BaseController;
use common\models\psources\AirDrop;
class AirDropController extends BaseController
{
/**
* 空投地址余额
* @param
* @return array
*/
public function actionGetBalance()
{
$address = Yii::$app->params['AirDrop']['address'];
$service = new Chain33Service();
$execer = 'coins';
$result = $service->getBalance($address, $execer);
if (0 != $result['code']) {
$this->code = -1;
$this->msg = '余额获取失败。失败原因:' . $result['error'];
goto doEnd;
}
$this->data = $result['result'][0]['balance'] ?? 0;
doEnd :
return ['code' => $this->code, 'msg' => $this->msg, 'data' => $this->data];
}
/**
* 总空投金额
* @param
* @return array
*/
public function actionExpenses()
{
$expiry_date = date("Y-m-d", strtotime("+1 day"));
$this->data = AirDropApplyRecord::find()
->where(['draw_status' => AirDropApplyRecord::STATUS_DRAW_SUEEESS])
->andWhere(['<', 'create_time', $expiry_date])
->sum('bonus_token');
if (empty($this->data)) {
$this->data = 0;
}
doEnd :
return ['code' => $this->code, 'msg' => $this->msg, 'data' => (int)$this->data];
}
/**
* 空投申请列表
* @param page 页码
* @param size 每页显示条数
* @return array
*/
public function actionIndex()
{
$page = Yii::$app->request->get('page', 1);
$size = Yii::$app->request->get('size', 10);
if (!Yii::$app->request->isGet) {
$this->code = -1;
$this->msg = '错误的请求方式.';
goto doEnd;
}
$query = AirDrop::find()->select('identifier, wallet_address,miner_address,create_time, finish_time');
$model = $query->offset(($page - 1) * $size)->orderBy('id desc')->limit($size)->all();
if (empty($model)) {
goto doEnd;
}
$countQuery = clone $query;
$redis = Yii::$app->redis_app;
foreach ($model as &$val) {
list($reach, $draw_success, $income, $un_draw) = $redis->hmget('airdrop:' . $val->identifier, 'reach', 'draw_success', 'income', 'un_draw');
$val->reach = empty($reach) ? 0 : (int)$reach;
$val->draw_success = empty($draw_success) ? 0 : (int)$draw_success;
$val->income = empty($income) ? 0 : (int)$income;
$val->un_draw = empty($un_draw) ? 0 : (int)$un_draw;
}
$this->data = [
'items' => $model,
'total' => (int)$countQuery->count()
];
doEnd :
return ['code' => $this->code, 'msg' => $this->msg, 'data' => $this->data];
}
/**
* 每个树莓派的空投记录
* @param identifier 树莓派编号
* @param miner_address 矿工地址
* @param apply_ids
* @param page 页码
* @param size 每页显示条数
* @return array
*/
public function actionApply()
{
$page = \Yii::$app->request->get('page', 1);
$size = \Yii::$app->request->get('size', 10);
$data = Yii::$app->request->get();
$identifier = $data['identifier'] ?? '';
$miner_address = $data['miner_address'] ?? '';
$apply_ids = isset($data['apply_ids']) ? $data['apply_ids'] : '';
if (false == $identifier || false == $miner_address) {
$this->code = -1;
$this->msg = 'Validation failed.';
goto doEnd;
}
$model = AirDrop::find()->select('id')->where(['identifier' => $identifier, 'miner_address' => $miner_address])->one();
$total = 0;
$items = [];
if (empty($model) || empty($model->record)) {
goto doEnd;
}
$query = AirDropApplyRecord::find()
->select('reach, draw_status, create_time, update_time')
->where(['apply_id' => $model['id']]);
if (!empty($apply_ids)) {
$apply_ids = rtrim($apply_ids, ',');
$apply_id_arr = explode(',', $apply_ids);
$query->andWhere(['in', 'id', $apply_id_arr]);
}
$expiry_date = date("Y-m-d", strtotime("+1 day"));
$query->andWhere(['<', 'create_time', $expiry_date]);
$items = $query->offset(($page - 1) * $size)->orderBy('id desc')->limit($size)->all();
$countQuery = clone $query;
$total = (int)$countQuery->count();
$this->data = [
'items' => $items,
'total' => $total,
];
doEnd :
return ['code' => $this->code, 'msg' => $this->msg, 'data' => $this->data];
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment