diff --git a/app/Bean/Model/Api/Wallet/CustomerWalletBalanceTransactionBean.php b/app/Bean/Model/Api/Wallet/CustomerWalletBalanceTransactionBean.php index 0a4e2c1..b53d15b 100644 --- a/app/Bean/Model/Api/Wallet/CustomerWalletBalanceTransactionBean.php +++ b/app/Bean/Model/Api/Wallet/CustomerWalletBalanceTransactionBean.php @@ -14,6 +14,7 @@ class CustomerWalletBalanceTransactionBean extends BaseBean protected $uid; protected $currency_code = CustomerWalletCurrencyModel::CODE_USDT_TRC20; protected $amount = 0; + protected $fee_amount = 0; protected $before_total_amount; protected $after_total_amount; protected $source_params; @@ -27,6 +28,17 @@ class CustomerWalletBalanceTransactionBean extends BaseBean protected $created_at; protected $updated_at; + public function getFeeAmount(): int + { + return $this->fee_amount; + } + + public function setFeeAmount(int $fee_amount): void + { + $this->fee_amount = $fee_amount; + } + + public function getTargetPostOrderDisputeId() { return $this->target_post_order_dispute_id; diff --git a/app/Bean/Model/Wallet/Platform/WalletPlatformBalanceTransactionBean.php b/app/Bean/Model/Wallet/Platform/WalletPlatformBalanceTransactionBean.php new file mode 100644 index 0000000..aa2ae37 --- /dev/null +++ b/app/Bean/Model/Wallet/Platform/WalletPlatformBalanceTransactionBean.php @@ -0,0 +1,305 @@ +id; + } + + public function setId($id): void + { + $this->id = $id; + } + + public function getSn() + { + return $this->sn; + } + + public function setSn($sn): void + { + $this->sn = $sn; + } + + public function getBindWalletAddressId() + { + return $this->bind_wallet_address_id; + } + + public function setBindWalletAddressId($bind_wallet_address_id): void + { + $this->bind_wallet_address_id = $bind_wallet_address_id; + } + + public function getBindWalletAddress() + { + return $this->bind_wallet_address; + } + + public function setBindWalletAddress($bind_wallet_address): void + { + $this->bind_wallet_address = $bind_wallet_address; + } + + public function getFromWalletAddressId() + { + return $this->from_wallet_address_id; + } + + public function setFromWalletAddressId($from_wallet_address_id): void + { + $this->from_wallet_address_id = $from_wallet_address_id; + } + + public function getFromWalletAddress() + { + return $this->from_wallet_address; + } + + public function setFromWalletAddress($from_wallet_address): void + { + $this->from_wallet_address = $from_wallet_address; + } + + public function getToWalletAddressId() + { + return $this->to_wallet_address_id; + } + + public function setToWalletAddressId($to_wallet_address_id): void + { + $this->to_wallet_address_id = $to_wallet_address_id; + } + + public function getToWalletAddress() + { + return $this->to_wallet_address; + } + + public function setToWalletAddress($to_wallet_address): void + { + $this->to_wallet_address = $to_wallet_address; + } + + + + public function getCallbackWalletAddressTransactionId() + { + return $this->callback_wallet_address_transaction_id; + } + + public function setCallbackWalletAddressTransactionId($callback_wallet_address_transaction_id): void + { + $this->callback_wallet_address_transaction_id = $callback_wallet_address_transaction_id; + } + + public function getUid() + { + return $this->uid; + } + + public function setUid($uid): void + { + $this->uid = $uid; + } + + + public function getSourceWalletId() + { + return $this->source_wallet_id; + } + + public function setSourceWalletId($source_wallet_id): void + { + $this->source_wallet_id = $source_wallet_id; + } + + public function getBalanceId() + { + return $this->balance_id; + } + + public function setBalanceId($balance_id): void + { + $this->balance_id = $balance_id; + } + + public function getType() + { + return $this->type; + } + + public function setType($type): void + { + $this->type = $type; + } + + public function getStatus() + { + return $this->status; + } + + public function setStatus($status): void + { + $this->status = $status; + } + + public function getPlatformId() + { + return $this->platform_id; + } + + public function setPlatformId($platform_id): void + { + $this->platform_id = $platform_id; + } + + public function getCurrencyCode() + { + return $this->currency_code; + } + + public function setCurrencyCode($currency_code): void + { + $this->currency_code = $currency_code; + } + + public function getBlockTransactionId() + { + return $this->block_transaction_id; + } + + public function setBlockTransactionId($block_transaction_id): void + { + $this->block_transaction_id = $block_transaction_id; + } + + + public function getFeeAmount() + { + return $this->fee_amount; + } + + public function setFeeAmount($fee_amount): void + { + $this->fee_amount = $fee_amount; + } + + public function getAmount() + { + return $this->amount; + } + + public function setAmount($amount): void + { + $this->amount = $amount; + } + + + public function getBeforeTotalAmount() + { + return $this->before_total_amount; + } + + public function setBeforeTotalAmount($before_total_amount): void + { + $this->before_total_amount = $before_total_amount; + } + + public function getAfterTotalAmount() + { + return $this->after_total_amount; + } + + public function setAfterTotalAmount($after_total_amount): void + { + $this->after_total_amount = $after_total_amount; + } + + public function getRemark() + { + return $this->remark; + } + + public function setRemark($remark): void + { + $this->remark = $remark; + } + + public function getCallbackTime() + { + return $this->callback_time; + } + + public function setCallbackTime($callback_time): void + { + $this->callback_time = $callback_time; + } + + + public function getIsNotify() + { + return $this->is_notify; + } + + public function setIsNotify($is_notify): void + { + $this->is_notify = $is_notify; + } + + public function getCreatedAt() + { + return $this->created_at; + } + + public function setCreatedAt($created_at): void + { + $this->created_at = $created_at; + } + + public function getUpdatedAt() + { + return $this->updated_at; + } + + public function setUpdatedAt($updated_at): void + { + $this->updated_at = $updated_at; + } + + +} diff --git a/app/Bean/Model/Wallet/Tron/WalletTronBlockBean.php b/app/Bean/Model/Wallet/Tron/WalletTronBlockBean.php new file mode 100644 index 0000000..8cf65b6 --- /dev/null +++ b/app/Bean/Model/Wallet/Tron/WalletTronBlockBean.php @@ -0,0 +1,79 @@ +id; + } + + public function setId($id): void + { + $this->id = $id; + } + + public function getStatus() + { + return $this->status; + } + + public function setStatus($status): void + { + $this->status = $status; + } + + public function getBlockId() + { + return $this->block_id; + } + + public function setBlockId($block_id): void + { + $this->block_id = $block_id; + } + + public function getBlockNum() + { + return $this->block_num; + } + + public function setBlockNum($block_num): void + { + $this->block_num = $block_num; + } + + public function getBlockTimestamp() + { + return $this->block_timestamp; + } + + public function setBlockTimestamp($block_timestamp): void + { + $this->block_timestamp = $block_timestamp; + } + + public function getCreatedAt() + { + return $this->created_at; + } + + public function setCreatedAt($created_at): void + { + $this->created_at = $created_at; + } + + + +} diff --git a/app/Bean/Model/Wallet/Wallet/WalletAddressBean.php b/app/Bean/Model/Wallet/Wallet/WalletAddressBean.php new file mode 100644 index 0000000..dd61392 --- /dev/null +++ b/app/Bean/Model/Wallet/Wallet/WalletAddressBean.php @@ -0,0 +1,124 @@ +id; + } + + public function setId($id): void + { + $this->id = $id; + } + + public function getUseStatus() + { + return $this->use_status; + } + + public function setUseStatus($use_status): void + { + $this->use_status = $use_status; + } + + public function getCurrencyCode() + { + return $this->currency_code; + } + + public function setCurrencyCode($currency_code): void + { + $this->currency_code = $currency_code; + } + + public function getBalance() + { + return $this->balance; + } + + public function setBalance($balance): void + { + $this->balance = $balance; + } + + public function getAddressHex() + { + return $this->address_hex; + } + + public function setAddressHex($address_hex): void + { + $this->address_hex = $address_hex; + } + + public function getAddressBase58() + { + return $this->address_base58; + } + + public function setAddressBase58($address_base58): void + { + $this->address_base58 = $address_base58; + } + + public function getPrivateKey() + { + return $this->private_key; + } + + public function setPrivateKey($private_key): void + { + $this->private_key = $private_key; + } + + public function getRemark() + { + return $this->remark; + } + + public function setRemark($remark): void + { + $this->remark = $remark; + } + + public function getCreatedAt() + { + return $this->created_at; + } + + public function setCreatedAt($created_at): void + { + $this->created_at = $created_at; + } + + public function getUpdatedAt() + { + return $this->updated_at; + } + + public function setUpdatedAt($updated_at): void + { + $this->updated_at = $updated_at; + } + + + +} diff --git a/app/Bean/Model/Wallet/Wallet/WalletAddressTransactionBean.php b/app/Bean/Model/Wallet/Wallet/WalletAddressTransactionBean.php new file mode 100644 index 0000000..b287e33 --- /dev/null +++ b/app/Bean/Model/Wallet/Wallet/WalletAddressTransactionBean.php @@ -0,0 +1,169 @@ +id; + } + + public function setId($id): void + { + $this->id = $id; + } + + public function getCurrencyCode() + { + return $this->currency_code; + } + + public function setCurrencyCode($currency_code): void + { + $this->currency_code = $currency_code; + } + + public function getType() + { + return $this->type; + } + + public function setType($type): void + { + $this->type = $type; + } + + public function getWalletAddressId() + { + return $this->wallet_address_id; + } + + public function setWalletAddressId($wallet_address_id): void + { + $this->wallet_address_id = $wallet_address_id; + } + + public function getAmount() + { + return $this->amount; + } + + public function setAmount($amount): void + { + $this->amount = $amount; + } + + public function getBlockTransactionId() + { + return $this->block_transaction_id; + } + + public function setBlockTransactionId($block_transaction_id): void + { + $this->block_transaction_id = $block_transaction_id; + } + + public function getBlockNumber() + { + return $this->block_number; + } + + public function setBlockNumber($block_number): void + { + $this->block_number = $block_number; + } + + public function getBlockEventName() + { + return $this->block_event_name; + } + + public function setBlockEventName($block_event_name): void + { + $this->block_event_name = $block_event_name; + } + + public function getBlockFromAddress() + { + return $this->block_from_address; + } + + public function setBlockFromAddress($block_from_address): void + { + $this->block_from_address = $block_from_address; + } + + public function getBlockToAddress() + { + return $this->block_to_address; + } + + public function setBlockToAddress($block_to_address): void + { + $this->block_to_address = $block_to_address; + } + + public function getBlockValue() + { + return $this->block_value; + } + + public function setBlockValue($block_value): void + { + $this->block_value = $block_value; + } + + public function getBlockTimestamp() + { + return $this->block_timestamp; + } + + public function setBlockTimestamp($block_timestamp): void + { + $this->block_timestamp = $block_timestamp; + } + + public function getCreatedAt() + { + return $this->created_at; + } + + public function setCreatedAt($created_at): void + { + $this->created_at = $created_at; + } + + public function getIsNotify() + { + return $this->is_notify; + } + + public function setIsNotify($is_notify): void + { + $this->is_notify = $is_notify; + } + + + + + +} diff --git a/app/Bean/Model/Wallet/Wallet/WalletPlatformBindBean.php b/app/Bean/Model/Wallet/Wallet/WalletPlatformBindBean.php new file mode 100644 index 0000000..a7a3a71 --- /dev/null +++ b/app/Bean/Model/Wallet/Wallet/WalletPlatformBindBean.php @@ -0,0 +1,79 @@ +id; + } + + public function setId($id): void + { + $this->id = $id; + } + + public function getPlatformId() + { + return $this->platform_id; + } + + public function setPlatformId($platform_id): void + { + $this->platform_id = $platform_id; + } + + public function getWalletAddressId() + { + return $this->wallet_address_id; + } + + public function setWalletAddressId($wallet_address_id): void + { + $this->wallet_address_id = $wallet_address_id; + } + + public function getCurrencyCode() + { + return $this->currency_code; + } + + public function setCurrencyCode($currency_code): void + { + $this->currency_code = $currency_code; + } + + public function getUid() + { + return $this->uid; + } + + public function setUid($uid): void + { + $this->uid = $uid; + } + + public function getCreatedAt() + { + return $this->created_at; + } + + public function setCreatedAt($created_at): void + { + $this->created_at = $created_at; + } + + + +} diff --git a/app/Bean/Queue/QueueBaseBean.php b/app/Bean/Queue/QueueBaseBean.php new file mode 100644 index 0000000..70a6575 --- /dev/null +++ b/app/Bean/Queue/QueueBaseBean.php @@ -0,0 +1,25 @@ +try_times += $num; + } + + public function checkTryTimes(): bool + { + if($this->try_times >= self::TRY_LIMIT) { + return false; + } + return true; + } + +} + diff --git a/app/Bean/Queue/Wallet/QueueEventBean.php b/app/Bean/Queue/Wallet/QueueEventBean.php new file mode 100644 index 0000000..c0707a3 --- /dev/null +++ b/app/Bean/Queue/Wallet/QueueEventBean.php @@ -0,0 +1,123 @@ +block_number; + } + + public function setBlockNumber($block_number): void + { + $this->block_number = $block_number; + } + + public function getBlockTimestamp() + { + return $this->block_timestamp; + } + + public function setBlockTimestamp($block_timestamp): void + { + $this->block_timestamp = $block_timestamp; + } + + public function getCallerContractAddress() + { + return $this->caller_contract_address; + } + + public function setCallerContractAddress($caller_contract_address): void + { + $this->caller_contract_address = $caller_contract_address; + } + + public function getContractAddress() + { + return $this->contract_address; + } + + public function setContractAddress($contract_address): void + { + $this->contract_address = $contract_address; + } + + public function getEvent() + { + return $this->event; + } + + public function setEvent($event): void + { + $this->event = $event; + } + + public function getEventIndex() + { + return $this->event_index; + } + + public function setEventIndex($event_index): void + { + $this->event_index = $event_index; + } + + public function getEventName() + { + return $this->event_name; + } + + public function setEventName($event_name): void + { + $this->event_name = $event_name; + } + + public function getResult(): EventResultBean + { + return $this->result; + } + + public function setResult(EventResultBean $result): void + { + $this->result = $result; + } + + public function getResultType(): EventResultTypeBean + { + return $this->result_type; + } + + public function setResultType(EventResultTypeBean $result_type): void + { + $this->result_type = $result_type; + } + + public function getTransactionId() + { + return $this->transaction_id; + } + + public function setTransactionId($transaction_id): void + { + $this->transaction_id = $transaction_id; + } + + +} diff --git a/app/Bean/Queue/Wallet/QueueNotifyToPlatformBean.php b/app/Bean/Queue/Wallet/QueueNotifyToPlatformBean.php new file mode 100644 index 0000000..0ce66ff --- /dev/null +++ b/app/Bean/Queue/Wallet/QueueNotifyToPlatformBean.php @@ -0,0 +1,84 @@ +platform_id; + } + + public function setPlatformId($platform_id): void + { + $this->platform_id = $platform_id; + } + + public function getType() + { + return $this->type; + } + + public function setType($type): void + { + $this->type = $type; + } + + public function getSn() + { + return $this->sn; + } + + public function setSn($sn): void + { + $this->sn = $sn; + } + + public function getAmount() + { + return $this->amount; + } + + public function setAmount($amount): void + { + $this->amount = $amount; + } + + public function getCurrencyCode() + { + return $this->currency_code; + } + + public function setCurrencyCode($currency_code): void + { + $this->currency_code = $currency_code; + } + + public function getStatus() + { + return $this->status; + } + + public function setStatus($status): void + { + $this->status = $status; + } + + + + +} + diff --git a/app/Bean/Queue/Wallet/QueueWalletBlockBean.php b/app/Bean/Queue/Wallet/QueueWalletBlockBean.php new file mode 100644 index 0000000..fec9583 --- /dev/null +++ b/app/Bean/Queue/Wallet/QueueWalletBlockBean.php @@ -0,0 +1,35 @@ +id; + } + + public function setId($id): void + { + $this->id = $id; + } + + public function getBlockNumber() + { + return $this->block_number; + } + + public function setBlockNumber($block_number): void + { + $this->block_number = $block_number; + } + + +} + diff --git a/app/Bean/Queue/Wallet/QueueWalletBlockTransactionBean.php b/app/Bean/Queue/Wallet/QueueWalletBlockTransactionBean.php new file mode 100644 index 0000000..87c4dec --- /dev/null +++ b/app/Bean/Queue/Wallet/QueueWalletBlockTransactionBean.php @@ -0,0 +1,25 @@ +data; + } + + public function setData(array $data): void + { + $this->data = $data; + } + + +} + diff --git a/app/Bean/Queue/Wallet/QueueWalletPlatformTransactionBean.php b/app/Bean/Queue/Wallet/QueueWalletPlatformTransactionBean.php new file mode 100644 index 0000000..0ba910e --- /dev/null +++ b/app/Bean/Queue/Wallet/QueueWalletPlatformTransactionBean.php @@ -0,0 +1,69 @@ +wallet_id; + } + + public function setWalletId($wallet_id): void + { + $this->wallet_id = $wallet_id; + } + + public function getWalletTransactionId() + { + return $this->wallet_transaction_id; + } + + public function setWalletTransactionId($wallet_transaction_id): void + { + $this->wallet_transaction_id = $wallet_transaction_id; + } + + public function getBlockTransactionId() + { + return $this->block_transaction_id; + } + + public function setBlockTransactionId($block_transaction_id): void + { + $this->block_transaction_id = $block_transaction_id; + } + + public function getAmount() + { + return $this->amount; + } + + public function setAmount($amount): void + { + $this->amount = $amount; + } + + public function getType() + { + return $this->type; + } + + public function setType($type): void + { + $this->type = $type; + } + + +} + diff --git a/app/Bean/Queue/Wallet/QueueWalletPlatformWithdrawTransferBean.php b/app/Bean/Queue/Wallet/QueueWalletPlatformWithdrawTransferBean.php new file mode 100644 index 0000000..62826b3 --- /dev/null +++ b/app/Bean/Queue/Wallet/QueueWalletPlatformWithdrawTransferBean.php @@ -0,0 +1,25 @@ +transaction_id; + } + + public function setTransactionId($transaction_id): void + { + $this->transaction_id = $transaction_id; + } + + + +} + diff --git a/app/Bean/Sdk/Wallet/Tron/AccountTransactionBean.php b/app/Bean/Sdk/Wallet/Tron/AccountTransactionBean.php new file mode 100644 index 0000000..bdaa1f4 --- /dev/null +++ b/app/Bean/Sdk/Wallet/Tron/AccountTransactionBean.php @@ -0,0 +1,88 @@ +transaction_id; + } + + public function setTransactionId($transaction_id): void + { + $this->transaction_id = $transaction_id; + } + + public function getTokenInfo(): AccountTransactionTokenInfoBean + { + return $this->token_info; + } + + public function setTokenInfo(AccountTransactionTokenInfoBean $token_info): void + { + $this->token_info = $token_info; + } + + public function getBlockTimestamp() + { + return $this->block_timestamp; + } + + public function setBlockTimestamp($block_timestamp): void + { + $this->block_timestamp = $block_timestamp; + } + + public function getFrom() + { + return $this->from; + } + + public function setFrom($from): void + { + $this->from = $from; + } + + public function getTo() + { + return $this->to; + } + + public function setTo($to): void + { + $this->to = $to; + } + + public function getType() + { + return $this->type; + } + + public function setType($type): void + { + $this->type = $type; + } + + public function getValue() + { + return $this->value; + } + + public function setValue($value): void + { + $this->value = $value; + } + + + +} diff --git a/app/Bean/Sdk/Wallet/Tron/AccountTransactionTokenInfoBean.php b/app/Bean/Sdk/Wallet/Tron/AccountTransactionTokenInfoBean.php new file mode 100644 index 0000000..a81149c --- /dev/null +++ b/app/Bean/Sdk/Wallet/Tron/AccountTransactionTokenInfoBean.php @@ -0,0 +1,55 @@ +symbol; + } + + public function setSymbol($symbol): void + { + $this->symbol = $symbol; + } + + public function getAddress() + { + return $this->address; + } + + public function setAddress($address): void + { + $this->address = $address; + } + + public function getDecimals() + { + return $this->decimals; + } + + public function setDecimals($decimals): void + { + $this->decimals = $decimals; + } + + public function getName() + { + return $this->name; + } + + public function setName($name): void + { + $this->name = $name; + } + + + +} diff --git a/app/Bean/Sdk/Wallet/Tron/BlockEventBean.php b/app/Bean/Sdk/Wallet/Tron/BlockEventBean.php new file mode 100644 index 0000000..7fc16d0 --- /dev/null +++ b/app/Bean/Sdk/Wallet/Tron/BlockEventBean.php @@ -0,0 +1,119 @@ +block_number; + } + + public function setBlockNumber($block_number): void + { + $this->block_number = $block_number; + } + + public function getBlockTimestamp() + { + return $this->block_timestamp; + } + + public function setBlockTimestamp($block_timestamp): void + { + $this->block_timestamp = $block_timestamp; + } + + public function getCallerContractAddress() + { + return $this->caller_contract_address; + } + + public function setCallerContractAddress($caller_contract_address): void + { + $this->caller_contract_address = $caller_contract_address; + } + + public function getContractAddress() + { + return $this->contract_address; + } + + public function setContractAddress($contract_address): void + { + $this->contract_address = $contract_address; + } + + public function getEvent() + { + return $this->event; + } + + public function setEvent($event): void + { + $this->event = $event; + } + + public function getEventIndex() + { + return $this->event_index; + } + + public function setEventIndex($event_index): void + { + $this->event_index = $event_index; + } + + public function getEventName() + { + return $this->event_name; + } + + public function setEventName($event_name): void + { + $this->event_name = $event_name; + } + + public function getResult() + { + return $this->result; + } + + public function setResult($result): void + { + $this->result = $result; + } + + public function getResultType() + { + return $this->result_type; + } + + public function setResultType($result_type): void + { + $this->result_type = $result_type; + } + + public function getTransactionId() + { + return $this->transaction_id; + } + + public function setTransactionId($transaction_id): void + { + $this->transaction_id = $transaction_id; + } +} + diff --git a/app/Bean/Sdk/Wallet/Tron/BlockEventResultBean.php b/app/Bean/Sdk/Wallet/Tron/BlockEventResultBean.php new file mode 100644 index 0000000..7483c55 --- /dev/null +++ b/app/Bean/Sdk/Wallet/Tron/BlockEventResultBean.php @@ -0,0 +1,44 @@ +from; + } + + public function setFrom($from): void + { + $this->from = $from; + } + + public function getTo() + { + return $this->to; + } + + public function setTo($to): void + { + $this->to = $to; + } + + public function getValue() + { + return $this->value; + } + + public function setValue($value): void + { + $this->value = $value; + } + + + +} diff --git a/app/Bean/Sdk/Wallet/Tron/EventBean.php b/app/Bean/Sdk/Wallet/Tron/EventBean.php new file mode 100644 index 0000000..68f0380 --- /dev/null +++ b/app/Bean/Sdk/Wallet/Tron/EventBean.php @@ -0,0 +1,120 @@ +block_number; + } + + public function setBlockNumber($block_number): void + { + $this->block_number = $block_number; + } + + public function getBlockTimestamp() + { + return $this->block_timestamp; + } + + public function setBlockTimestamp($block_timestamp): void + { + $this->block_timestamp = $block_timestamp; + } + + public function getCallerContractAddress() + { + return $this->caller_contract_address; + } + + public function setCallerContractAddress($caller_contract_address): void + { + $this->caller_contract_address = $caller_contract_address; + } + + public function getContractAddress() + { + return $this->contract_address; + } + + public function setContractAddress($contract_address): void + { + $this->contract_address = $contract_address; + } + + public function getEvent() + { + return $this->event; + } + + public function setEvent($event): void + { + $this->event = $event; + } + + public function getEventIndex() + { + return $this->event_index; + } + + public function setEventIndex($event_index): void + { + $this->event_index = $event_index; + } + + public function getEventName() + { + return $this->event_name; + } + + public function setEventName($event_name): void + { + $this->event_name = $event_name; + } + + public function getResult(): EventResultBean + { + return $this->result; + } + + public function setResult(EventResultBean $result): void + { + $this->result = $result; + } + + public function getResultType(): EventResultTypeBean + { + return $this->result_type; + } + + public function setResultType(EventResultTypeBean $result_type): void + { + $this->result_type = $result_type; + } + + public function getTransactionId() + { + return $this->transaction_id; + } + + public function setTransactionId($transaction_id): void + { + $this->transaction_id = $transaction_id; + } + + +} diff --git a/app/Bean/Sdk/Wallet/Tron/EventResultBean.php b/app/Bean/Sdk/Wallet/Tron/EventResultBean.php new file mode 100644 index 0000000..79b15df --- /dev/null +++ b/app/Bean/Sdk/Wallet/Tron/EventResultBean.php @@ -0,0 +1,43 @@ +from; + } + + public function setFrom($from): void + { + $this->from = $from; + } + + public function getTo() + { + return $this->to; + } + + public function setTo($to): void + { + $this->to = $to; + } + + public function getValue() + { + return $this->value; + } + + public function setValue($value): void + { + $this->value = $value; + } + + +} diff --git a/app/Bean/Sdk/Wallet/Tron/EventResultTypeBean.php b/app/Bean/Sdk/Wallet/Tron/EventResultTypeBean.php new file mode 100644 index 0000000..35bcf75 --- /dev/null +++ b/app/Bean/Sdk/Wallet/Tron/EventResultTypeBean.php @@ -0,0 +1,43 @@ +from; + } + + public function setFrom($from): void + { + $this->from = $from; + } + + public function getTo() + { + return $this->to; + } + + public function setTo($to): void + { + $this->to = $to; + } + + public function getValue() + { + return $this->value; + } + + public function setValue($value): void + { + $this->value = $value; + } + + +} diff --git a/app/Bean/Sdk/Wallet/Tron/MetaBean.php b/app/Bean/Sdk/Wallet/Tron/MetaBean.php new file mode 100644 index 0000000..c36a29b --- /dev/null +++ b/app/Bean/Sdk/Wallet/Tron/MetaBean.php @@ -0,0 +1,55 @@ +at; + } + + public function setAt($at): void + { + $this->at = $at; + } + + public function getFingerprint() + { + return $this->fingerprint; + } + + public function setFingerprint($fingerprint): void + { + $this->fingerprint = $fingerprint; + } + + public function getLinks(): MetaLinksBean + { + return $this->links; + } + + public function setLinks(MetaLinksBean $links): void + { + $this->links = $links; + } + + public function getPageSize() + { + return $this->page_size; + } + + public function setPageSize($page_size): void + { + $this->page_size = $page_size; + } + + + +} diff --git a/app/Bean/Sdk/Wallet/Tron/MetaLinksBean.php b/app/Bean/Sdk/Wallet/Tron/MetaLinksBean.php new file mode 100644 index 0000000..783076d --- /dev/null +++ b/app/Bean/Sdk/Wallet/Tron/MetaLinksBean.php @@ -0,0 +1,10 @@ +block_number; + } + + public function setBlockNumber($block_number): void + { + $this->block_number = $block_number; + } + + public function getBlockTimestamp() + { + return $this->block_timestamp; + } + + public function setBlockTimestamp($block_timestamp): void + { + $this->block_timestamp = $block_timestamp; + } + + + + +} diff --git a/app/Bean/Sdk/Wallet/Tron/ResponseBean.php b/app/Bean/Sdk/Wallet/Tron/ResponseBean.php new file mode 100644 index 0000000..f643b96 --- /dev/null +++ b/app/Bean/Sdk/Wallet/Tron/ResponseBean.php @@ -0,0 +1,43 @@ +data; + } + + public function setData($data): void + { + $this->data = $data; + } + + public function getSuccess(): bool + { + return $this->success; + } + + public function setSuccess($success): void + { + $this->success = $success; + } + + public function getMeta(): MetaBean + { + return $this->meta; + } + + public function setMeta($meta): void + { + $this->meta = $meta; + } + + +} diff --git a/app/Bean/Sdk/Wallet/Tron/TokenAddressBean.php b/app/Bean/Sdk/Wallet/Tron/TokenAddressBean.php new file mode 100644 index 0000000..e547312 --- /dev/null +++ b/app/Bean/Sdk/Wallet/Tron/TokenAddressBean.php @@ -0,0 +1,55 @@ +private_key; + } + + public function setPrivateKey($private_key): void + { + $this->private_key = $private_key; + } + + public function getPublicKey() + { + return $this->public_key; + } + + public function setPublicKey($public_key): void + { + $this->public_key = $public_key; + } + + public function getAddressHex() + { + return $this->address_hex; + } + + public function setAddressHex($address_hex): void + { + $this->address_hex = $address_hex; + } + + public function getAddressBase58() + { + return $this->address_base58; + } + + public function setAddressBase58($address_base58): void + { + $this->address_base58 = $address_base58; + } + + + +} diff --git a/app/Bean/Sdk/Wallet/Tron/TransferTransactionBean.php b/app/Bean/Sdk/Wallet/Tron/TransferTransactionBean.php new file mode 100644 index 0000000..75269d4 --- /dev/null +++ b/app/Bean/Sdk/Wallet/Tron/TransferTransactionBean.php @@ -0,0 +1,33 @@ +txID; + } + + public function setTxID($txID): void + { + $this->txID = $txID; + } + + public function getRawData() + { + return $this->raw_data; + } + + public function setRawData($raw_data): void + { + $this->raw_data = $raw_data; + } + + + +} diff --git a/app/Cache/Base/BaseCache.php b/app/Cache/Base/BaseCache.php index d384b3f..791a5b7 100644 --- a/app/Cache/Base/BaseCache.php +++ b/app/Cache/Base/BaseCache.php @@ -30,12 +30,17 @@ abstract class BaseCache $sCacheKey = $this->getPrimaryKey(); $aData = $this->loadData(); if (empty($aData)) return false; - return Cache::put($sCacheKey, serialize($aData), self::CACHE_TTL); + return Cache::put($sCacheKey, $aData, self::CACHE_TTL); } - abstract function loadData(): array|null; + abstract function loadData(): array|string|null; - function getCacheData($primary_key = null): array|null + function get($key): array|string|null + { + return $this->getCacheData($key); + } + + function getCacheData($primary_key = null): array|string|null { if ($primary_key === null) $primary_key = $this->primary_key; if (empty($primary_key)) return []; @@ -43,10 +48,10 @@ abstract class BaseCache $sData = Cache::get($sCacheKey); if (empty($sData)) { $this->primary_key = $primary_key; - if($this->loadToCache()) $sData = Cache::get($sCacheKey); + if ($this->loadToCache()) $sData = Cache::get($sCacheKey); } if (empty($sData)) return null; - return unserialize($sData); + return $sData; } //根据primary_key获取缓存数据单个值,不指定key就默认获取所有 @@ -55,7 +60,7 @@ abstract class BaseCache if ($primary_key === null) $primary_key = $this->primary_key; if (empty($primary_key)) return false; $aData = $this->getCacheData($primary_key); - if(empty($aData)) return null; + if (empty($aData)) return null; if (empty($key)) return $aData; return $aData[$key] ?? ''; } @@ -68,4 +73,10 @@ abstract class BaseCache return Cache::forget($sCacheKey); } + function clearAll(): bool + { + if (empty($this->primary_prefix)) return false; + return Cache::forget($this->primary_prefix); + } + } diff --git a/app/Cache/Base/KeyBaseCache.php b/app/Cache/Base/KeyBaseCache.php new file mode 100644 index 0000000..aa420d8 --- /dev/null +++ b/app/Cache/Base/KeyBaseCache.php @@ -0,0 +1,42 @@ +getKey($key), $value); + } + + function setKeyWithExp($key, $value, $exp = self::CACHE_TTL): bool + { + return Cache::put($this->getKey($key), $value, $exp); + } + + function getPrefix(): string + { + return $this->prefix; + } + + function getKey($key): string + { + return $this->getPrefix().$key; + } + + function removeKey($key): bool + { + return Cache::forget($this->getKey($key)); + } + +} diff --git a/app/Cache/Base/SetBaseCache.php b/app/Cache/Base/SetBaseCache.php new file mode 100644 index 0000000..46e63c0 --- /dev/null +++ b/app/Cache/Base/SetBaseCache.php @@ -0,0 +1,59 @@ +client) $this->client = Redis::client(); + return $this->client ; + } + + function getAll(): bool + { + return $this->getRedis()->sMembers($this->getSetName()); + } + + function checkKey($value): bool + { + return $this->getRedis()->sIsMember($this->getSetName(),$value); + } + + function setKey($value): bool + { + return $this->getRedis()->sAdd($this->getSetName(),$value); + } + + function removeKey($value): bool + { + return $this->getRedis()->sRem($this->getSetName(),$value); + } + + function getCount() + { + return $this->getRedis()->sCard($this->getSetName()); + } + + function getPrefix(): string + { + return $this->prefix; + } + + function getSetName(): string + { + return $this->getPrefix().$this->set_name; + } + + +} diff --git a/app/Cache/Base/TableBaseCache.php b/app/Cache/Base/TableBaseCache.php index b2d4c55..c638dcd 100644 --- a/app/Cache/Base/TableBaseCache.php +++ b/app/Cache/Base/TableBaseCache.php @@ -10,12 +10,12 @@ abstract class TableBaseCache extends BaseCache public array $get_columns = ['*']; public array $get_exclude_columns = []; - function loadTable(): array|null + function loadTable(): array|string|null { return null; } - function loadData(): array|null + function loadData(): array|string|null { //默认获取表数据方式 if (!empty($table_class)) { @@ -23,7 +23,7 @@ abstract class TableBaseCache extends BaseCache //排除不需要的字段 if (!empty($this->get_exclude_columns) && $this->get_columns != ['*']) $this->get_columns = array_diff($this->get_columns, $this->get_exclude_columns); $oData = $oTable->findItemByWhere([$this->primary_key_column => $this->primary_key], $this->get_columns); - if($oData->isEmpty()) return null; + if ($oData->isEmpty()) return null; $aData = $oData->toArray(); //排除不需要的字段 if (!empty($this->get_exclude_columns) && $this->get_columns == ['*'] && !empty($aData)) { diff --git a/app/Cache/Key/TronKeyCache.php b/app/Cache/Key/TronKeyCache.php new file mode 100644 index 0000000..2533026 --- /dev/null +++ b/app/Cache/Key/TronKeyCache.php @@ -0,0 +1,23 @@ +setKey(self::NOW_BLOCK, $block); + } + + function getNowBlock(): bool|array|string|null + { + return $this->getByKey(self::NOW_BLOCK); + } + +} diff --git a/app/Cache/Set/TronWalletAddressSetCache.php b/app/Cache/Set/TronWalletAddressSetCache.php new file mode 100644 index 0000000..db91f20 --- /dev/null +++ b/app/Cache/Set/TronWalletAddressSetCache.php @@ -0,0 +1,11 @@ +table_class(); + $oData = $oTable->findItemByWhere([$this->primary_key_column => $this->primary_key], $this->get_columns); + if ($oData->isEmpty()) return null; + $aData = $oData->toArray(); + + if (empty($aData)) return null; + return $aData['value']; + } + + function getWithdrawFeeAmount(): string|null + { + $res = $this->get(self::NAME_WITHDRAW_FEE_AMOUNT); + if (empty($res)) $res = 0; + return $res; + } + + +} diff --git a/app/Cache/Table/TableCustomerUserCache.php b/app/Cache/Table/Api/TableCustomerUserCache.php similarity index 94% rename from app/Cache/Table/TableCustomerUserCache.php rename to app/Cache/Table/Api/TableCustomerUserCache.php index 09534c0..36d5790 100644 --- a/app/Cache/Table/TableCustomerUserCache.php +++ b/app/Cache/Table/Api/TableCustomerUserCache.php @@ -1,5 +1,6 @@ table_class(); + $oData = $oTable->findItemByWhere([$this->primary_key_column => $this->primary_key], $this->get_columns); + if ($oData->isEmpty()) return null; + $aData = $oData->toArray(); + + if (empty($aData)) return null; + return $aData['value']; + } + + function getWithdrawFeeAmount(): string|null + { + $res = $this->get(self::NAME_WITHDRAW_FEE_AMOUNT); + if (empty($res)) $res = 0; + return $res; + } + + +} diff --git a/app/Const/Prefix.php b/app/Const/Prefix.php index 0ea779c..d4bc786 100644 --- a/app/Const/Prefix.php +++ b/app/Const/Prefix.php @@ -3,6 +3,6 @@ namespace App\Const; class Prefix{ - const ORDER_SN_PREFIX = 'OD_'; + const ORDER_SN_PREFIX = 'SN_'; } diff --git a/app/Exceptions/QueueException.php b/app/Exceptions/QueueException.php new file mode 100644 index 0000000..4613b35 --- /dev/null +++ b/app/Exceptions/QueueException.php @@ -0,0 +1,7 @@ +walletAddressTransactionConsumer($oQueueEventBean); + } catch (\Exception $e) { + } + } + + public static function putToQueue(QueueEventBean $bean,$delaySec = null): \Illuminate\Foundation\Bus\PendingDispatch + { + $queue = self::dispatch($bean->toArrayNotNull())->onQueue(QueueEventBean::QUEUE_NAME); + if(!empty($delaySec)){ + $queue->delay(now()->addSeconds($delaySec)); + } + return $queue; + } +} diff --git a/app/Jobs/Wallet/WalletBlockQueue.php b/app/Jobs/Wallet/WalletBlockQueue.php new file mode 100644 index 0000000..7bfadab --- /dev/null +++ b/app/Jobs/Wallet/WalletBlockQueue.php @@ -0,0 +1,46 @@ +tronBlockConsumer($oQueueWalletBlockBean); + } catch (\Exception $e) { + } + } + + public static function putToQueue(QueueWalletBlockBean $bean,$delaySec = null): \Illuminate\Foundation\Bus\PendingDispatch + { + $queue = self::dispatch($bean->toArrayNotNull())->onQueue(QueueWalletBlockBean::QUEUE_NAME); + if(!empty($delaySec)){ + $queue->delay(now()->addSeconds($delaySec)); + } + return $queue; + } +} diff --git a/app/Jobs/Wallet/WalletBlockTransactionQueue.php b/app/Jobs/Wallet/WalletBlockTransactionQueue.php new file mode 100644 index 0000000..409d0b8 --- /dev/null +++ b/app/Jobs/Wallet/WalletBlockTransactionQueue.php @@ -0,0 +1,43 @@ +tronBlockTransactionConsumer($oQueueWalletBlockTransactionBean); + } catch (\Exception $e) { + } + } + + public static function putToQueue(QueueWalletBlockTransactionBean $bean): \Illuminate\Foundation\Bus\PendingDispatch + { + return self::dispatch($bean->toArrayNotNull())->onQueue(QueueWalletBlockTransactionBean::QUEUE_NAME); + } +} diff --git a/app/Jobs/Wallet/WalletNotifyToPlatformQueue.php b/app/Jobs/Wallet/WalletNotifyToPlatformQueue.php new file mode 100644 index 0000000..d142934 --- /dev/null +++ b/app/Jobs/Wallet/WalletNotifyToPlatformQueue.php @@ -0,0 +1,36 @@ +toArrayNotNull())->onQueue(QueueNotifyToPlatformBean::QUEUE_NAME); + } +} diff --git a/app/Jobs/Wallet/WalletPlatformTransactionQueue.php b/app/Jobs/Wallet/WalletPlatformTransactionQueue.php new file mode 100644 index 0000000..3fa67a2 --- /dev/null +++ b/app/Jobs/Wallet/WalletPlatformTransactionQueue.php @@ -0,0 +1,55 @@ +getType(); + //提现 + if ($type == WalletAddressTransactionModel::TYPE_WITHDRAW) { + $oWithdrawService->walletPlatformTransactionConsumer($bean); + } + //充值 + if ($type == WalletAddressTransactionModel::TYPE_RECHARGE) { + $oRechargeSService->walletPlatformTransactionConsumer($bean); + } + } catch (\Exception $e) { + + } + } + + public static function putToQueue(QueueWalletPlatformTransactionBean $bean): \Illuminate\Foundation\Bus\PendingDispatch + { + return self::dispatch($bean->toArrayNotNull())->onQueue(QueueWalletPlatformTransactionBean::QUEUE_NAME); + } +} diff --git a/app/Jobs/Wallet/WalletPlatformWithdrawTransferQueue.php b/app/Jobs/Wallet/WalletPlatformWithdrawTransferQueue.php new file mode 100644 index 0000000..da8d601 --- /dev/null +++ b/app/Jobs/Wallet/WalletPlatformWithdrawTransferQueue.php @@ -0,0 +1,47 @@ +withdrawTransferConsumer($bean); + } catch (\Exception $e) { + } + } + + public static function putToQueue(QueueWalletPlatformWithdrawTransferBean $bean, $delaySec = null): \Illuminate\Foundation\Bus\PendingDispatch + { + $queue = self::dispatch($bean->toArrayNotNull())->onQueue(QueueWalletPlatformWithdrawTransferBean::QUEUE_NAME); + if(!empty($delaySec)){ + $queue->delay(now()->addSeconds($delaySec)); + } + return $queue; + } +} diff --git a/app/Jobs/WalletAddrTransactionChangeQueue.php b/app/Jobs/WalletAddrTransactionChangeQueue.php deleted file mode 100644 index e061c59..0000000 --- a/app/Jobs/WalletAddrTransactionChangeQueue.php +++ /dev/null @@ -1,39 +0,0 @@ -walletAddrTransactionChangeConsumer($wallet_addr_transaction_id, $wallet_addr_transaction_type); - } -} diff --git a/app/Jobs/WalletPlatformUserWithdrawQueue.php b/app/Jobs/WalletPlatformUserWithdrawQueue.php deleted file mode 100644 index ab7e006..0000000 --- a/app/Jobs/WalletPlatformUserWithdrawQueue.php +++ /dev/null @@ -1,35 +0,0 @@ -withdrawConsumer($id); - - } -} diff --git a/app/Models/Api/Customer/CustomerUserExtendModel.php b/app/Models/Api/Customer/CustomerUserExtendModel.php index b6bc898..63c5548 100644 --- a/app/Models/Api/Customer/CustomerUserExtendModel.php +++ b/app/Models/Api/Customer/CustomerUserExtendModel.php @@ -3,10 +3,10 @@ namespace App\Models\Api\Customer; use App\Exceptions\ModelException; -use App\Jobs\UserActiveStatusQueue; +use App\Jobs\Api\UserActiveStatusQueue; +use App\Models\Api\Base\ApiBaseModel; use App\Models\Api\Post\PostPushBoxModel; use App\Models\Api\WebSocket\CustomerWsHistoryModel; -use App\Models\Api\Base\ApiBaseModel; use App\Structs\QueueUserActiveStatusStruct; use Carbon\Carbon; use Illuminate\Support\Facades\DB; diff --git a/app/Models/Api/Customer/CustomerUserModel.php b/app/Models/Api/Customer/CustomerUserModel.php index 3f55394..e82f4fe 100644 --- a/app/Models/Api/Customer/CustomerUserModel.php +++ b/app/Models/Api/Customer/CustomerUserModel.php @@ -2,7 +2,7 @@ namespace App\Models\Api\Customer; -use App\Cache\Table\TableCustomerUserCache; +use App\Cache\Table\Api\TableCustomerUserCache; use App\Models\Api\Base\ApiBaseModel; use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Support\Carbon; diff --git a/app/Models/Api/Other/CustomerSettingModel.php b/app/Models/Api/Other/CustomerSettingModel.php new file mode 100644 index 0000000..4f6579e --- /dev/null +++ b/app/Models/Api/Other/CustomerSettingModel.php @@ -0,0 +1,20 @@ +setStatus(self::STATUS_PROCESSING); try { DB::beginTransaction(); + //获取提现手续费 + $oTableCustomerSettingCache = new TableCustomerSettingCache(); + $withdraw_fee = $oTableCustomerSettingCache->getWithdrawFeeAmount(); //查询用户余额 $oCustomerWalletBalanceModel = new CustomerWalletBalanceModel(); $resWalletBalanceModel = $oCustomerWalletBalanceModel->findByUidCurrencyCode($bean->getUid(), $bean->getCurrencyCode()); if (!$resWalletBalanceModel) throw new ModelException('wallet not found'); + //检查余额是否足够 + if (Math::bcComp(Math::bcSub($resWalletBalanceModel->available_amount, $withdraw_fee), abs($bean->getAmount())) == -1) throw new ModelException('balance not enough'); + + $bean->setFeeAmount($withdraw_fee); $bean->setWalletId($resWalletBalanceModel->id); $bean->setBeforeTotalAmount($resWalletBalanceModel->total_amount); $bean->setAfterTotalAmount($resWalletBalanceModel->total_amount); //新增账变 $res = $this->addTransaction($bean); if (!$res) throw new ModelException('addTransaction fail'); + //先扣除手续费 + $res = $this->typeTransactionFeeSub($uid, $currency_code, $withdraw_fee, $res->id . ' withdraw fee'); + if (!$res) throw new ModelException('withdraw fee fail'); //变更余额 - $oCustomerWalletBalanceModel = new CustomerWalletBalanceModel(); //先冻结,等回调成功再扣减 $res = $oCustomerWalletBalanceModel->frozenAmount($bean->getWalletId(), $bean->getAmount()); if (!$res) throw new ModelException('withdraw fail'); DB::commit(); Logs::SuccLog(__FUNCTION__, func_get_args()); + //@@发送到提现通知钱包队列 + return true; } catch (\Exception $e) { DB::rollBack(); @@ -760,6 +773,9 @@ class CustomerWalletBalanceTransactionModel extends ApiBaseModel if (!empty($remark)) $updateItem['remark'] = $remark; $res = $this->updateItem($updateItem); if (!$res) throw new ModelException('updateItem fail'); + //返还手续费 + $res = $this->typeTransactionFeeAdd($resModel->uid, $resModel->currency_code, $resModel->fee_amount, $resModel->id . ' withdraw fail return fee'); + if (!$res) throw new ModelException('withdraw fail return fee fail'); } DB::commit(); Logs::SuccLog(__FUNCTION__, func_get_args()); @@ -803,13 +819,13 @@ class CustomerWalletBalanceTransactionModel extends ApiBaseModel return true; } catch (\Exception $e) { DB::rollBack(); - Logs::ErrLog('typeRecharge error rollBack', $e); + Logs::ErrLog(__FUNCTION__.'typeRecharge error rollBack', $e); return false; } } - function addTransaction(CustomerWalletBalanceTransactionBean &$bean) + function addTransaction(CustomerWalletBalanceTransactionBean &$bean): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|bool { if (!$bean->getWalletId()) throw new ModelException('wallet_id is required'); if (!$bean->getType()) throw new ModelException('type is required'); diff --git a/app/Models/Wallet/Wallet/WalletSettingModel.php b/app/Models/Wallet/Other/WalletSettingModel.php similarity index 85% rename from app/Models/Wallet/Wallet/WalletSettingModel.php rename to app/Models/Wallet/Other/WalletSettingModel.php index 62b1750..ad6338d 100644 --- a/app/Models/Wallet/Wallet/WalletSettingModel.php +++ b/app/Models/Wallet/Other/WalletSettingModel.php @@ -1,5 +1,6 @@ newQuery()->where('id', $id)->first(['total_amount', 'available_amount']); - if (!$oModel) throw new ModelException('找不到id'); - $oModel->frozen_amount = Db::raw('total_amount + ' . $amount); - $oModel->available_amount = Db::raw('available_amount + ' . $amount); - return $oModel->save(); + $updateItem = [ + 'id' => $id, + 'frozen_amount' => DB::raw('frozen_amount + '. $amount), + 'available_amount' => DB::raw('available_amount - '. $amount), + ]; + return $this->updateItem($updateItem); } - //扣除平台余额 - function decAvailableBalance($id, $amount): bool + function unFrozenAmount($id,$amount): bool|int { $amount = abs($amount); - $oModel = $this->newQuery()->where('id', $id)->first(['total_amount', 'available_amount']); - if (!$oModel) throw new ModelException('找不到id'); - $oModel->frozen_amount = Db::raw('total_amount - ' . $amount); - $oModel->available_amount = Db::raw('available_amount - ' . $amount); - return $oModel->save(); + $updateItem = [ + 'id' => $id, + 'frozen_amount' => DB::raw('frozen_amount - '. $amount), + 'available_amount' => DB::raw('available_amount + '. $amount), + ]; + return $this->updateItem($updateItem); } - function decFrozenAmountById($id, $amount): int + function subFrozenAmount($id, $amount): bool|int { $amount = abs($amount); - $oModel = $this->newQuery()->where('id', $id)->first(['total_amount', 'frozen_amount']); - if (!$oModel) throw new ModelException('找不到id'); - $oModel->frozen_amount = Db::raw('frozen_amount - ' . $amount); - $oModel->total_amount = Db::raw('total_amount - ' . $amount); - return $oModel->save(); + $updateItem = [ + 'id' => $id, + 'total_amount' => DB::raw('total_amount - '. $amount), + 'frozen_amount' => DB::raw('frozen_amount - '. $amount), + ]; + return $this->updateItem($updateItem); } - function unFrozenAmountById($id, $amount): int + function addFrozenAmount($id, $amount): bool|int { $amount = abs($amount); - $oModel = $this->newQuery()->where('id', $id)->first(['frozen_amount', 'available_amount']); - if (!$oModel) throw new ModelException('找不到id'); - $oModel->frozen_amount = Db::raw('frozen_amount - ' . $amount); - $oModel->available_amount = Db::raw('available_amount + ' . $amount); - return $oModel->save(); + $updateItem = [ + 'id' => $id, + 'total_amount' => DB::raw('total_amount + '. $amount), + 'frozen_amount' => DB::raw('frozen_amount + '. $amount), + ]; + return $this->updateItem($updateItem); } - function frozenAmountById($id, $amount): int + function subAvailableAmount($id, $amount): bool|int { $amount = abs($amount); - $oModel = $this->newQuery()->where('id', $id)->first(['frozen_amount', 'available_amount']); - if (!$oModel) throw new ModelException('找不到id'); - $oModel->frozen_amount = Db::raw('frozen_amount + ' . $amount); - $oModel->available_amount = Db::raw('available_amount - ' . $amount); - return $oModel->save(); + $updateItem = [ + 'id' => $id, + 'total_amount' => DB::raw('total_amount - '. $amount), + 'available_amount' => DB::raw('available_amount - '. $amount), + ]; + return $this->updateItem($updateItem); + } + + function addAvailableAmount($id, $amount): bool|int + { + $amount = abs($amount); + $updateItem = [ + 'id' => $id, + 'total_amount' => DB::raw('total_amount + '. $amount), + 'available_amount' => DB::raw('available_amount + '. $amount), + ]; + return $this->updateItem($updateItem); } diff --git a/app/Models/Wallet/Platform/WalletPlatformBalanceTransactionModel.php b/app/Models/Wallet/Platform/WalletPlatformBalanceTransactionModel.php index a6354e7..3ddd0d1 100644 --- a/app/Models/Wallet/Platform/WalletPlatformBalanceTransactionModel.php +++ b/app/Models/Wallet/Platform/WalletPlatformBalanceTransactionModel.php @@ -2,255 +2,453 @@ namespace App\Models\Wallet\Platform; + +use App\Bean\Model\Wallet\Platform\WalletPlatformBalanceTransactionBean; +use App\Bean\Queue\Wallet\QueueNotifyToPlatformBean; +use App\Bean\Queue\Wallet\QueueWalletPlatformWithdrawTransferBean; +use App\Cache\Table\Wallet\TableWalletSettingCache; use App\Exceptions\ModelException; +use App\Jobs\Wallet\WalletNotifyToPlatformQueue; +use App\Jobs\Wallet\WalletPlatformWithdrawTransferQueue; use App\Models\Wallet\Base\WalletBaseModel; -use App\Models\Wallet\Wallet\WalletCurrencyModel; +use App\Models\Wallet\Wallet\WalletAddressModel; +use App\Tools\Logs; use App\Tools\Math; use App\Tools\Times; use App\Tools\Tools; use Illuminate\Support\Facades\DB; -use Illuminate\Support\Facades\Log; -use Symfony\Contracts\Service; class WalletPlatformBalanceTransactionModel extends WalletBaseModel { - protected $table = 'wallet_platform_balance_transaction'; + protected $table = 'wallet_address_transaction'; protected $primaryKey = 'id'; protected $fillable = [ 'id', + 'sn', 'type', 'status', 'platform_id', - 'currency_id', 'currency_code', - 'currency_type', - 'from_wallet_addr_id', - 'from_user_transaction_id', - 'from_uid', - 'wallet_addr', - 'from_wallet_transaction_id', - 'received_amount', - 'entered_amount', + 'balance_id', + 'block_transaction_id', + 'bind_wallet_address_id', + 'bind_wallet_address', + 'from_wallet_address_id', + 'from_wallet_address', + 'to_wallet_address_id', + 'to_wallet_address', + 'uid', + 'amount', 'fee_amount', 'before_total_amount', 'after_total_amount', - 'desc_key', - 'desc', 'remark', - 'sign', + 'source_wallet_id', + 'callback_time', + 'callback_wallet_address_transaction_id', + 'is_notify', 'created_at', 'updated_at', ]; - const TYPE_USER_RECHARGE = 1; - const TYPE_USER_WITHDRAW = 2; - const TYPE_ADMIN_ADD = 3; - const TYPE_ADMIN_DEC = 4; + const TYPE_RECHARGE_ADD = 1; + const TYPE_WITHDRAW_DEC = 2; + + const TYPE_TRANSACTION_FEE_SUB = 10; + const TYPE_TRANSACTION_FEE_ADD = 11; + const TYPE_ADMIN_ADD = 12; + const TYPE_ADMIN_SUB = 13; const TYPE = [ - self::TYPE_USER_RECHARGE => '用户充值', - self::TYPE_USER_WITHDRAW => '用户提现', - self::TYPE_ADMIN_ADD => '管理员加', - self::TYPE_ADMIN_DEC => '管理员减', + self::TYPE_RECHARGE_ADD => '充值', + self::TYPE_WITHDRAW_DEC => '提现', + self::TYPE_TRANSACTION_FEE_SUB => '交易手续费扣款', + self::TYPE_TRANSACTION_FEE_ADD => '交易手续费加款', + self::TYPE_ADMIN_ADD => '管理员加款', + self::TYPE_ADMIN_SUB => '管理员扣款', ]; - const STATUS_WAITING_QUEUE = 1; - const STATUS_CHAIN_WAITING_CALLBACK = 2; + const STATUS_WAIT = 1; + const STATUS_PROCESSING = 2; const STATUS_SUCCESS = 3; const STATUS_FAIL = 4; const STATUS = [ - self::STATUS_WAITING_QUEUE => '等待队列', - self::STATUS_CHAIN_WAITING_CALLBACK => '链上等待回调', + self::STATUS_WAIT => '等待处理', + self::STATUS_PROCESSING => '处理中', self::STATUS_SUCCESS => '成功', self::STATUS_FAIL => '失败', ]; - function addPlatformTransaction( - $type, - $status, - $received_amount, - $entered_amount, - $platform_id, - $currency_code, - $from_uid = '', - $from_user_transaction_id = '', - $from_wallet_addr_id = '', - $wallet_addr = '', - $desc_key = '', - $desc = '', - $remark = '', - ): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|bool - { - $received_amount = abs($received_amount); - $entered_amount = abs($entered_amount); - $oWalletPlatformBalanceModel = new WalletPlatformBalanceModel(); - $oWalletCurrencyModel = new WalletCurrencyModel(); - $resWalletPlatformBalanceModel = $oWalletPlatformBalanceModel->findPlatformBalance($platform_id, $currency_code); - if (!$resWalletPlatformBalanceModel) throw new ModelException('platform balance not found'); - $resWalletCurrencyModel = $oWalletCurrencyModel->findByCode($currency_code); - if (!$resWalletCurrencyModel) throw new ModelException('currency_code error'); - - if (in_array($type, [self::TYPE_ADMIN_DEC, self::TYPE_USER_WITHDRAW])) { - if (Math::bcComp($resWalletPlatformBalanceModel->available_amount, $received_amount) == -1) throw new ModelException('platform balance not enough'); - } - //提现费率计算 - $fee_amount = 0; - if ($type == self::TYPE_USER_WITHDRAW) { - $fee_amount = $oWalletCurrencyModel->computeTransferRate($received_amount, $oWalletCurrencyModel->transfer_rate); - $entered_amount = Math::bcSub($received_amount, $fee_amount); - } - - if($type == self::TYPE_USER_RECHARGE){ - $fee_amount = Math::bcSub($received_amount, $entered_amount); - } - - $insert = [ - 'type' => $type, - 'status' => $status, - 'platform_id' => $platform_id, - 'currency_id' => $resWalletPlatformBalanceModel->currency_id, - 'currency_code' => $resWalletPlatformBalanceModel->currency_code, - 'currency_type' => $resWalletPlatformBalanceModel->currency_type, - 'from_wallet_addr_id' => $from_wallet_addr_id, - 'from_user_transaction_id' => $from_user_transaction_id, - 'from_uid' => $from_uid, - 'wallet_addr' => $wallet_addr, - 'received_amount' => $received_amount, - 'entered_amount' => $entered_amount, - 'fee_amount' => $fee_amount, - 'before_total_amount' => $resWalletPlatformBalanceModel->total_amount, - 'after_total_amount' => Math::bcAdd($resWalletPlatformBalanceModel->total_amount, $entered_amount), - 'desc_key' => $desc_key, - 'desc' => $desc, - 'remark' => $remark, - ]; -// $insert['sign'] = ''; - $insert['created_at'] = Times::getNowDateTime(); - $insert['updated_at'] = Times::getNowDateTime(); - return $this->addItem($insert); - } - - //增加提现账变并且冻结平台金额 - function newWithdrawPlatformTransaction( - $amount, - $platform_id, - $currency_code, - $uid, - ): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|bool + const IS_NOTIFY_WAIT = 1; + const IS_NOTIFY_PROCESS = 2; + const IS_NOTIFY_FINISH = 3; + const IS_NOTIFY_FAIL = 4; + const IS_NOTIFY = [ + self::IS_NOTIFY_WAIT => '待处理', + self::IS_NOTIFY_PROCESS => '处理中', + self::IS_NOTIFY_FINISH => '处理完成', + self::IS_NOTIFY_FAIL => '处理失败', + ]; + + //管理员扣款 + function typeAdminSub($platform_id, $uid, $currency_code, $amount, $remark = null): bool { + $bean = new WalletPlatformBalanceTransactionBean(); + $bean->setPlatformId($platform_id); + $bean->setUid($uid); + $bean->setCurrencyCode($currency_code); + $bean->setAmount(-abs($amount)); //负数 + $bean->setType(self::TYPE_ADMIN_SUB); + $bean->setStatus(self::STATUS_SUCCESS); + $bean->setRemark($remark); try { - Db::beginTransaction(); - $resModel = $this->addPlatformTransaction(self::TYPE_USER_WITHDRAW, self::STATUS_WAITING_QUEUE, $amount,$amount, $platform_id, $currency_code,$uid); - if(!$resModel) throw new ModelException('addPlatformTransaction error'); + DB::beginTransaction(); + //查询平台余额 $oWalletPlatformBalanceModel = new WalletPlatformBalanceModel(); - $res = $oWalletPlatformBalanceModel->findPlatformBalance($platform_id,$currency_code); - if (!$res) throw new ModelException('findPlatformBalance error'); - $res = $oWalletPlatformBalanceModel->frozenAmountById($oWalletPlatformBalanceModel->id, $amount); //变更平台余额 - if (!$res) throw new ModelException('frozenAmountById error'); - Db::commit(); - return $resModel; - }catch (\Exception $e) { - Db::rollBack(); - Log::error('newWithdrawPlatformTransaction', ['code' => $e->getCode(), 'error' => $e->getMessage()]); - return false; - } + $resBalanceModel = $oWalletPlatformBalanceModel->findPlatformBalanceOrCreate($platform_id, $currency_code); + if (!$resBalanceModel) throw new ModelException('findPlatformBalanceOrCreate error'); - } + $bean->setBalanceId($resBalanceModel->id); + $bean->setBeforeTotalAmount($resBalanceModel->total_amount); + $bean->setAfterTotalAmount(Math::bcSub($resBalanceModel->total_amount, abs($amount))); + //新增账变 + $res = $this->addTransaction($bean); + if (!$res) throw new ModelException('addTransaction fail'); + //变更余额 + $res = $oWalletPlatformBalanceModel->subAvailableAmount($bean->getBalanceId(), abs($amount)); + if (!$res) throw new ModelException('subAvailableAmount fail'); - //成功提现处理 - function withdrawSuccByUserTransactionId($user_transaction_id,$entered_amount, $remark = ''): bool - { - try{ - Db::beginTransaction(); - $resModel = $this->findItemByWhere(['from_user_transaction_id' => $user_transaction_id, 'type' => self::TYPE_USER_WITHDRAW]); - if (!$resModel) throw new ModelException('user transaction not found'); - if (!in_array($resModel->status, [self::STATUS_WAITING_QUEUE, self::STATUS_CHAIN_WAITING_CALLBACK])) throw new ModelException('status error'); - $updateItems = [ - 'id' => $resModel->id, - 'status' => self::STATUS_SUCCESS, - 'updated_at' => Times::getNowDateTime(), - 'entered_amount' => $entered_amount, - 'fee_amount' => Db::raw('received_amount - '.$entered_amount), - ]; - if(!empty($remark)) $updateItems['remark'] = $remark; - $res = $this->updateItem($updateItems); - if(!$res) throw new ModelException('save error'); - - //扣除平台冻结余额 - $oWalletPlatformBalanceModel = new WalletPlatformBalanceModel(); - $resWalletPlatformBalanceModel = $oWalletPlatformBalanceModel->findPlatformBalance($resModel->platform_id, $resModel->currency_code); - if (!$resWalletPlatformBalanceModel) throw new ModelException('platform balance not found'); - $res = $oWalletPlatformBalanceModel->decFrozenAmountById($resWalletPlatformBalanceModel->id, $resModel->received_amount); - if (!$res) throw new ModelException('incBalance error'); - - Db::commit(); - return true; - }catch (\Exception $e){ - Db::rollBack(); - Log::error('withdrawSuccByUserTransactionIdErr', ['code' => $e->getCode(), 'error' => $e->getMessage()]); - return false; - } - - } - - - //失败提现处理 - function withdrawErrByUserTransactionId($user_transaction_id, $remark = ''): bool - { - try { - Db::beginTransaction(); - $resModel = $this->findItemByWhere(['from_user_transaction_id' => $user_transaction_id, 'type' => self::TYPE_USER_WITHDRAW]); - if (!$resModel) throw new ModelException('user transaction not found'); - if (!in_array($resModel->status, [self::STATUS_WAITING_QUEUE, self::STATUS_CHAIN_WAITING_CALLBACK])) throw new ModelException('status error'); - //更改账变状态 - $updateItems = [ - 'id' => $resModel->id, - 'status' => self::STATUS_FAIL, - 'updated_at' => Times::getNowDateTime(), - ]; - if(!empty($remark)) $updateItems['remark'] = $remark; - $res = $this->updateItem($updateItems); - if (!$res) throw new ModelException('save error'); - - //解冻平台余额 - $oWalletPlatformBalanceModel = new WalletPlatformBalanceModel(); - $resWalletPlatformBalanceModel = $oWalletPlatformBalanceModel->findPlatformBalance($resModel->platform_id, $resModel->currency_code); - if (!$resWalletPlatformBalanceModel) throw new ModelException('platform balance not found'); - $res = $oWalletPlatformBalanceModel->unFrozenAmountById($resWalletPlatformBalanceModel->id, $resModel->received_amount); - if (!$res) throw new ModelException('incBalance error'); - Db::commit(); + DB::commit(); + Logs::SuccLog(__FUNCTION__, func_get_args()); return true; } catch (\Exception $e) { - Db::rollBack(); - Log::error('withdrawErrByUserTransactionIdErr', ['code' => $e->getCode(), 'error' => $e->getMessage()]); + DB::rollBack(); + Logs::ErrLog(__FUNCTION__ . ' rollBack', $e, func_get_args()); return false; } } - function newRechargePlatformTransaction( - $resWalletAddrTransactionModel, - $resWalletPlatformUserTransactionModel, - $amount, - $platform_id, - $currency_code, - ): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|bool + //管理员加款 + function typeAdminAdd($platform_id, $uid, $currency_code, $amount, $remark = null): bool { + $bean = new WalletPlatformBalanceTransactionBean(); + $bean->setPlatformId($platform_id); + $bean->setUid($uid); + $bean->setCurrencyCode($currency_code); + $bean->setAmount(abs($amount)); //正数 + $bean->setType(self::TYPE_ADMIN_ADD); + $bean->setStatus(self::STATUS_SUCCESS); + $bean->setRemark($remark); try { - Db::beginTransaction(); - $resModel = $this->addPlatformTransaction(self::TYPE_USER_RECHARGE, self::STATUS_SUCCESS, $amount,$amount, $platform_id, $currency_code,$resWalletPlatformUserTransactionModel->uid,$resWalletPlatformUserTransactionModel->id,$resWalletAddrTransactionModel->wallet_addr_id,$resWalletAddrTransactionModel->wallet_addr); - if(!$resModel) throw new ModelException('addPlatformTransaction error'); + DB::beginTransaction(); + //查询平台余额 $oWalletPlatformBalanceModel = new WalletPlatformBalanceModel(); - $resWalletPlatformBalanceModel = $oWalletPlatformBalanceModel->findPlatformBalance($platform_id,$currency_code); - if (!$resWalletPlatformBalanceModel) throw new ModelException('findPlatformBalance error'); - $res = $oWalletPlatformBalanceModel->incAvailableBalance($resWalletPlatformBalanceModel->id, $amount); //变更平台余额 - if (!$res) throw new ModelException('frozenAmountById error'); - Db::commit(); - return $resModel; - }catch (\Exception $e) { - Db::rollBack(); - Log::error('newWithdrawPlatformTransaction', ['code' => $e->getCode(), 'error' => $e->getMessage()]); + $resBalanceModel = $oWalletPlatformBalanceModel->findPlatformBalanceOrCreate($platform_id, $currency_code); + if (!$resBalanceModel) throw new ModelException('findPlatformBalanceOrCreate error'); + + $bean->setBalanceId($resBalanceModel->id); + $bean->setBeforeTotalAmount($resBalanceModel->total_amount); + $bean->setAfterTotalAmount(Math::bcAdd($resBalanceModel->total_amount, $bean->getAmount())); + //新增账变 + $res = $this->addTransaction($bean); + if (!$res) throw new ModelException('addTransaction fail'); + //变更余额 + $res = $oWalletPlatformBalanceModel->addAvailableAmount($bean->getBalanceId(), $bean->getAmount()); + if (!$res) throw new ModelException('addAvailableAmount fail'); + + DB::commit(); + Logs::SuccLog(__FUNCTION__, func_get_args()); + return true; + } catch (\Exception $e) { + DB::rollBack(); + Logs::ErrLog(__FUNCTION__ . ' rollBack', $e, func_get_args()); return false; } + } + //手续费扣除 + function typeTransactionFeeSub($platform_id, $uid, $currency_code, $amount, $remark = null): bool + { + $bean = new WalletPlatformBalanceTransactionBean(); + $bean->setPlatformId($platform_id); + $bean->setUid($uid); + $bean->setCurrencyCode($currency_code); + $bean->setAmount(-abs($amount)); //负数 + $bean->setType(self::TYPE_TRANSACTION_FEE_SUB); + $bean->setStatus(self::STATUS_SUCCESS); + $bean->setRemark($remark); + try { + DB::beginTransaction(); + //查询平台余额 + $oWalletPlatformBalanceModel = new WalletPlatformBalanceModel(); + $resBalanceModel = $oWalletPlatformBalanceModel->findPlatformBalanceOrCreate($platform_id, $currency_code); + if (!$resBalanceModel) throw new ModelException('findPlatformBalanceOrCreate error'); + + $bean->setBalanceId($resBalanceModel->id); + $bean->setBeforeTotalAmount($resBalanceModel->total_amount); + $bean->setAfterTotalAmount(Math::bcSub($resBalanceModel->total_amount, abs($amount))); + //新增账变 + $res = $this->addTransaction($bean); + if (!$res) throw new ModelException('addTransaction fail'); + //变更余额 + $res = $oWalletPlatformBalanceModel->subAvailableAmount($bean->getBalanceId(), abs($amount)); + if (!$res) throw new ModelException('subAvailableAmount fail'); + + DB::commit(); + Logs::SuccLog(__FUNCTION__, func_get_args()); + return true; + } catch (\Exception $e) { + DB::rollBack(); + Logs::ErrLog(__FUNCTION__ . ' rollBack', $e, func_get_args()); + return false; + } + } + + //手续费增加 + function typeTransactionFeeAdd($platform_id, $uid, $currency_code, $amount, $remark = null): bool + { + $bean = new WalletPlatformBalanceTransactionBean(); + $bean->setPlatformId($platform_id); + $bean->setUid($uid); + $bean->setCurrencyCode($currency_code); + $bean->setAmount(abs($amount)); //正数 + $bean->setType(self::TYPE_TRANSACTION_FEE_ADD); + $bean->setStatus(self::STATUS_SUCCESS); + $bean->setRemark($remark); + try { + DB::beginTransaction(); + //查询平台余额 + $oWalletPlatformBalanceModel = new WalletPlatformBalanceModel(); + $resBalanceModel = $oWalletPlatformBalanceModel->findPlatformBalanceOrCreate($platform_id, $currency_code); + if (!$resBalanceModel) throw new ModelException('findPlatformBalanceOrCreate error'); + + $bean->setBalanceId($resBalanceModel->id); + $bean->setBeforeTotalAmount($resBalanceModel->total_amount); + $bean->setAfterTotalAmount(Math::bcAdd($resBalanceModel->total_amount, $bean->getAmount())); + //新增账变 + $res = $this->addTransaction($bean); + if (!$res) throw new ModelException('addTransaction fail'); + //变更余额 + $res = $oWalletPlatformBalanceModel->addAvailableAmount($bean->getBalanceId(), $bean->getAmount()); + if (!$res) throw new ModelException('addAvailableAmount fail'); + + DB::commit(); + Logs::SuccLog(__FUNCTION__, func_get_args()); + return true; + } catch (\Exception $e) { + DB::rollBack(); + Logs::ErrLog(__FUNCTION__ . ' rollBack', $e, func_get_args()); + return false; + } + } + + //充值 + function typeRecharge($platform_id, $uid, $currency_code, $amount, $to_wallet_address_id = null, $tid = null, $callback_wallet_address_transaction_id = null): bool + { + $bean = new WalletPlatformBalanceTransactionBean(); + $bean->setBlockTransactionId($tid); + $bean->setPlatformId($platform_id); + $bean->setUid($uid); + $bean->setCurrencyCode($currency_code); + $bean->setAmount(abs($amount)); //正数 + $bean->setType(self::TYPE_RECHARGE_ADD); + $bean->setStatus(self::STATUS_SUCCESS); + $bean->setCallbackWalletAddressTransactionId($callback_wallet_address_transaction_id); + $bean->setToWalletAddressId($to_wallet_address_id); + try { + DB::beginTransaction(); + //检测钱包地址和当前绑定地址是否一致 + $oWalletPlatformBindModel = new WalletPlatformBindModel(); + $resBindModel = $oWalletPlatformBindModel->findBind($platform_id, $uid, $currency_code); + if (!$resBindModel) throw new ModelException('WalletPlatformBindModel findBind error'); + //查找钱包地址 + $oWalletAddressModel = new WalletAddressModel(); + $resWalletAddressModel = $oWalletAddressModel->findItem($resBindModel->wallet_address_id); + if (!$resWalletAddressModel) throw new ModelException('WalletAddressModel findItem error'); + //检测异步到账地址是否和绑定地址一致 + if (!empty($wallet_address_id)) { + if ($resWalletAddressModel->id != $to_wallet_address_id) throw new ModelException('wallet_address_id not same'); + } + $bean->setBindWalletAddressId($resWalletAddressModel->id); + $bean->setBindWalletAddress($resWalletAddressModel->address_base58); + + //查询平台余额 + $oWalletPlatformBalanceModel = new WalletPlatformBalanceModel(); + $resBalanceModel = $oWalletPlatformBalanceModel->findPlatformBalanceOrCreate($platform_id, $currency_code); + if (!$resBalanceModel) throw new ModelException('findPlatformBalanceOrCreate error'); + $bean->setBalanceId($resBalanceModel->id); + $bean->setBeforeTotalAmount($resBalanceModel->total_amount); + $bean->setAfterTotalAmount(Math::bcAdd($resBalanceModel->total_amount, $bean->getAmount())); + //新增账变 + $res = $this->addTransaction($bean); + if (!$res) throw new ModelException('addTransaction fail'); + //变更余额 + $res = $oWalletPlatformBalanceModel->addAvailableAmount($bean->getBalanceId(), $bean->getAmount()); + if (!$res) throw new ModelException('addAvailableAmount fail'); + + DB::commit(); + Logs::SuccLog(__FUNCTION__, func_get_args()); + return true; + } catch (\Exception $e) { + DB::rollBack(); + Logs::ErrLog(__FUNCTION__ . ' rollBack', $e); + return false; + } + } + + //发起提现 + function typeWithdrawFirst($platform_id, $uid, $currency_code, $amount, $to_address = null): bool + { + $bean = new WalletPlatformBalanceTransactionBean(); + $bean->setPlatformId($platform_id); + $bean->setUid($uid); + $bean->setCurrencyCode($currency_code); + $bean->setAmount(-abs($amount)); //负数 + $bean->setType(self::TYPE_WITHDRAW_DEC); + $bean->setStatus(self::STATUS_WAIT); + $bean->setToWalletAddress($to_address); + try { + DB::beginTransaction(); + //获取提现手续费 + $oTableWalletSettingCache = new TableWalletSettingCache(); + $withdraw_fee = $oTableWalletSettingCache->getWithdrawFeeAmount(); + //查询平台余额 + $oWalletPlatformBalanceModel = new WalletPlatformBalanceModel(); + $resBalanceModel = $oWalletPlatformBalanceModel->findPlatformBalanceOrCreate($platform_id, $currency_code); + if (!$resBalanceModel) throw new ModelException('findPlatformBalanceOrCreate error'); + //检查余额是否足够 + if (Math::bcComp(Math::bcSub($resBalanceModel->available_amount, $withdraw_fee), abs($bean->getAmount())) == -1) throw new ModelException('available_amount not enough'); + $bean->setBalanceId($resBalanceModel->id); + $bean->setBeforeTotalAmount($resBalanceModel->total_amount); + $bean->setAfterTotalAmount(Math::bcSub($resBalanceModel->total_amount, $bean->getAmount())); + $bean->setFeeAmount($withdraw_fee); + + //查询当前绑定地址 + $oWalletPlatformBindModel = new WalletPlatformBindModel(); + $resBindModel = $oWalletPlatformBindModel->findBind($platform_id, $uid, $currency_code); + if (!$resBindModel) throw new ModelException('findBind error'); + //查找钱包地址 + $oWalletAddressModel = new WalletAddressModel(); + $resWalletAddressModel = $oWalletAddressModel->findItem($resBindModel->wallet_address_id); + if (!$resWalletAddressModel) throw new ModelException('WalletAddressModel findItem error'); + $bean->setBindWalletAddressId($resWalletAddressModel->id); + $bean->setBindWalletAddress($resWalletAddressModel->address_base58); + + //新增账变 + $res = $this->addTransaction($bean); + if (!$res) throw new ModelException('addTransaction fail'); + //先扣除手续费 + $res = $this->typeTransactionFeeSub($platform_id, $uid, $currency_code, $withdraw_fee, $res->id .'withdraw fee'); + if (!$res) throw new ModelException('withdraw fee fail'); + //变更余额 + //先冻结,等回调成功再扣减 + $res = $oWalletPlatformBalanceModel->frozenAmount($bean->getBalanceId(), $bean->getAmount()); + if (!$res) throw new ModelException('frozenAmount fail'); + + //投递到提现处理队列 + $oQueueWalletPlatformWithdrawBean = new QueueWalletPlatformWithdrawTransferBean(); + $oQueueWalletPlatformWithdrawBean->setTransactionId($bean->getId()); + WalletPlatformWithdrawTransferQueue::putToQueue($oQueueWalletPlatformWithdrawBean); + + DB::commit(); + Logs::SuccLog(__FUNCTION__, func_get_args()); + return true; + } catch (\Exception $e) { + DB::rollBack(); + Logs::ErrLog(__FUNCTION__ . 'rollBack', $e); + return false; + } + } + + //提现回调 + function typeWithdrawSecondCallback($id, $status, $remark = null, $callback_wallet_address_transaction_id = null): bool + { + try { + DB::beginTransaction(); + //获取账变 + $resModel = $this->findItem($id); + if (!$resModel) throw new ModelException('findItem error'); + if ($resModel->status != self::STATUS_PROCESSING) throw new ModelException('status error'); + //查询平台余额 + $oWalletPlatformBalanceModel = new WalletPlatformBalanceModel(); + $resBalanceModel = $oWalletPlatformBalanceModel->findItem($resModel->balance_id); + if (!$resBalanceModel) throw new ModelException('WalletPlatformBalanceModel findItem error'); + + if ($status == self::STATUS_SUCCESS) { + //变更余额 + $res = $oWalletPlatformBalanceModel->subFrozenAmount($resModel->balance_id, $resModel->amount); + if (!$res) throw new ModelException('subFrozenAmount error'); + //更新账变状态 + $updateItem = [ + 'id' => $id, + 'status' => self::STATUS_SUCCESS, + 'remark' => $remark, + 'updated_at' => Times::getNowDateTime(), + 'callback_time' => Times::getNowDateTime(), + 'after_total_amount' => Math::bcAdd($resBalanceModel->total_amount, $resModel->amount), + 'before_total_amount' => $resBalanceModel->total_amount, + 'callback_wallet_address_transaction_id' => $callback_wallet_address_transaction_id, + ]; + if (!empty($remark)) $updateItem['remark'] = $remark; + $res = $this->updateItem($updateItem); + if (!$res) throw new ModelException('updateItem error'); + //投递到通知平台队列 + $oQueueNotifyToPlatformBean = new QueueNotifyToPlatformBean(); + $oQueueNotifyToPlatformBean->setType(QueueNotifyToPlatformBean::TYPE_WITHDRAW); + $oQueueNotifyToPlatformBean->setPlatformId($resModel->platform_id); + $oQueueNotifyToPlatformBean->setCurrencyCode($resModel->currency_code); + $oQueueNotifyToPlatformBean->setAmount($resModel->amount); + $oQueueNotifyToPlatformBean->setStatus(self::STATUS_SUCCESS); + $oQueueNotifyToPlatformBean->setSn($resModel->sn); + + WalletNotifyToPlatformQueue::putToQueue($oQueueNotifyToPlatformBean); + } else { + //变更余额 + $res = $oWalletPlatformBalanceModel->unFrozenAmount($resModel->balance_id, $resModel->amount); + if (!$res) throw new ModelException('unFrozenAmount error'); + //更新账变状态 + $updateItem = [ + 'id' => $id, + 'status' => self::STATUS_FAIL, + 'updated_at' => Times::getNowDateTime(), + 'callback_time' => Times::getNowDateTime(), + 'callback_wallet_address_transaction_id' => $callback_wallet_address_transaction_id, + ]; + if (!empty($remark)) $updateItem['remark'] = $remark; + $res = $this->updateItem($updateItem); + if (!$res) throw new ModelException('updateItem error'); + //返还手续费 + $res = $this->typeTransactionFeeAdd($resModel->platform_id, $resModel->uid, $resModel->currency_code, $resModel->fee_amount, $resModel->id . 'withdraw fail return fee'); + if (!$res) throw new ModelException('withdraw fail return fee fail'); + } + + DB::commit(); + Logs::SuccLog(__FUNCTION__, func_get_args()); + return true; + } catch (\Exception $e) { + DB::rollBack(); + Logs::ErrLog(__FUNCTION__ . ' rollBack', $e, func_get_args()); + return false; + } + } + + + function addTransaction(WalletPlatformBalanceTransactionBean &$bean): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|bool + { + if (!$bean->getPlatformId()) throw new ModelException('addTransaction getPlatformId is required'); + if (!$bean->getCurrencyCode()) throw new ModelException('addTransaction getCurrencyCode is required'); + if (!$bean->getType()) throw new ModelException('addTransaction getType is required'); + if (!$bean->getStatus()) throw new ModelException('addTransaction getStatus is required'); + if (!$bean->getBalanceId()) throw new ModelException('addTransaction getBalanceId is required'); + if (!$bean->getBindWalletAddressId()) throw new ModelException('addTransaction getBindWalletAddressId is required'); + if (empty($bean->getSn())) $bean->setSn(Tools::genUuid()); + $bean->setCreatedAt(Times::getNowDateTime()); + return $this->addItem($bean->toArrayNotNull()); + } + + function findByBlockTransactionId(string $tid, $type): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection|\Illuminate\Database\Eloquent\Builder|array|null + { + if (!in_array($type, [self::TYPE_RECHARGE_ADD, self::TYPE_WITHDRAW_DEC])) throw new ModelException('type error'); + return $this->findItemByWhere(['block_transaction_id' => $tid, 'type' => $type]); } diff --git a/app/Models/Wallet/Platform/WalletPlatformBindHistoryModel.php b/app/Models/Wallet/Platform/WalletPlatformBindHistoryModel.php new file mode 100644 index 0000000..424f6bb --- /dev/null +++ b/app/Models/Wallet/Platform/WalletPlatformBindHistoryModel.php @@ -0,0 +1,47 @@ +addItem($aItem); + + } + + + +} diff --git a/app/Models/Wallet/Platform/WalletPlatformBindModel.php b/app/Models/Wallet/Platform/WalletPlatformBindModel.php new file mode 100644 index 0000000..c663a4b --- /dev/null +++ b/app/Models/Wallet/Platform/WalletPlatformBindModel.php @@ -0,0 +1,169 @@ +newQuery() + ->where('platform_id', $platformId) + ->where('wallet_address_id', $walletAddressId) + ->where('currency_code', $currencyCode) + ->where('uid', $uid) + ->first(); + } + + function checkIsBind($platformId, $uid, $currencyCode): bool + { + $res = $this->findBind($platformId, $uid, $currencyCode,['id']); + if($res) return true; + return false; + } + + function findBind($platformId, $uid, $currencyCode,$cols = ['*']): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|null + { + if(empty($uid)) $uid = 0; //平台默认充提地址 + return $this->newQuery() + ->where('platform_id', $platformId) + ->where('currency_code', $currencyCode) + ->where('uid', $uid) + ->first($cols) + ; + } + + //查找空余钱包地址分配给平台 + function addBindWallet($platformId, $uid = null, $currencyCode = WalletCurrencyModel::CODE_USDT_TRC20): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|bool + { + $res = $this->checkIsBind($platformId, $uid, $currencyCode); + if($res) return false; + + try { + DB::beginTransaction(); + //检测是否已经绑定 + $this->getBindInfo( $platformId, $uid, $currencyCode); + $oWalletAddressModel = new WalletAddressModel(); + $resWalletAddressModel = $oWalletAddressModel->findFreeAddress($currencyCode); + if ($resWalletAddressModel) { + throw new ModelException("can not find free address"); + } + $bean = new WalletPlatformBindBean(); + $bean->setPlatformId($platformId); + $bean->setCurrencyCode($currencyCode); + $bean->setUid($uid); + $bean->setWalletAddressId($resWalletAddressModel->id); + $bean->setCreatedAt(Times::getNowDateTime()); + $res = $this->addItem($bean->toArrayNotNull()); + if(!$res) throw new ModelException("add bind fail"); + //更新钱包地址状态 + $updateItem = [ + 'id' => $resWalletAddressModel->id, + 'use_status' => WalletAddressModel::USE_STATUS_USING, + ]; + $res = $oWalletAddressModel->updateItem($updateItem); + if(!$res) throw new ModelException("change use_status fail wallet_address_id:{$resWalletAddressModel->id}"); + + DB::commit(); + Logs::SuccLog(__FUNCTION__, $bean->toArrayNotNull()); + return true; + }catch (\Exception $e) { + DB::rollBack(); + Logs::ErrLog(__FUNCTION__ . ' ' . 'rollBack', $e, func_get_args()); + return false; + } + } + + //解绑 + function unBindWithUid($platformId, $uid, $currencyCode = WalletCurrencyModel::CODE_USDT_TRC20,$remark = ''): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|bool + { + $res = $this->checkIsBind($platformId, $uid, $currencyCode); + if(!$res) return true; + + try { + DB::beginTransaction(); + $oWalletAddressModel = new WalletAddressModel(); + $oWalletPlatformBindModel = new WalletPlatformBindModel(); + $resWalletPlatformBindModel = $oWalletPlatformBindModel->newQuery() + ->where('platform_id', $platformId) + ->where('currency_code', $currencyCode) + ->where('uid', $uid) + ->first(); + if (!$resWalletPlatformBindModel) return true; + + //废弃原有地址 + $updateItem = [ + 'id' => $resWalletPlatformBindModel->id, + 'use_status' => WalletAddressModel::USE_STATUS_USED, + ]; + $res = $oWalletAddressModel->updateItem($updateItem); + if(!$res) throw new ModelException("change used use_status fail wallet_address_id:{$resWalletPlatformBindModel->wallet_address_id}"); + + //删除原有绑定记录 + $res = $oWalletPlatformBindModel->delItem($resWalletPlatformBindModel->id); + if(!$res) throw new ModelException("delete bind fail"); + + //原有绑定记录添加到历史 + $oWalletPlatformBindHistoryModel = new WalletPlatformBindHistoryModel(); + $res = $oWalletPlatformBindHistoryModel->addHistory($resWalletPlatformBindModel->toArray(),$remark); + if(!$res) throw new ModelException("add history fail"); + + DB::commit(); + Logs::SuccLog(__FUNCTION__, func_get_args()); + return true; + }catch (\Exception $e) { + DB::rollBack(); + Logs::ErrLog(__FUNCTION__ . ' ' . 'rollBack', $e, func_get_args()); + return false; + } + } + + //绑定检测是否已绑定,未绑定则绑定,已绑定则解绑再绑定新地址 + function bindWallet( $platformId, $currencyCode = WalletCurrencyModel::CODE_USDT_TRC20, $uid = null): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|bool + { + try { + DB::beginTransaction(); + + $res = $this->unBindWithUid($platformId, $uid, $currencyCode); + if(!$res) throw new ModelException("unBindWithUid fail"); + + $res = $this->addBindWallet($platformId, $uid, $currencyCode); + if(!$res) throw new ModelException("addBindWallet fail"); + + DB::commit(); + Logs::SuccLog(__FUNCTION__, func_get_args()); + return true; + }catch (\Exception $e) { + DB::rollBack(); + Logs::ErrLog(__FUNCTION__ . ' ' . 'rollBack', $e, func_get_args()); + return false; + } + } + + + + + +} diff --git a/app/Models/Wallet/PlatformUser/WalletPlatformUserTransactionModel.php b/app/Models/Wallet/PlatformUser/WalletPlatformUserTransactionModel.php deleted file mode 100644 index 5ab171c..0000000 --- a/app/Models/Wallet/PlatformUser/WalletPlatformUserTransactionModel.php +++ /dev/null @@ -1,360 +0,0 @@ - '充值', - self::TYPE_WITHDRAW => '提现', - ]; - - const STATUS_WAITING_QUEUE = 1; - const STATUS_CODE_PROCESSING = 2; - const STATUS_CHAIN_WAITING = 3; - const STATUS_SUCCESS = 4; - const STATUS_FAIL = 5; - const STATUS = [ - self::STATUS_WAITING_QUEUE => '等待队列', - self::STATUS_CODE_PROCESSING => '程序处理中', - self::STATUS_CHAIN_WAITING => '链上等待', - self::STATUS_SUCCESS => '成功', - self::STATUS_FAIL => '失败', - ]; - - const DESC_KEY_NOT_FOUND_WITHDRAW_AMOUNT_WALLET_ADDR = 'notFoundWithdrawAmountWalletAddr'; - const DESC_KEY_WITHDRAW_WALLET_AMOUNT_LOW = 'withdrawWalletAmountLow'; - const DESC_KEY_WITHDRAW_CALL_CHAIN_WRONG = 'withdrawCallChainWrong'; - - const DESC = [ - self::DESC_KEY_NOT_FOUND_WITHDRAW_AMOUNT_WALLET_ADDR => '未找到足额提现金额钱包地址', - self::DESC_KEY_WITHDRAW_WALLET_AMOUNT_LOW => '提现钱包金额不足', - self::DESC_KEY_WITHDRAW_CALL_CHAIN_WRONG => '提现调用链上接口失败', - ]; - - //请求提现发起 - function withdrawFirst($amount, $platform_id, $uid, $currency_code, $desc_key = null, $remark = ''): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|bool - { - try { - Db::beginTransaction(); - $amount = abs($amount); - //检查平台余额 - $oWalletPlatformBalanceModel = new WalletPlatformBalanceModel(); - $resWalletPlatformBalanceModel = $oWalletPlatformBalanceModel->findPlatformBalance($platform_id, $currency_code); - if (!$resWalletPlatformBalanceModel) throw new ModelException('platform_id or currency_code error'); - if (Math::bcComp($resWalletPlatformBalanceModel->available_amount, $amount) == -1) throw new ModelException('platform balance not enough'); - - //冻结平台余额并增加账变 - $oWalletPlatformBalanceTransactionModel = new WalletPlatformBalanceTransactionModel(); - $resWalletPlatformBalanceTransactionModel = $oWalletPlatformBalanceTransactionModel->newWithdrawPlatformTransaction($amount, $platform_id, $currency_code,$uid); - if (!$resWalletPlatformBalanceTransactionModel) throw new ModelException('newWithdrawPlatformTransaction error'); - - //根据币种计算费率 - $oWalletCurrencyModel = new WalletCurrencyModel(); - $oWalletCurrencyModel = $oWalletCurrencyModel->findByCode($currency_code); - if (!$oWalletCurrencyModel) throw new ModelException('currency_code error'); - $fee_amount = $oWalletCurrencyModel->computeTransferRate($amount, $oWalletCurrencyModel->transfer_rate); - //预计费率计算 - if ($fee_amount <= 0) throw new ModelException('fee_amount error'); - $desc = isset(self::DESC[$desc_key]) ? self::DESC[$desc_key] : ''; - $resModel = $this->addWithdrawTransaction($platform_id, $uid, $oWalletCurrencyModel, $amount, $fee_amount, $desc_key, $desc, $remark); - if (!$resModel) throw new ModelException('addItem error'); - $oWalletPlatformBalanceTransactionModel->updateItem([ - 'id' => $resWalletPlatformBalanceTransactionModel->id, - 'from_user_transaction_id' => $resModel->id, - ]); - $this->putWithdrawToQueue($resModel->id); //投递到队列处理 - Db::commit(); - Log::info('newWithdrawSucc', ['platform_id' => $platform_id, 'uid' => $uid, 'currency_code' => $currency_code, 'amount' => $amount]); - return $resModel; - } catch (\Exception $e) { - Db::rollBack(); - Log::error('newWithdrawErr', ['platform_id' => $platform_id, 'uid' => $uid, 'currency_code' => $currency_code, 'amount' => $amount, 'msg' => $e->getMessage()]); - return false; - } - } - - function addWithdrawTransaction($platform_id, $uid, $oWalletCurrencyModel, $amount, $fee_amount, $desc_key = null, $desc = '', $remark = ''): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|bool - { - $insert = [ - 'type' => self::TYPE_WITHDRAW, - 'status' => self::STATUS_WAITING_QUEUE, - 'platform_id' => $platform_id, - 'uid' => $uid, - 'currency_id' => $oWalletCurrencyModel->id, - 'currency_code' => $oWalletCurrencyModel->code, - 'currency_type' => $oWalletCurrencyModel->type, - 'received_amount' => abs($amount), -// 'entered_amount' => abs($entered_amount), - 'fee_amount' => abs($fee_amount), - 'desc_key' => $desc_key ?? '', - 'desc' => $desc, - 'remark' => $remark, - 'created_at' => date('Y-m-d H:i:s'), - ]; - return $this->addItem($insert); - } - - function addRechargeTransaction($resWalletAddrTransactionModel,$platform_id, $uid, $oWalletCurrencyModel, $amount, $desc_key = null, $desc = '', $remark = ''): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|bool - { - $amount = abs($amount); - $insert = [ - 'type' => self::TYPE_RECHARGE, - 'status' => self::STATUS_SUCCESS, //充提成功 - 'platform_id' => $platform_id, - 'uid' => $uid, - 'currency_id' => $oWalletCurrencyModel->id, - 'currency_code' => $oWalletCurrencyModel->code, - 'currency_type' => $oWalletCurrencyModel->type, - 'from_wallet_addr_id' => $resWalletAddrTransactionModel->wallet_addr_id, - 'wallet_addr' => $resWalletAddrTransactionModel->wallet_addr, - 'from_wallet_transaction_id' => $resWalletAddrTransactionModel->id, - 'received_amount' => $amount, - 'entered_amount' => $amount, - 'desc_key' => $desc_key ?? '', - 'desc' => $desc, - 'remark' => $remark, - 'created_at' => date('Y-m-d H:i:s'), - ]; - return $this->addItem($insert); - } - - function addTransactionWithPlatformBalance($resWalletAddrTransactionModel,$platform_id, $uid, $oWalletCurrencyModel, $amount, $desc_key = null, $desc = '', $remark = '') - { - try { - Db::beginTransaction(); - $resModel = $this->addRechargeTransaction($resWalletAddrTransactionModel,$platform_id, $uid, $oWalletCurrencyModel, $amount, $desc_key, $desc, $remark); - if(!$resModel) throw new ModelException('addRechargeTransaction error'); - $oWalletPlatformBalanceTransactionModel = new WalletPlatformBalanceTransactionModel(); - $res = $oWalletPlatformBalanceTransactionModel->newRechargePlatformTransaction($resWalletAddrTransactionModel,$resModel,$amount, $platform_id, $oWalletCurrencyModel->code); - if(!$res) throw new ModelException('newRechargePlatformTransaction error'); - Db::commit(); - return true; - }catch (\Exception $e) { - Db::rollBack(); - Log::error('addTransactionWithBalance', ['platform_id' => $platform_id, 'uid' => $uid, 'amount' => $amount, 'msg' => $e->getMessage()]); - return false; - } - - } - - //@@投递到rabbitmq队列处理 - function putWithdrawToQueue($wallet_platform_user_transaction_id): void - { - $params = [ - 'wallet_platform_user_transaction_id' => $wallet_platform_user_transaction_id, - ]; - WalletPlatformUserWithdrawQueue::dispatch($params)->onQueue(QueueWalletPlatformUserWithdrawStruct::QUEUE_NAME); - } - - //处理用户提现队列,发起链上提现 - function withdrawConsumer($id): void - { - //@新增任务处理表 - //查询前先检查redis中锁 - $oWalletPlatformUserTransactionLock = new WalletPlatformUserTransactionLock(); - $isLock = $oWalletPlatformUserTransactionLock->checkLock($oWalletPlatformUserTransactionLock->getWithdrawKey($id)); - if ($isLock) return; //有锁就跳过 - //加锁 - $isLock = $oWalletPlatformUserTransactionLock->setLock($oWalletPlatformUserTransactionLock->getWithdrawKey($id)); - if (!$isLock) return; //加锁失败 - //查询任务 - $resWalletPlatformUserTransactionModel = $this->findItem($id); - if (!$resWalletPlatformUserTransactionModel) throw new ModelException('id error'); - if ($resWalletPlatformUserTransactionModel->type != self::TYPE_WITHDRAW) throw new ModelException('type error'); - if ($resWalletPlatformUserTransactionModel->status != self::STATUS_WAITING_QUEUE) throw new ModelException('status error'); - $resWalletPlatformUserTransactionModel->status = self::STATUS_CODE_PROCESSING; - $resWalletPlatformUserTransactionModel->save(); - - //获取提现地址 - $oWalletAddrModel = new WalletAddrModel(); - try { - $resWalletAddrModel = $oWalletAddrModel->findWithdrawAddrWithAmount($resWalletPlatformUserTransactionModel->received_amount, $resWalletPlatformUserTransactionModel->currency_code); - if (!$resWalletAddrModel) throw new ModelException('not found withdraw amount wallet addr'); - } catch (ModelException $e) { //未找到足额提现金额钱包地址 - $code = $e->getCode(); - $msg = $e->getMessage(); - $resWalletPlatformUserTransactionModel->status = self::STATUS_FAIL; - if ($code == ModelException::CODE_WALLET_AMOUNT_ADDR_NOT_FOUND) { //未找到足额提现金额钱包地址 - $resWalletPlatformUserTransactionModel->desc_key = self::DESC_KEY_NOT_FOUND_WITHDRAW_AMOUNT_WALLET_ADDR; - $resWalletPlatformUserTransactionModel->desc = self::DESC[self::DESC_KEY_NOT_FOUND_WITHDRAW_AMOUNT_WALLET_ADDR]; - } - if ($code == ModelException::CODE_WALLET_ADDR_BALANCE_LOW) { //提现钱包金额不足 - $resWalletPlatformUserTransactionModel->desc_key = self::DESC_KEY_WITHDRAW_WALLET_AMOUNT_LOW; - $resWalletPlatformUserTransactionModel->desc = self::DESC[self::DESC_KEY_WITHDRAW_WALLET_AMOUNT_LOW]; - } - - $resWalletPlatformUserTransactionModel->save(); - $this->withdrawFailUnLock($id); //解锁 - return; - } - - try { - $resWalletPlatformUserTransactionModel->from_wallet_addr_id = $resWalletAddrModel->id; - $resWalletPlatformUserTransactionModel->wallet_addr = $resWalletAddrModel->addr; - $resWalletPlatformUserTransactionModel->save(); - - //增加钱包账变 - $oWalletAddrTransactionModel = new WalletAddrTransactionModel(); - $resWalletAddrTransactionModel = $oWalletAddrTransactionModel->newPlatformUserWithdraw( - $resWalletAddrModel->id, - $resWalletPlatformUserTransactionModel->entered_amount, - $resWalletPlatformUserTransactionModel->id - ); - if (!$resWalletAddrTransactionModel) { - $this->withdrawFailUnLock($id); //解锁 - return; - } - //调用链上接口 - $resChain = $oWalletAddrModel->callWalletAddrChainTransferApi($resWalletPlatformUserTransactionModel->id, $resWalletAddrModel->id); - if (!$resChain) { //链上提现失败 - $resWalletPlatformUserTransactionModel->status = self::STATUS_FAIL; - $resWalletPlatformUserTransactionModel->desc_key = self::DESC_KEY_WITHDRAW_CALL_CHAIN_WRONG; - $resWalletPlatformUserTransactionModel->desc = self::DESC[self::DESC_KEY_WITHDRAW_CALL_CHAIN_WRONG]; - $resWalletPlatformUserTransactionModel->save(); - //解冻钱包余额 - $oWalletAddrTransactionModel->platformUserWithdrawCallback($resWalletAddrTransactionModel->id, $resWalletAddrTransactionModel->received_amount, WalletAddrTransactionModel::STATUS_FAIL); - $this->withdrawFailUnLock($id); //解锁 - return; - } - $resWalletPlatformUserTransactionModel->status = self::STATUS_CHAIN_WAITING; - $resWalletPlatformUserTransactionModel->save(); - $this->withdrawFailUnLock($id); //解锁 - - } catch (\Exception $e) { - Log::error('withdrawConsumer', ['id' => $id, 'msg' => $e->getMessage()]); - $this->withdrawFailUnLock($id); //解锁 - } - - } - - //用户提现失败解锁并返还平台余额 - function withdrawFailUnLock($id): void - { - //返还用户余额 - $oWalletPlatformBalanceTransactionModel = new WalletPlatformBalanceTransactionModel(); - $oWalletPlatformBalanceTransactionModel->withdrawErrByUserTransactionId($id); - //解锁 - $oWalletPlatformUserTransactionLock = new WalletPlatformUserTransactionLock(); - $oWalletPlatformUserTransactionLock->unLock($oWalletPlatformUserTransactionLock->getWithdrawKey($id)); - } - - //提现链上回调监听 - function listenWithdrawCallback($wallet_addr_transaction_id): void - { - Log::info('listenWithdrawCallback', ['wallet_addr_transaction_id' => $wallet_addr_transaction_id]); - //查找钱包账变 - $oWalletAddrTransactionModel = new WalletAddrTransactionModel(); - $resWalletAddrTransactionModel = $oWalletAddrTransactionModel->findItem($wallet_addr_transaction_id); - if (!$resWalletAddrTransactionModel) throw new ModelException('wallet_addr_transaction_id error'); - if ($resWalletAddrTransactionModel->type !== WalletAddrTransactionModel::TYPE_TRANSFER) throw new ModelException('wallet_addr_transaction_type error'); - if (!in_array($resWalletAddrTransactionModel->status, [WalletAddrTransactionModel::STATUS_SUCCESS, WalletAddrTransactionModel::STATUS_FAIL])) throw new ModelException('status error'); - if ($resWalletAddrTransactionModel->status == WalletAddrTransactionModel::STATUS_SUCCESS) $status = self::STATUS_SUCCESS; - if ($resWalletAddrTransactionModel->status == WalletAddrTransactionModel::STATUS_FAIL) $status = self::STATUS_FAIL; - if (empty($resWalletAddrTransactionModel->platform_user_transaction_id)) throw new ModelException('platform_user_transaction_id error'); - $id = $resWalletAddrTransactionModel->platform_user_transaction_id; - - if (!in_array($status, [self::STATUS_SUCCESS, self::STATUS_FAIL])) throw new ModelException('status error'); - $resWalletPlatformUserTransactionModel = $this->findItem($id); - if (!$resWalletPlatformUserTransactionModel) throw new ModelException('id error'); - if ($resWalletPlatformUserTransactionModel->type != self::TYPE_WITHDRAW) throw new ModelException('type error'); - if ($resWalletPlatformUserTransactionModel->status != self::STATUS_CHAIN_WAITING) throw new ModelException('status error'); - //用户账变处理 - $updateItems = [ - 'id' => $resWalletPlatformUserTransactionModel->id, - 'status' => $status, - 'entered_amount' => $resWalletAddrTransactionModel->entered_amount, - 'fee_amount' => Db::raw('received_amount - '.$resWalletAddrTransactionModel->entered_amount), - ]; - $res = $this->updateItem($updateItems); - if(!$res) { - Log::error('listenWithdrawCallbackErr', $updateItems); - return; - } - - //平台余额和账变处理 - $oWalletPlatformBalanceTransactionModel = new WalletPlatformBalanceTransactionModel(); - if ($status == self::STATUS_SUCCESS) { //成功 - $oWalletPlatformBalanceTransactionModel->withdrawSuccByUserTransactionId($id,$resWalletAddrTransactionModel->entered_amount); - } else { //失败 - $oWalletPlatformBalanceTransactionModel->withdrawErrByUserTransactionId($id); - } - } - - function listenRechargeCallback($wallet_addr_transaction_id): void - { - Log::info('listenRechargeCallback', ['wallet_addr_transaction_id' => $wallet_addr_transaction_id]); - //查找钱包账变 - $oWalletAddrTransactionModel = new WalletAddrTransactionModel(); - $resWalletAddrTransactionModel = $oWalletAddrTransactionModel->findItem($wallet_addr_transaction_id); - if (!$resWalletAddrTransactionModel) throw new ModelException('wallet_addr_transaction_id error'); - if ($resWalletAddrTransactionModel->type !== WalletAddrTransactionModel::TYPE_RECHARGE) throw new ModelException('wallet_addr_transaction_type error'); - if (!in_array($resWalletAddrTransactionModel->status, [WalletAddrTransactionModel::STATUS_SUCCESS, WalletAddrTransactionModel::STATUS_FAIL])) throw new ModelException('status error'); - if ($resWalletAddrTransactionModel->status == WalletAddrTransactionModel::STATUS_SUCCESS) $status = self::STATUS_SUCCESS; - if ($resWalletAddrTransactionModel->status == WalletAddrTransactionModel::STATUS_FAIL) $status = self::STATUS_FAIL; - if ($status != self::STATUS_SUCCESS) throw new ModelException('status not success'); - - $oWalletCurrencyModel = new WalletCurrencyModel(); - $resWalletCurrencyModel = $oWalletCurrencyModel->findItem($resWalletAddrTransactionModel->currency_id); - - //查找用户绑定钱包地址 - $oWalletPlatformUserWalletAddrModel = new WalletPlatformUserWalletAddrModel(); - $resWalletPlatformUserWalletAddrModel = $oWalletPlatformUserWalletAddrModel->findByWalletAddrId($resWalletAddrTransactionModel->wallet_addr_id); - if (!$resWalletPlatformUserWalletAddrModel) throw new ModelException('找不到wallet_addr_id绑定用户'); - - //给用户增加账变/平台增加账变增加余额 - $this->addTransactionWithPlatformBalance( - $resWalletAddrTransactionModel, - $resWalletPlatformUserWalletAddrModel->platform_id, - $resWalletPlatformUserWalletAddrModel->uid, - $resWalletCurrencyModel, - $resWalletAddrTransactionModel->received_amount, - ); - - } - - -} diff --git a/app/Models/Wallet/PlatformUser/WalletPlatformUserWalletAddrHistoryModel.php b/app/Models/Wallet/PlatformUser/WalletPlatformUserWalletAddrHistoryModel.php deleted file mode 100644 index bce51dc..0000000 --- a/app/Models/Wallet/PlatformUser/WalletPlatformUserWalletAddrHistoryModel.php +++ /dev/null @@ -1,44 +0,0 @@ - '绑定', - self::TYPE_UNBIND => '解绑', - ]; - - function addUserWalletAddrHistory($aItem,$type,$desc = ''): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|array|null - { - if(!in_array($type,self::TYPE)) throw new ModelException('type error'); - unset($aItem['id']);//去掉id(主键) - $aItem['type'] = $type; - $aItem['desc'] = $desc; - $sDateTime = date('Y-m-d H:i:s'); - $aItem['created_at'] = $sDateTime; - return $this->addItem($aItem); - } - -} diff --git a/app/Models/Wallet/PlatformUser/WalletPlatformUserWalletAddrModel.php b/app/Models/Wallet/PlatformUser/WalletPlatformUserWalletAddrModel.php deleted file mode 100644 index 5401385..0000000 --- a/app/Models/Wallet/PlatformUser/WalletPlatformUserWalletAddrModel.php +++ /dev/null @@ -1,81 +0,0 @@ -findUserWalletAddr($platform_id, $uid, $currency_code); - if($mode == WalletPlatformUserWalletAddrHistoryModel::TYPE_BIND && $resOldModel){ //默认检测是否已经绑定过 - throw new ModelException('已经绑定过地址'); - } - try { - DB::beginTransaction(); - //从钱包地址表取值 - $walletAddrModel = new WalletAddrModel(); - $oWalletPlatformUserWalletAddrHistoryModel = new WalletPlatformUserWalletAddrHistoryModel(); - $walletAddrModel = $walletAddrModel->findUnusedAddrPutUsing($currency_code); - if(!$walletAddrModel) throw new ModelException('获取新地址失败'); - if($mode == WalletPlatformUserWalletAddrHistoryModel::TYPE_UNBIND){ - if($resOldModel){ - $res = $this->delItem($resOldModel->id); - if(!$res) throw new ModelException('删除原有地址失败'); - $res = $oWalletPlatformUserWalletAddrHistoryModel->addUserWalletAddrHistory($resOldModel->toArray(),WalletPlatformUserWalletAddrHistoryModel::TYPE_UNBIND); - if(!$res) throw new ModelException('增加历史绑定地址失败'); - } - } - - $insert = [ - 'platform_id' => $platform_id, - 'uid' => $uid, - 'wallet_addr_id' => $walletAddrModel->id, - 'wallet_addr' => $walletAddrModel->addr, - 'currency_id' => $walletAddrModel->currency_id, - 'currency_code' => $walletAddrModel->currency_code, - 'created_at' => Times::getNowDateTime(), - ]; - $resModel = $this->addItem($insert); - if($resModel) $oWalletPlatformUserWalletAddrHistoryModel->addUserWalletAddrHistory($resModel->toArray(),WalletPlatformUserWalletAddrHistoryModel::TYPE_BIND); - DB::commit(); - }catch (\Exception $e) { - DB::rollBack(); - throw $e; - } - - return $resModel; - } - - function findUserWalletAddr($platform_id, $uid, $currency_code): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection|\Illuminate\Database\Eloquent\Builder|array|null - { - return $this->findItemByWhere(['platform_id' => $platform_id, 'uid' => $uid, 'currency_code' => $currency_code]); - } - - function findByWalletAddrId($wallet_addr_id): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection|\Illuminate\Database\Eloquent\Builder|array|null - { - return $this->findItemByWhere(['from_wallet_addr_id' => $wallet_addr_id]); - } - -} diff --git a/app/Models/Wallet/Tron/WalletTronBlockModel.php b/app/Models/Wallet/Tron/WalletTronBlockModel.php new file mode 100644 index 0000000..c30d26e --- /dev/null +++ b/app/Models/Wallet/Tron/WalletTronBlockModel.php @@ -0,0 +1,49 @@ + '等待', + self::STATUS_PROCESS => '处理中', + self::STATUS_FINISH => '完成', + self::STATUS_FAIL => '处理失败', + ]; + + function insertByBlockNum($blockNum): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|bool + { + $data = [ + 'block_num' => $blockNum, + 'status' => self::STATUS_WAIT, + 'created_at' => Times::getNowDateTime(), + + ]; + return $this->addItem($data); + } + + function getLastBlockNumber() + { + return $this->newQuery()->orderBy('block_num', 'desc')->value('block_num'); + } + + +} diff --git a/app/Models/Wallet/Wallet/WalletAddrModel.php b/app/Models/Wallet/Wallet/WalletAddrModel.php deleted file mode 100644 index e22bb29..0000000 --- a/app/Models/Wallet/Wallet/WalletAddrModel.php +++ /dev/null @@ -1,317 +0,0 @@ - '用户', - self::ROLE_SYSTEM => '系统', - ]; - - const TYPE_CASH = 1; - const TYPE_CRYPTO_COIN = 2; - const TYPE = [ - self::TYPE_CASH => '现金', - self::TYPE_CRYPTO_COIN => '加密货币', - ]; - - const USE_STATUS_UNUSED = 1; - const USE_STATUS_USING = 2; - const USE_STATUS_USED = 3; - const USE_STATUS = [ - self::USE_STATUS_UNUSED => '未使用', - self::USE_STATUS_USING => '使用中', - self::USE_STATUS_USED => '已使用', - ]; - - const DESC_KEY_USER_RECHARGE = 'userRecharge'; - const DESC_KEY_USER_WITHDRAW = 'userWithdraw'; - const DESC = [ - self::DESC_KEY_USER_RECHARGE => '用户充值', - self::DESC_KEY_USER_WITHDRAW => '用户提现', - ]; - - function addAddr($addr, $secret, $currency_code = WalletCurrencyModel::CODE_USDT_TRC20, $desc_key = '', $desc = '', $remark = '', $available_amount = 0, $role = self::ROLE_USER, $type = self::TYPE_CRYPTO_COIN, $use_status = self::USE_STATUS_UNUSED): int - { - $oWalletCurrencyModel = (new WalletCurrencyModel())->findByCode($currency_code, ['id', 'code']); - if (!$oWalletCurrencyModel) throw new ModelException('币种不存在'); - return $this->newQuery()->insertGetId([ - 'role' => $role, - 'type' => $type, - 'use_status' => $use_status, - 'addr' => $addr, - 'secret' => $secret, - 'desc_key' => $desc_key, - 'desc' => $desc, - 'remark' => $remark, - 'currency_id' => $oWalletCurrencyModel->id, - 'currency_code' => $oWalletCurrencyModel->code, - 'total_amount' => $available_amount, - 'available_amount' => $available_amount, - 'created_at' => date('Y-m-d H:i:s'), - ]); - } - - function findAddr($currency_code = WalletCurrencyModel::CODE_USDT_TRC20, $use_status = self::USE_STATUS_UNUSED): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|null - { - return $this->newQuery()->where('currency_code', $currency_code)->where('use_status', $use_status)->first(); - } - - function findUnusedAddrPutUsing($currency_code = WalletCurrencyModel::CODE_USDT_TRC20): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|null - { - $resModel = $this->newQuery()->where('currency_code', $currency_code)->where('use_status', self::USE_STATUS_UNUSED)->first(); - if (!$resModel) { - //@@获取不到地址就发送到队列生成新地址 - $this->makeNewWalletAddr($currency_code); - throw new ModelException('获取地址失败'); - } - $resModel->use_status = self::USE_STATUS_USING; - $resModel->save(); - return $resModel; - - } - - function makeNewWalletAddr($currency_code = WalletCurrencyModel::CODE_USDT_TRC20) - { - - } - - function changeUseStatus($id, $use_status): int - { - return $this->newQuery()->where('id', $id)->update(['use_status' => $use_status]); - } - - function incAvailableAmount($id, $amount): int - { - $amount = abs($amount); - $oModel = $this->newQuery()->where('id', $id)->first(['total_amount', 'available_amount']); - if (!$oModel) throw new ModelException('找不到wallet_addr_id'); - $oModel->frozen_amount = Db::raw('available_amount + ' . $amount); - $oModel->total_amount = Db::raw('total_amount + ' . $amount); - return $oModel->save(); - } - - function decAvailableAmount($id, $amount): int - { - $amount = abs($amount); - $oModel = $this->newQuery()->where('id', $id)->first(['total_amount', 'available_amount']); - if (!$oModel) throw new ModelException('找不到wallet_addr_id'); - $oModel->frozen_amount = Db::raw('available_amount - ' . $amount); - $oModel->total_amount = Db::raw('total_amount - ' . $amount); - return $oModel->save(); - } - - function decFrozenAmountById($id, $amount): int - { - $amount = abs($amount); - $oModel = $this->newQuery()->where('id', $id)->first(['total_amount', 'frozen_amount']); - if (!$oModel) throw new ModelException('找不到wallet_addr_id'); - $oModel->frozen_amount = Db::raw('frozen_amount - ' . $amount); - $oModel->total_amount = Db::raw('total_amount - ' . $amount); - return $oModel->save(); - } - - function unFrozenAmountById($id, $amount): int - { - $amount = abs($amount); - $oModel = $this->newQuery()->where('id', $id)->first(['frozen_amount', 'available_amount']); - if (!$oModel) throw new ModelException('找不到wallet_addr_id'); - $oModel->frozen_amount = Db::raw('frozen_amount - ' . $amount); - $oModel->available_amount = Db::raw('available_amount + ' . $amount); - return $oModel->save(); - } - - function frozenAmountById($id, $amount): int - { - $amount = abs($amount); - $oModel = $this->newQuery()->where('id', $id)->first(['frozen_amount', 'available_amount']); - if (!$oModel) throw new ModelException('找不到wallet_addr_id'); - $oModel->frozen_amount = Db::raw('frozen_amount + ' . $amount); - $oModel->available_amount = Db::raw('available_amount - ' . $amount); - return $oModel->save(); - } - - /** - * 充值回调监听 - * @throws ModelException - */ - function walletAddrTransactionChangeConsumer($wallet_addr_transaction_id,$wallet_addr_transaction_type): void - { - Log::info('walletAddrTransactionChangeConsumer', ['wallet_addr_transaction_id' => $wallet_addr_transaction_id,]); - $oWalletPlatformUserTransactionModel = new WalletPlatformUserTransactionModel(); - if($wallet_addr_transaction_type == WalletAddrTransactionModel::TYPE_RECHARGE){ - $oWalletPlatformUserTransactionModel->listenRechargeCallback($wallet_addr_transaction_id); - } - if($wallet_addr_transaction_type == WalletAddrTransactionModel::TYPE_TRANSFER){ - $oWalletPlatformUserTransactionModel->listenWithdrawCallback($wallet_addr_transaction_id); - } - - - } - - //提现链上回调监听 - function listenWalletAddrCallback($chain_sn, $token, $type, $addr, $amount, $status): void - { - //@@新增表记录每个地址的监听消息 - Log::info('listenWalletAddrCallbackParams', ['token' => $token, 'addr' => $addr, 'amount' => $amount, 'status' => $status]); - if (!in_array($type, [WalletAddrTransactionModel::TYPE_RECHARGE, WalletAddrTransactionModel::TYPE_TRANSFER])) { - Log::error('listenWalletAddrCallbackErr', ['token' => $token, 'addr' => $addr, 'amount' => $amount, 'status' => $status, 'error' => 'type类型错误']); - throw new ModelException('type类型错误'); - } - //充值不成功默认不处理 - if($type == WalletAddrTransactionModel::TYPE_RECHARGE && $status != WalletAddrTransactionModel::STATUS_SUCCESS){ - Log::error('listenWalletAddrCallbackStatus', ['token' => $token, 'addr' => $addr, 'amount' => $amount, 'status' => $status, 'error' => '充值失败']); - throw new ModelException('链上充值失败'); - } - - try { - Db::beginTransaction(); - $oWalletCurrencyModel = (new WalletCurrencyModel())->findByToken($token); - if (!$oWalletCurrencyModel) { - Log::error('listenWalletAddrCallbackErr', ['token' => $token, 'addr' => $addr, 'amount' => $amount, 'status' => $status, 'error' => '币种不存在']); - throw new ModelException('币种不存在'); - } - //查找钱包地址 - $resModel = $this->findItemByWhere([ - 'currency_id' => $oWalletCurrencyModel->id, - 'addr' => $addr, - ]); - if (!$resModel) { - Log::error('listenWalletAddrCallbackErr', ['token' => $token, 'addr' => $addr, 'amount' => $amount, 'status' => $status, 'error' => '地址不存在']); - throw new ModelException('地址不存在'); - } - - if ($type == WalletAddrTransactionModel::TYPE_RECHARGE) { //充值到账 - $res = $this->incAvailableAmount($resModel->id, $amount); - } else { //提现到账 - //查询账变表提现记录中是否存在 - $oWalletAddrTransactionModel = new WalletAddrTransactionModel(); - $resWalletAddrTransactionModel = $oWalletAddrTransactionModel->findItemByWhere([ - 'wallet_addr_id' => $resModel->id, - 'type' => WalletAddrTransactionModel::TYPE_TRANSFER, - 'block_sn' => $chain_sn, - ]); - if ($resWalletAddrTransactionModel->status != WalletAddrTransactionModel::STATUS_WAITING_CHAIN_CALLBACK) { //已经处理过 - Log::error('listenWalletAddrCallbackErr', ['token' => $token, 'addr' => $addr, 'amount' => $amount, 'status' => $status, 'wallet_addr_id' => $resModel->id, 'wallet_transaction_id' => $resWalletAddrTransactionModel->id, 'error' => '该提现条目已经处理过']); - throw new ModelException('该提现条目已经处理过'); - } - if ($resWalletAddrTransactionModel) { //存在就扣除冻结金额 - $res = $resWalletAddrTransactionModel->platformUserWithdrawCallback($resModel->id,$amount,$status); - } else { //未找到就直接扣除余额 - $res = $this->decAvailableAmount($resModel->id, $amount); - } - } - - if (!$res) { - Log::error('listenWalletAddrCallbackErr', ['token' => $token, 'addr' => $addr, 'amount' => $amount, 'status' => $status, 'wallet_addr_id' => $resModel->id, 'error' => '修改地址余额失败']); - throw new ModelException('修改地址余额失败'); - } - - if ($type == WalletAddrTransactionModel::TYPE_TRANSFER && $resWalletAddrTransactionModel) { //提现已有账变,修改账变状态即可 - $updateItems = [ - 'id' => $resWalletAddrTransactionModel->id, - 'status' => $status, - ]; - if($status == WalletAddrTransactionModel::STATUS_SUCCESS){ - $updateItems['entered_amount'] = $amount; - $updateItems['fee_amount'] = Db::raw('received_amount - '.$amount); - } - $res = $oWalletAddrTransactionModel->updateItem($updateItems); - if (!$res) { - Log::error('listenWalletAddrCallbackErr', ['token' => $token, 'addr' => $addr, 'amount' => $amount, 'status' => $status, 'wallet_addr_id' => $resModel->id, 'wallet_transaction_id' => $resWalletAddrTransactionModel->id, 'error' => '修改账变状态失败']); - throw new ModelException('修改账变状态失败'); - } - } else { //充值和未记录的转账,增加到钱包账变记录 - $oWalletAddrTransactionModel = new WalletAddrTransactionModel(); - $res = $oWalletAddrTransactionModel->addTransaction($resModel->id, $type, WalletAddrTransactionModel::ROLE_SYSTEM, $status, $amount); - if (!$res) { - Log::error('listenWalletAddrCallbackErr', ['token' => $token, 'addr' => $addr, 'amount' => $amount, 'status' => $status, 'wallet_addr_id' => $resModel->id, 'error' => '增加到钱包账变记录失败']); - throw new ModelException('增加到钱包账变记录失败'); - } - } - //成功记录日志 - $log = ['token' => $token, 'addr' => $addr, 'amount' => $amount, 'status' => $status, 'wallet_addr_id' => $resModel->id, 'info' => '监听钱包处理成功']; - if (isset($resWalletAddrTransactionModel) && $resWalletAddrTransactionModel->id) $log['wallet_transaction_id'] = $resWalletAddrTransactionModel->id; - Log::info('listenWalletAddrCallbackSucc', $log); - - //投递到钱包账变队列 - self::putWalletAddrTransactionChangeQueue($resWalletAddrTransactionModel->id, $resWalletAddrTransactionModel->type); - - Db::commit(); - } catch (\Exception $e) { - Db::rollBack(); - throw $e; - } - } - - static function putWalletAddrTransactionChangeQueue($wallet_addr_transaction_id, $type): void - { - WalletAddrTransactionChangeQueue::dispatch([ - 'wallet_addr_transaction_id_id' => $wallet_addr_transaction_id, - 'wallet_addr_transaction_type' => $type, - ])->onQueue(QueueWalletAddrTransactionChangeStruct::QUEUE_NAME); - } - - function findWithdrawAddrWithAmount($amount, $currency_code = WalletCurrencyModel::CODE_USDT_TRC20): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|null - { - //获取当前系统使用中的热钱包 - $oModel = $this->findItemByWhere([ - 'currency_code' => $currency_code, - 'use_status' => self::USE_STATUS_USING, - 'role' => self::ROLE_SYSTEM, - ['available_amount', '>=', $amount] - ]); - if (!$oModel) throw new ModelException(ModelException::CODE[ModelException::CODE_WALLET_AMOUNT_ADDR_NOT_FOUND], ModelException::CODE_WALLET_AMOUNT_ADDR_NOT_FOUND); - if ($oModel->available_amount < $amount) throw new ModelException(ModelException::CODE[ModelException::CODE_WALLET_ADDR_BALANCE_LOW], ModelException::CODE_WALLET_ADDR_BALANCE_LOW); - return $oModel; - } - - - - //@@调用链上接口,发起转账,要返回链上交易订单号用于追踪并更新到数据库 - function callWalletAddrChainTransferApi($id, $wallet_addr_id): bool - { - return true; - } - - -} diff --git a/app/Models/Wallet/Wallet/WalletAddrTransactionModel.php b/app/Models/Wallet/Wallet/WalletAddrTransactionModel.php deleted file mode 100644 index ade1f55..0000000 --- a/app/Models/Wallet/Wallet/WalletAddrTransactionModel.php +++ /dev/null @@ -1,208 +0,0 @@ - '充值', - self::TYPE_TRANSFER => '转账', - self::TYPE_FROZEN => '冻结', - self::TYPE_UN_FROZEN => '解冻', - ]; - - const ROLE_USER = 1; - const ROLE_SYSTEM = 2; - const ROLE_ADMIN = 3; - const ROLE_OTHER = 4; - const ROLE = [ - self::ROLE_USER => '用户操作', - self::ROLE_SYSTEM => '系统操作', - self::ROLE_ADMIN => '管理员操作', - self::ROLE_OTHER => '其他操作', - ]; - - const STATUS_WAITING_CHAIN_CALLBACK = 1; - const STATUS_SUCCESS = 2; - const STATUS_FAIL = 3; - const STATUS = [ - self::STATUS_WAITING_CHAIN_CALLBACK => '等待链回调', - self::STATUS_SUCCESS => '成功', - self::STATUS_FAIL => '失败', - ]; - - const DESC_KEY_WITHDRAW_FROZEN = 'withdrawFrozen'; - const DESC_KEY_WITHDRAW_UN_FROZEN = 'withdrawUnFrozen'; - const DESC_KEY_WITHDRAW_DETECT = 'withdrawDetect'; - const DESC = [ - self::DESC_KEY_WITHDRAW_FROZEN => '提现冻结', - self::DESC_KEY_WITHDRAW_UN_FROZEN => '提现解冻', - self::DESC_KEY_WITHDRAW_DETECT => '提现成功扣除', - ]; - - //@@钱包账变处理 - - function addTransaction( - $wallet_addr_id, - $type, - $role, - $status, - $received_amount, - $entered_amount = null, - $fee_amount = null, - $desc_key = '', - $remark = '', - $platform_user_transaction_id = null, - ): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|bool - { - $entered_amount = abs($entered_amount); - - $oWalletAddrModel = new WalletAddrModel(); - $resWalletAddrModel = $oWalletAddrModel->findItem($wallet_addr_id); - - $received_amount = abs($received_amount); - if (empty($fee_amount)) $fee_amount = 0; - if (empty($entered_amount)) $entered_amount = Math::bcSub($received_amount, $fee_amount); - - $desc = ''; - if (!empty($desc_key) && isset(self::DESC[$desc_key])) $desc = self::DESC[$desc_key]; - - if ($type == self::TYPE_RECHARGE) { //充值 - $after_total_amount = Math::bcAdd($oWalletAddrModel->total_amount, $entered_amount); - } elseif ($type == self::TYPE_TRANSFER) { //转账 - $after_total_amount = Math::bcSub($oWalletAddrModel->total_amount, $entered_amount); - } elseif (in_array($type, [self::TYPE_FROZEN, self::TYPE_UN_FROZEN])) { //冻结/解冻 - $after_total_amount = $oWalletAddrModel->total_amount; - } else { - throw new ModelException('未知类型'); - } - - $insert = [ - 'type' => $type, - 'role' => $role, - 'status' => $status, - 'currency_id' => $resWalletAddrModel->currency_id, - 'currency_code' => $resWalletAddrModel->currency_code, - 'received_amount' => $received_amount, - 'entered_amount' => $entered_amount, - 'fee_amount' => $fee_amount, - 'before_total_amount' => $oWalletAddrModel->total_amount, - 'after_total_amount' => $after_total_amount, - 'desc_key' => $desc_key, - 'desc' => $desc, - 'remark' => $remark, - 'platform_user_transaction_id' => $platform_user_transaction_id, - ]; -// $insert['sign'] = ''; - $insert['created_at'] = Times::getNowDateTime(); - return $this->addItem($insert); - } - - //用户发起提现 - function newPlatformUserWithdraw( - $wallet_addr_id, - $received_amount, - $platform_user_transaction_id, - ): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|bool - { - try { - Db::beginTransaction(); - //查询钱包 - $oWalletAddrModel = new WalletAddrModel(); - $resWalletAddrModel = $oWalletAddrModel->findItem($wallet_addr_id); - if (!$resWalletAddrModel) return false; - - if (Math::bcComp($resWalletAddrModel->available_amount, $received_amount) == -1) throw new ModelException('余额不足'); - - //冻结钱包余额 - $res = $oWalletAddrModel->frozenAmountById($wallet_addr_id, $received_amount); - if (!$res) throw new ModelException('钱包余额冻结失败'); - - //增加钱包账变 - $res = $this->addTransaction( - $wallet_addr_id, - $type = self::TYPE_TRANSFER, - $role = self::ROLE_USER, - $status = self::STATUS_WAITING_CHAIN_CALLBACK, - $received_amount, - $entered_amount = null, - $fee_amount = null, - $desc_key = '', - $remark = '', - $platform_user_transaction_id, - ); - if (!$res) throw new ModelException('钱包账变失败'); - Db::commit(); - return $res; - } catch (\Exception $e) { - Db::rollBack(); - Log::error('newPlatformUserWithdraw', ['wallet_addr_id' => $wallet_addr_id, 'received_amount' => $received_amount, 'platform_user_transaction_id' => $platform_user_transaction_id, 'msg' => $e->getMessage()]); - return false; - } - } - - - function platformUserWithdrawCallback($wallet_transaction_id, $amount, $status) - { - if (!in_array($status, [self::STATUS_SUCCESS, self::STATUS_FAIL])) throw new ModelException('提现状态错误'); - $resModel = $this->findItem($wallet_transaction_id); - if (!$resModel) throw new ModelException('钱包账变不存在'); - $oWalletAddrModel = new WalletAddrModel(); - try { - Db::beginTransaction(); - if ($status == self::STATUS_SUCCESS) { - $res = $oWalletAddrModel->decFrozenAmountById($resModel->wallet_addr_id, $amount); - if (!$res) throw new ModelException('扣除冻结失败'); - } else if ($status == WalletAddrTransactionModel::STATUS_FAIL) { //失败就解冻金额 - $resModel->status = WalletAddrTransactionModel::STATUS_FAIL; - $res = $resModel->save(); - if (!$res) throw new ModelException('更新状态失败'); - $res = $oWalletAddrModel->unFrozenAmountById($resModel->id, $resModel->received_amount); - if (!$res) throw new ModelException('解冻失败'); - } - Db::commit(); - return true; - } catch (\Exception $e) { - Db::rollBack(); - Log::error('platformUserWithdrawCallback', ['wallet_transaction_id' => $wallet_transaction_id, 'amount' => $amount, 'status' => $status, 'msg' => $e->getMessage()]); - return false; - } - - } - -} diff --git a/app/Models/Wallet/Wallet/WalletAddressModel.php b/app/Models/Wallet/Wallet/WalletAddressModel.php new file mode 100644 index 0000000..25c3b82 --- /dev/null +++ b/app/Models/Wallet/Wallet/WalletAddressModel.php @@ -0,0 +1,146 @@ + '空闲', + self::USE_STATUS_USING => '使用中', + self::USE_STATUS_USED => '废弃', + ]; + + const ROLE_PLATFORM = 1; + const ROLE_SYSTEM = 2; + const ROLE = [ + self::ROLE_PLATFORM => '平台', + self::ROLE_SYSTEM => '系统', + ]; + + const ROLE_TAGS_WALLET= 1; + const ROLE_TAGS_WITHDRAW = 2; + const ROLE_TAGS_COLLECTION = 3; + const ROLE_TAGS = [ + self::ROLE_TAGS_WALLET => '钱包', + self::ROLE_TAGS_WITHDRAW => '提现', + self::ROLE_TAGS_COLLECTION => '归集', + ]; + + //查找空闲钱包地址 + function findFreeAddress($currency_code = WalletCurrencyModel::CODE_USDT_TRC20): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|null + { + return $this->newQuery() + ->where('use_status', self::USE_STATUS_FREE) + ->where('currency_code', $currency_code) + ->first(); + } + + + function findByAddressHex(string $sAddressHex, $currency_code = WalletCurrencyModel::CODE_USDT_TRC20): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection|\Illuminate\Database\Eloquent\Builder|array|null + { + return $this->findItemByWhere(['address_hex' => $sAddressHex, 'currency_code' => $currency_code]); + } + + function findByAddressBase58(string $sAddressBase58, $currency_code = WalletCurrencyModel::CODE_USDT_TRC20): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection|\Illuminate\Database\Eloquent\Builder|array|null + { + return $this->findItemByWhere(['address_base58' => $sAddressBase58, 'currency_code' => $currency_code]); + } + + function findByAddress(string $sAddress, $currency_code = WalletCurrencyModel::CODE_USDT_TRC20): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection|\Illuminate\Database\Eloquent\Builder|array|null + { + return $this->newQuery()->where('currency_code', $currency_code) + ->where(function ($query) use ($sAddress) { + $query->where('address_hex', $sAddress) + ->orWhere('address_base58', $sAddress); + }) + ->first(); + } + + function findWithdrawWallet($currency_code,$amount): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|null + { + $amount = abs($amount); + return $this->findItemByWhere([ + 'role' => self::ROLE_PLATFORM, + 'role_tags' => self::ROLE_TAGS_WITHDRAW, + 'currency_code' => $currency_code, + 'balance' => ['>=', $amount], + ]); + } + + function updateRoleTags($id, array $role_tags): bool|int + { + $tags_values = array_keys(self::ROLE_TAGS); + foreach ($role_tags as $val){ + if (!in_array($val, array_keys($tags_values))) return false; + } + $role_tags = array_unique($role_tags); + asort($role_tags); + $updateItem = [ + 'id' => $id, + 'role_tags' => implode(',', $role_tags), + ]; + return $this->updateItem($updateItem); + } + + function checkRoleTags(string $role_tag, array $aRoleTags): bool + { + asort($aRoleTags); + $tmp1 = implode(',', $aRoleTags); + return $tmp1 == $role_tag; + } + + function decodePrivateKey(string $private_key): string + { + return $private_key; + } + + + function subBalance($id, $amount): bool|int + { + $amount = abs($amount); + $updateItem = [ + 'id' => $id, + 'balance' => DB::raw('balance - '. $amount), + ]; + return $this->updateItem($updateItem); + } + + function addBalance($id, $amount): bool|int + { + $amount = abs($amount); + $updateItem = [ + 'id' => $id, + 'balance' => DB::raw('balance + '. $amount), + ]; + return $this->updateItem($updateItem); + } + + + + + + +} diff --git a/app/Models/Wallet/Wallet/WalletAddressTransactionModel.php b/app/Models/Wallet/Wallet/WalletAddressTransactionModel.php new file mode 100644 index 0000000..6a0a538 --- /dev/null +++ b/app/Models/Wallet/Wallet/WalletAddressTransactionModel.php @@ -0,0 +1,135 @@ + '转入', + self::TYPE_WITHDRAW => '转出', + ]; + + const IS_NOTIFY_WAIT = 1; + const IS_NOTIFY_PROCESS = 2; + const IS_NOTIFY_FINISH = 3; + const IS_NOTIFY_FAIL = 4; + const IS_NOTIFY = [ + self::IS_NOTIFY_WAIT => '待处理', + self::IS_NOTIFY_PROCESS => '处理中', + self::IS_NOTIFY_FINISH => '处理完成', + self::IS_NOTIFY_FAIL => '处理失败', + ]; + + function typeRecharge(WalletAddressTransactionBean &$bean): bool + { + //查重 + $oRes = $this->findByBlockTransactionId($bean->getBlockTransactionId(), WalletAddressTransactionModel::TYPE_RECHARGE); + if ($oRes) throw new ModelException('BlockTransactionId already exists'); + //根据value计算amount + if($bean->getBlockValue() == null) throw new ModelException('getBlockValue is required'); + $amount = Math::valueToAmount($bean->getBlockValue()); + $bean->setAmount(abs($amount)); + + try { + Db::beginTransaction(); + //增加交易记录 + $res = $this->addTransaction($bean); + if (!$res) throw new ModelException('addTransaction error'); + $bean->setId($res->id); + //增加钱包地址余额 + $oWalletAddressModel = new WalletAddressModel(); + $resWalletAddressModel = $oWalletAddressModel->findItem($bean->getWalletAddressId()); + if(!$resWalletAddressModel) throw new ModelException('WalletAddressModel findItem error'); + $res = $oWalletAddressModel->addBalance($resWalletAddressModel->id, $bean->getAmount()); + if (!$res) throw new ModelException('WalletAddressModel addBalance error'); + + Db::commit(); + Logs::SuccLog(__FUNCTION__, $bean->toArrayNotNull()); + return true; + }catch (\Exception $e){ + Db::rollBack(); + Logs::ErrLog('typeRecharge error rollBack', $e, $bean->toArrayNotNull()); + return false; + } + } + + function typeWithdraw(WalletAddressTransactionBean $bean) + { + //查重 + $oRes = $this->findByBlockTransactionId($bean->getBlockTransactionId(), WalletAddressTransactionModel::TYPE_WITHDRAW); + if ($oRes) throw new ModelException('BlockTransactionId already exists'); + //根据value计算amount + if($bean->getBlockValue() == null) throw new ModelException('getBlockValue is required'); + $amount = Math::valueToAmount($bean->getBlockValue()); + $bean->setAmount(-abs($amount)); + + try { + Db::beginTransaction(); + //增加交易记录 + $res = $this->addTransaction($bean); + if (!$res) throw new ModelException('addTransaction error'); + //扣除钱包地址余额 + $oWalletAddressModel = new WalletAddressModel(); + $resWalletAddressModel = $oWalletAddressModel->findItem($bean->getWalletAddressId()); + if(!$resWalletAddressModel) throw new ModelException('WalletAddressModel findItem error'); + $res = $oWalletAddressModel->subBalance($resWalletAddressModel->id, $bean->getAmount()); + if (!$res) throw new ModelException('WalletAddressModel addBalance error'); + + Db::commit(); + Logs::SuccLog(__FUNCTION__, $bean->toArrayNotNull()); + return true; + }catch (\Exception $e){ + Db::rollBack(); + Logs::ErrLog('typeRecharge error rollBack', $e, $bean->toArrayNotNull()); + return false; + } + + } + + function addTransaction(WalletAddressTransactionBean &$bean): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Builder|bool + { + if (!$bean->getWalletAddressId()) throw new ModelException('getWalletAddressId is required'); + if (!$bean->getType()) throw new ModelException('type is required'); + + $bean->setCreatedAt(Times::getNowDateTime()); + return $this->addItem($bean->toArrayNotNull()); + } + + function findByBlockTransactionId(string $tid,$type): \Illuminate\Database\Eloquent\Model|\Illuminate\Database\Eloquent\Collection|\Illuminate\Database\Eloquent\Builder|array|null + { + if(!in_array($type,[self::TYPE_RECHARGE,self::TYPE_WITHDRAW])) throw new ModelException('type error'); + return $this->findItemByWhere(['block_transaction_id' => $tid,'type' => $type]); + } + + + +} diff --git a/app/Service/Coin/Tron/UsdtTrx20Service.php b/app/Service/Coin/Tron/UsdtTrx20Service.php new file mode 100644 index 0000000..ee97e2d --- /dev/null +++ b/app/Service/Coin/Tron/UsdtTrx20Service.php @@ -0,0 +1,228 @@ +usdtTrc20Sdk = new UsdtTrc20(); + } + + function getHandle(): \Sdk\Wallet\Trc20Sdk + { + return $this->usdtTrc20Sdk->getHandler(); + } + + //定时请求当前区块比对redis中当前区块,差值存入队列 + function checkNowBlock(): void + { + $oNowBlockBean = $this->getHandle()->getNowBlockNumber(); + //查询redis中当前区块 + $oTronKeyCache = new TronKeyCache(); + $sLocalNowBlock = $oTronKeyCache->getNowBlock(); + if (empty($sLocalNowBlock)) { //不存在就从数据库中取 + $oWalletTronBlockModel = new WalletTronBlockModel(); + $sLocalNowBlock = $oWalletTronBlockModel->getLastBlockNumber(); + if (!empty($sLocalNowBlock)) $oTronKeyCache->setNowBlock($sLocalNowBlock); + } + + $oWalletTronBlockModel = new WalletTronBlockModel(); + //如果都不存在,就直接投递到队列 + if (empty($sLocalNowBlock)) { + $res = $oWalletTronBlockModel->insertByBlockNum($oNowBlockBean->getBlockNumber()); + if (!$res) return; + $oQueueWalletBlockBean = new QueueWalletBlockBean(); + $oQueueWalletBlockBean->setId($res->id); + $oQueueWalletBlockBean->setBlockNumber($oNowBlockBean->getBlockNumber()); + WalletBlockQueue::putToQueue($oQueueWalletBlockBean); + return; + } + + //如果相等获取大于,就不处理 + if ($sLocalNowBlock >= $oNowBlockBean->getBlockNumber()) { + return; + } + + //如果不相等,获取差值一个个投递到队列 + for ($i = $sLocalNowBlock + 1; $i <= $oNowBlockBean->getBlockNumber(); $i++) { + $res = $oWalletTronBlockModel->insertByBlockNum($i); + if (!$res) continue; + $oQueueWalletBlockBean = new QueueWalletBlockBean(); + $oQueueWalletBlockBean->setId($res->id); + $oQueueWalletBlockBean->setBlockNumber($i); + WalletBlockQueue::putToQueue($oQueueWalletBlockBean); + } + } + + //监听处理区块 + public function tronBlockConsumer(QueueWalletBlockBean $oQueueWalletBlockBean): void + { + $oWalletTronBlockModel = new WalletTronBlockModel(); + $oResModel = $oWalletTronBlockModel->findItem($oQueueWalletBlockBean->getId()); + if (!$oResModel) throw new QueueException('区块不存在'); + if ($oResModel->status != WalletTronBlockModel::STATUS_WAIT) return; + $oResModel->status = WalletTronBlockModel::STATUS_PROCESS; + $oResModel->save(); + + $blockNumber = $oQueueWalletBlockBean->getBlockNumber(); + $fingerprint = null; + + try { + //循环获取区块所有转账信息 + while (true) { + $oResponseBean = $this->getHandle()->getTrc20BlockEventsTransferByBlockNumber($blockNumber, $fingerprint); + if ($oResponseBean === false) throw new QueueException('获取区块信息失败'); + if (empty($oResponseBean)) break; + if ($oResponseBean->getSuccess() === false) break; + $fingerprint = $oResponseBean->getMeta()->getFingerprint(); + if (empty($oResponseBean->getData())) break; + //投递到区块账变队列 + $oQueueWalletBlockTransactionBean = new QueueWalletBlockTransactionBean(); + $oQueueWalletBlockTransactionBean->setData($oResponseBean->getData()); + WalletBlockTransactionQueue::putToQueue($oQueueWalletBlockTransactionBean); + + if (empty($fingerprint)) break; + } + $updateItem = [ + 'id' => $oResModel->id, + 'status' => WalletTronBlockModel::STATUS_FINISH, + ]; + $oWalletTronBlockModel->updateItem($updateItem); + + } catch (\Exception $e) { + Logs::ErrLog(__FUNCTION__, $e, $oQueueWalletBlockBean->toArray()); + $oQueueWalletBlockBean->IncrTryTimes(); + if (!$oQueueWalletBlockBean->checkTryTimes()) { //超出重试次数 + $updateItem = [ + 'id' => $oResModel->id, + 'status' => WalletTronBlockModel::STATUS_FAIL, + ]; + $oWalletTronBlockModel->updateItem($updateItem); + return; + } + WalletBlockQueue::putToQueue($oQueueWalletBlockBean, 30); + } + + } + + //监听处理区块每笔合约交易 + public function tronBlockTransactionConsumer(QueueWalletBlockTransactionBean $oQueueWalletBlockTransactionBean): void + { + $aBlockEvents = $oQueueWalletBlockTransactionBean->getData(); + foreach ($aBlockEvents as $item) { + $oEventBean = new EventBean($item); + try { + $this->tronBlockTransaction($oEventBean); + } catch (\Exception $e) { + Logs::ErrLog(__FUNCTION__, $e, $oEventBean->toArray()); + } + } + } + + //监听处理单个合约交易 + function tronBlockTransaction(EventBean $oEventBean): void + { + //检查合约 + if ($oEventBean->getContractAddress() != UsdtTrc20::CONTRACT_ADDRESS) return; + + $from_addr = $oEventBean->getResult()->getFrom(); + $to_addr = $oEventBean->getResult()->getTo(); + $value = $oEventBean->getResult()->getValue(); + + //检查交易双方是否是平台地址 + $oTronWalletAddressSetCache = new TronWalletAddressSetCache(); + $is_from = $oTronWalletAddressSetCache->checkKey($from_addr); + $is_to = $oTronWalletAddressSetCache->checkKey($to_addr); + if (!$is_from && !$is_to) return; + //投递到钱包地址账变处理队列 + $oQueueEventBean = new QueueEventBean($oEventBean->toArray()); + WalletAddressTransactionQueue::putToQueue($oQueueEventBean); + return; + } + + //用户钱包地址交易账变处理 + function walletAddressTransactionConsumer(QueueEventBean $bean): void + { + try { + $from_addr = $bean->getResult()->getFrom(); + $to_addr = $bean->getResult()->getTo(); + $value = $bean->getResult()->getValue(); + + //查询地址是否存在 + $oWalletAddressModel = new WalletAddressModel(); + $resFromModel = $oWalletAddressModel->findByAddressHex($from_addr, WalletCurrencyModel::CODE_USDT_TRC20); + $resToModel = $oWalletAddressModel->findByAddressHex($to_addr, WalletCurrencyModel::CODE_USDT_TRC20); + if (!$resFromModel && !$resToModel) return; + + //先落地到数据库 + $oWalletAddressTransactionModel = new WalletAddressTransactionModel(); + $oWalletAddressTransactionBean = new WalletAddressTransactionBean(); + $oWalletAddressTransactionBean->setCurrencyCode(WalletCurrencyModel::CODE_USDT_TRC20); + $oWalletAddressTransactionBean->setBlockTransactionId($bean->getTransactionId()); + $oWalletAddressTransactionBean->setBlockNumber($bean->getBlockNumber()); + $oWalletAddressTransactionBean->setBlockEventName($bean->getEventName()); + $oWalletAddressTransactionBean->setBlockFromAddress($bean->getResult()->getFrom()); + $oWalletAddressTransactionBean->setBlockToAddress($bean->getResult()->getTo()); + $oWalletAddressTransactionBean->setBlockValue($bean->getResult()->getValue()); + $oWalletAddressTransactionBean->setIsNotify(WalletAddressTransactionModel::IS_NOTIFY_WAIT); + + if ($resToModel) { //充值 + $oWalletAddressTransactionBean->setType(WalletAddressTransactionModel::TYPE_RECHARGE); + $oWalletAddressTransactionBean->setWalletAddressId($resToModel->id); + $resRecharge = $oWalletAddressTransactionModel->typeRecharge($oWalletAddressTransactionBean); + if (!$resRecharge) throw new QueueException('WalletAddressTransactionModel addTransaction recharge error'); + //投递到处理平台用户账变队列 + $this->addToQueue($oWalletAddressTransactionBean); + } + if ($resFromModel) { //提现 + $oWalletAddressTransactionBean->setType(WalletAddressTransactionModel::TYPE_WITHDRAW); + $oWalletAddressTransactionBean->setWalletAddressId($resFromModel->id); + $resWithdraw = $oWalletAddressTransactionModel->typeWithdraw($oWalletAddressTransactionBean); + if (!$resWithdraw) throw new QueueException('WalletAddressTransactionModel addTransaction withdraw error'); + //投递到处理平台用户账变队列 + $this->addToQueue($oWalletAddressTransactionBean); + } + + } catch (\Exception $e) { + Logs::ErrLog(__FUNCTION__, $e, $bean->toArrayNotNull()); + $bean->IncrTryTimes(); + if($bean->checkTryTimes()) return; + WalletAddressTransactionQueue::putToQueue($bean, 30); + } + } + + + function addToQueue(WalletAddressTransactionBean $bean): void + { + $oQueueWalletPlatformTransactionBean = new QueueWalletPlatformTransactionBean(); + $oQueueWalletPlatformTransactionBean->setWalletId($bean->getWalletAddressId()); + $oQueueWalletPlatformTransactionBean->setWalletTransactionId($bean->getId()); + $oQueueWalletPlatformTransactionBean->setBlockTransactionId($bean->getBlockTransactionId()); + $oQueueWalletPlatformTransactionBean->setAmount($bean->getAmount()); + $oQueueWalletPlatformTransactionBean->setType($bean->getType()); + WalletPlatformTransactionQueue::putToQueue($oQueueWalletPlatformTransactionBean); + } +} diff --git a/app/Service/PlatformRechargeService.php b/app/Service/PlatformRechargeService.php new file mode 100644 index 0000000..d256b44 --- /dev/null +++ b/app/Service/PlatformRechargeService.php @@ -0,0 +1,31 @@ +findItem($bean->getWalletId()); + if (!$resBindModel) throw new QueueException('钱包不存在'); + $oWalletPlatformBalanceTransactionModel = new WalletPlatformBalanceTransactionModel(); + $res = $oWalletPlatformBalanceTransactionModel->typeRecharge( + $resBindModel->platform_id, + $resBindModel->uid, + $resBindModel->currency_code, + $bean->getAmount(), + $bean->getWalletId(), + $bean->getBlockTransactionId(), + $bean->getWalletTransactionId() + ); + if (!$res) throw new QueueException('typeRecharge fail'); + } + +} diff --git a/app/Service/PlatformWithdrawService.php b/app/Service/PlatformWithdrawService.php new file mode 100644 index 0000000..3caa39e --- /dev/null +++ b/app/Service/PlatformWithdrawService.php @@ -0,0 +1,130 @@ +findItem($bean->getTransactionId()); + if (!$resModel) throw new QueueException('账变不存在'); + if($resModel->status != WalletPlatformBalanceTransactionModel::STATUS_WAIT) throw new QueueException('账变状态不正确'); + + //更新账变状态 + $updateItem = [ + 'id' => $bean->getTransactionId(), + 'status' => WalletPlatformBalanceTransactionModel::STATUS_PROCESSING, + 'updated_at' => Times::getNowDateTime(), + ]; + $res = $oWalletPlatformBalanceTransactionModel->updateItem($updateItem); + if (!$res) throw new QueueException('更新账变状态失败'); + $currency_code = $resModel->currency_code; + //提现 + try { + //根据币种调用不同的提现方法 + switch ($currency_code) { + case WalletCurrencyModel::CODE_USDT_TRC20: //提现USDT + + $txId = $this->withdrawUsdtTrc20($resModel); + + break; + default: + throw new QueueException('不支持的币种'); + } + + + Logs::SuccLog(__FUNCTION__, $bean->toArrayNotNull()); + }catch (\Exception $e){ + //更新账变状态 + $updateItem = [ + 'id' => $bean->getTransactionId(), + 'status' => WalletPlatformBalanceTransactionModel::STATUS_FAIL, + 'updated_at' => Times::getNowDateTime(), + ]; + $oWalletPlatformBalanceTransactionModel->updateItem($updateItem); + Logs::ErrLog(__FUNCTION__ . ' ' . 'rollBack', $e, $bean->toArrayNotNull()); + throw new QueueException($e->getMessage()); + } + } + + function withdrawUsdtTrc20($model): string + { + try { + DB::beginTransaction(); + $oWalletAddressModel = new WalletAddressModel(); + //获取出金地址 + $resFromModel = $oWalletAddressModel->findWithdrawWallet($model->currency_code, $model->amount); + if(!$resFromModel) throw new QueueException('提现地址不足'); + $from_wallet_address_id = $resFromModel->id; + $from_wallet_address = $resFromModel->address_base58; + + //获取入金地址 + $to_wallet_address = $model->to_wallet_address; + if(!empty($to_wallet_address)) throw new QueueException('平台钱包id错误'); + + $fromAddress = new TokenAddress($resFromModel->address_base58, $oWalletAddressModel->decodePrivateKey($resFromModel->private_key)); + $toAddress = new TokenAddress($to_wallet_address); + $amount = abs($model->amount); + + //调用sdk发起提现 + $sdk = new UsdtTrc20(); + $oTransferTransactionBean = $sdk->getHandler()->trc20Transfer($fromAddress,$toAddress, $amount); + if(!$oTransferTransactionBean) throw new QueueException('提现sdk发起失败'); + if(empty($oTransferTransactionBean->getTxID())) throw new QueueException('提现sdk发起失败'); + + //存储交易id + $updateItem = [ + 'id' => $model->id, + 'block_transaction_id' => $oTransferTransactionBean->getTxID(), + 'from_wallet_address_id' => $from_wallet_address_id, + 'from_wallet_address' => $from_wallet_address, + 'updated_at' => Times::getNowDateTime(), + ]; + $oWalletPlatformBalanceTransactionModel = new WalletPlatformBalanceTransactionModel(); + $res = $oWalletPlatformBalanceTransactionModel->updateItem($updateItem); + if(!$res) throw new QueueException('更新账变失败'); + + DB::commit(); + return $oTransferTransactionBean->getTxID(); + }catch (\Exception $e){ + DB::rollBack(); + throw new QueueException($e->getMessage()); + } + + } + + function walletPlatformTransactionConsumer(QueueWalletPlatformTransactionBean $bean): void + { + //根据txid查找平台和用户 + $oWalletPlatformBindModel = new WalletPlatformBindModel(); + $resBindModel = $oWalletPlatformBindModel->findItem($bean->getWalletId()); + if (!$resBindModel) throw new QueueException('钱包不存在'); + $oWalletPlatformBalanceTransactionModel = new WalletPlatformBalanceTransactionModel(); + $resModel = $oWalletPlatformBalanceTransactionModel->findByBlockTransactionId($bean->getBlockTransactionId(), WalletPlatformBalanceTransactionModel::TYPE_WITHDRAW_DEC); + if (!$resModel) throw new QueueException('账变不存在'); + if($resModel->status != WalletPlatformBalanceTransactionModel::STATUS_PROCESSING) throw new QueueException('账变状态不正确'); + + $res = $oWalletPlatformBalanceTransactionModel->typeWithdrawSecondCallback( + $resModel->id, + WalletPlatformBalanceTransactionModel::STATUS_SUCCESS, + null, + $bean->getWalletTransactionId(), + ); + if (!$res) throw new QueueException('typeWithdrawSecondCallback fail'); + } + +} diff --git a/app/Tools/Math.php b/app/Tools/Math.php index b501134..5170b38 100644 --- a/app/Tools/Math.php +++ b/app/Tools/Math.php @@ -6,6 +6,8 @@ class Math const SCALE = 8; const SCALE_4 = 4; const SCALE_6= 6; + const SCALE_8= 8; + const DECIMAL_6= 6; static function bcMul($a1,$a2,$scale = self::SCALE): string { return bcmul($a1,$a2,$scale); @@ -26,6 +28,17 @@ class Math return bccomp($a1,$a2,$scale); } + static function valueToAmount($amount,$decimal = self::DECIMAL_6,$scale = self::SCALE_8): string + { + return (float) bcdiv((string)$amount, '1e'.$decimal, $scale); + } + + static function amountToValue($amount,$decimal = self::DECIMAL_6): string + { + return (float) bcmul((string)$amount, '1e'.$decimal,0); + } + + } diff --git a/app/Tools/Tools.php b/app/Tools/Tools.php index 8814074..52884d4 100644 --- a/app/Tools/Tools.php +++ b/app/Tools/Tools.php @@ -1,6 +1,7 @@ address2HexString($hex); + } + + static function base58ToHex(string $base58): string + { + return (new TronTools)->hexString2Address($base58); + } +} diff --git a/composer.json b/composer.json index 6c12671..696eaf1 100644 --- a/composer.json +++ b/composer.json @@ -10,9 +10,11 @@ "require": { "php": "^8.1", "ext-bcmath": "*", + "ext-gmp": "*", "easyswoole/spl": "^2.1", "godruoyi/php-snowflake": "^3.0", "guzzlehttp/guzzle": "^7.8", + "iexbase/tron-api": "^5.0", "laravel/framework": "^10.10", "laravel/sanctum": "^3.3", "laravel/tinker": "^2.8" @@ -30,7 +32,8 @@ "psr-4": { "App\\": "app/", "Database\\Factories\\": "database/factories/", - "Database\\Seeders\\": "database/seeders/" + "Database\\Seeders\\": "database/seeders/", + "Sdk\\": "sdk/" } }, "autoload-dev": { diff --git a/composer.lock b/composer.lock index 551d959..7cdb2e2 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "8d1357294fac8e18aa387c5c5f295c8e", + "content-hash": "eb2ef8d7d9bc89ca893bb6f81e8a32ab", "packages": [ { "name": "brick/math", @@ -130,6 +130,54 @@ ], "time": "2023-12-10T15:33:53+00:00" }, + { + "name": "comely-io/data-types", + "version": "1.0.34", + "source": { + "type": "git", + "url": "https://github.com/comely-io/data-types.git", + "reference": "833ecf364a99aa5cd161e0ebd1191860921834c6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/comely-io/data-types/zipball/833ecf364a99aa5cd161e0ebd1191860921834c6", + "reference": "833ecf364a99aa5cd161e0ebd1191860921834c6", + "shasum": "" + }, + "require": { + "ext-bcmath": "*", + "ext-mbstring": "*", + "php": "^7.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Comely\\DataTypes\\": [ + "src" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Furqan A. Siddiqui", + "email": "hello@furqansiddiqui.com", + "homepage": "https://www.furqansiddiqui.com", + "role": "Author" + } + ], + "description": "PHP data types", + "homepage": "https://github.com/comely-io/data-types", + "support": { + "issues": "https://github.com/comely-io/data-types/issues", + "source": "https://github.com/comely-io/data-types/tree/master" + }, + "abandoned": true, + "time": "2020-06-07T14:02:53+00:00" + }, { "name": "dflydev/dot-access-data", "version": "v3.0.2", @@ -556,6 +604,82 @@ ], "time": "2023-10-06T06:47:41+00:00" }, + { + "name": "fgrosse/phpasn1", + "version": "v2.5.0", + "source": { + "type": "git", + "url": "https://github.com/fgrosse/PHPASN1.git", + "reference": "42060ed45344789fb9f21f9f1864fc47b9e3507b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fgrosse/PHPASN1/zipball/42060ed45344789fb9f21f9f1864fc47b9e3507b", + "reference": "42060ed45344789fb9f21f9f1864fc47b9e3507b", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "php-coveralls/php-coveralls": "~2.0", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" + }, + "suggest": { + "ext-bcmath": "BCmath is the fallback extension for big integer calculations", + "ext-curl": "For loading OID information from the web if they have not bee defined statically", + "ext-gmp": "GMP is the preferred extension for big integer calculations", + "phpseclib/bcmath_compat": "BCmath polyfill for servers where neither GMP nor BCmath is available" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "FG\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Friedrich Große", + "email": "friedrich.grosse@gmail.com", + "homepage": "https://github.com/FGrosse", + "role": "Author" + }, + { + "name": "All contributors", + "homepage": "https://github.com/FGrosse/PHPASN1/contributors" + } + ], + "description": "A PHP Framework that allows you to encode and decode arbitrary ASN.1 structures using the ITU-T X.690 Encoding Rules.", + "homepage": "https://github.com/FGrosse/PHPASN1", + "keywords": [ + "DER", + "asn.1", + "asn1", + "ber", + "binary", + "decoding", + "encoding", + "x.509", + "x.690", + "x509", + "x690" + ], + "support": { + "issues": "https://github.com/fgrosse/PHPASN1/issues", + "source": "https://github.com/fgrosse/PHPASN1/tree/v2.5.0" + }, + "abandoned": true, + "time": "2022-12-19T11:08:26+00:00" + }, { "name": "fruitcake/php-cors", "version": "v1.3.0", @@ -1163,6 +1287,203 @@ ], "time": "2023-12-03T19:50:20+00:00" }, + { + "name": "iexbase/tron-api", + "version": "v5.0", + "source": { + "type": "git", + "url": "https://github.com/iexbase/tron-api.git", + "reference": "45b01d8a562a2445c307df3b2f233473d970755b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/iexbase/tron-api/zipball/45b01d8a562a2445c307df3b2f233473d970755b", + "reference": "45b01d8a562a2445c307df3b2f233473d970755b", + "shasum": "" + }, + "require": { + "comely-io/data-types": "^1.0", + "ext-bcmath": "*", + "ext-json": "*", + "guzzlehttp/guzzle": "^7.2", + "iexbase/web3.php": "^2.0.1", + "kornrunner/secp256k1": "^0.2", + "php": ">=8.0", + "simplito/elliptic-php": "^1.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "IEXBase\\TronAPI\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Shamsudin Serderov", + "email": "steein.shamsudin@gmail.com" + } + ], + "description": "A PHP API for interacting with Tron (Trx)", + "homepage": "https://github.com/iexbase/tron-api", + "keywords": [ + "iexbase", + "tron-api", + "tron-lib", + "tron-php", + "tron-rest-api" + ], + "support": { + "issues": "https://github.com/iexbase/tron-api/issues", + "source": "https://github.com/iexbase/tron-api/tree/v5.0" + }, + "time": "2022-10-18T15:21:26+00:00" + }, + { + "name": "iexbase/web3.php", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/iexbase/web3.php.git", + "reference": "f25ed954a7586ead86046dd7e02a333a8098511b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/iexbase/web3.php/zipball/f25ed954a7586ead86046dd7e02a333a8098511b", + "reference": "f25ed954a7586ead86046dd7e02a333a8098511b", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "guzzlehttp/guzzle": "^7.0", + "kornrunner/keccak": "~1.0", + "php": "^7.1", + "phpseclib/phpseclib": "~2.0.11" + }, + "require-dev": { + "phpunit/phpunit": "~6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Web3\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Ethereum web3 interface.", + "support": { + "source": "https://github.com/iexbase/web3.php/tree/2.0.1" + }, + "time": "2020-10-15T18:16:13+00:00" + }, + { + "name": "kornrunner/keccak", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/kornrunner/php-keccak.git", + "reference": "433749d28e117fb97baf9f2631b92b5d9ab3c890" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kornrunner/php-keccak/zipball/433749d28e117fb97baf9f2631b92b5d9ab3c890", + "reference": "433749d28e117fb97baf9f2631b92b5d9ab3c890", + "shasum": "" + }, + "require": { + "php": ">=7.3", + "symfony/polyfill-mbstring": "^1.8" + }, + "require-dev": { + "phpunit/phpunit": "^8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "kornrunner\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Boris Momcilovic", + "homepage": "https://github.com/kornrunner/php-keccak" + } + ], + "description": "Pure PHP implementation of Keccak", + "keywords": [ + "keccak", + "sha-3", + "sha3-256" + ], + "support": { + "issues": "https://github.com/kornrunner/php-keccak/issues", + "source": "https://github.com/kornrunner/php-keccak/tree/1.1.0" + }, + "time": "2020-12-07T15:40:44+00:00" + }, + { + "name": "kornrunner/secp256k1", + "version": "0.2.0", + "source": { + "type": "git", + "url": "https://github.com/kornrunner/php-secp256k1.git", + "reference": "c3990dba47c7a8b0c9fd858fb29c61a5794fbb39" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kornrunner/php-secp256k1/zipball/c3990dba47c7a8b0c9fd858fb29c61a5794fbb39", + "reference": "c3990dba47c7a8b0c9fd858fb29c61a5794fbb39", + "shasum": "" + }, + "require": { + "mdanter/ecc": "^1", + "php": ">=7.3" + }, + "require-dev": { + "phpunit/phpunit": "^9" + }, + "type": "library", + "autoload": { + "psr-4": { + "kornrunner\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Boris Momčilović", + "email": "boris.momcilovic@gmail.com" + } + ], + "description": "Pure PHP secp256k1", + "keywords": [ + "curve", + "ecc", + "elliptic", + "secp256k1" + ], + "support": { + "issues": "https://github.com/kornrunner/php-secp256k1/issues", + "source": "https://github.com/kornrunner/php-secp256k1/tree/0.2.0" + }, + "time": "2021-01-19T03:30:01+00:00" + }, { "name": "laravel/framework", "version": "v10.37.3", @@ -2011,6 +2332,82 @@ ], "time": "2023-10-17T14:13:20+00:00" }, + { + "name": "mdanter/ecc", + "version": "v1.0.0", + "source": { + "type": "git", + "url": "https://github.com/phpecc/phpecc.git", + "reference": "34e2eec096bf3dcda814e8f66dd91ae87a2db7cd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpecc/phpecc/zipball/34e2eec096bf3dcda814e8f66dd91ae87a2db7cd", + "reference": "34e2eec096bf3dcda814e8f66dd91ae87a2db7cd", + "shasum": "" + }, + "require": { + "ext-gmp": "*", + "fgrosse/phpasn1": "^2.0", + "php": "^7.0||^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^6.0||^8.0||^9.0", + "squizlabs/php_codesniffer": "^2.0", + "symfony/yaml": "^2.6|^3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Mdanter\\Ecc\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Matyas Danter", + "homepage": "http://matejdanter.com/", + "role": "Author" + }, + { + "name": "Thibaud Fabre", + "email": "thibaud@aztech.io", + "homepage": "http://aztech.io", + "role": "Maintainer" + }, + { + "name": "Thomas Kerin", + "email": "afk11@users.noreply.github.com", + "role": "Maintainer" + } + ], + "description": "PHP Elliptic Curve Cryptography library", + "homepage": "https://github.com/phpecc/phpecc", + "keywords": [ + "Diffie", + "ECDSA", + "Hellman", + "curve", + "ecdh", + "elliptic", + "nistp192", + "nistp224", + "nistp256", + "nistp384", + "nistp521", + "phpecc", + "secp256k1", + "secp256r1" + ], + "support": { + "issues": "https://github.com/phpecc/phpecc/issues", + "source": "https://github.com/phpecc/phpecc/tree/v1.0.0" + }, + "time": "2021-01-16T19:42:14+00:00" + }, { "name": "monolog/monolog", "version": "3.5.0", @@ -2584,6 +2981,116 @@ ], "time": "2023-11-12T21:59:55+00:00" }, + { + "name": "phpseclib/phpseclib", + "version": "2.0.47", + "source": { + "type": "git", + "url": "https://github.com/phpseclib/phpseclib.git", + "reference": "b7d7d90ee7df7f33a664b4aea32d50a305d35adb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/b7d7d90ee7df7f33a664b4aea32d50a305d35adb", + "reference": "b7d7d90ee7df7f33a664b4aea32d50a305d35adb", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "require-dev": { + "phing/phing": "~2.7", + "phpunit/phpunit": "^4.8.35|^5.7|^6.0|^9.4", + "squizlabs/php_codesniffer": "~2.0" + }, + "suggest": { + "ext-gmp": "Install the GMP (GNU Multiple Precision) extension in order to speed up arbitrary precision integer arithmetic operations.", + "ext-libsodium": "SSH2/SFTP can make use of some algorithms provided by the libsodium-php extension.", + "ext-mcrypt": "Install the Mcrypt extension in order to speed up a few other cryptographic operations.", + "ext-openssl": "Install the OpenSSL extension in order to speed up a wide variety of cryptographic operations.", + "ext-xml": "Install the XML extension to load XML formatted public keys." + }, + "type": "library", + "autoload": { + "files": [ + "phpseclib/bootstrap.php" + ], + "psr-4": { + "phpseclib\\": "phpseclib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jim Wigginton", + "email": "terrafrost@php.net", + "role": "Lead Developer" + }, + { + "name": "Patrick Monnerat", + "email": "pm@datasphere.ch", + "role": "Developer" + }, + { + "name": "Andreas Fischer", + "email": "bantu@phpbb.com", + "role": "Developer" + }, + { + "name": "Hans-Jürgen Petrich", + "email": "petrich@tronic-media.com", + "role": "Developer" + }, + { + "name": "Graham Campbell", + "email": "graham@alt-three.com", + "role": "Developer" + } + ], + "description": "PHP Secure Communications Library - Pure-PHP implementations of RSA, AES, SSH2, SFTP, X.509 etc.", + "homepage": "http://phpseclib.sourceforge.net", + "keywords": [ + "BigInteger", + "aes", + "asn.1", + "asn1", + "blowfish", + "crypto", + "cryptography", + "encryption", + "rsa", + "security", + "sftp", + "signature", + "signing", + "ssh", + "twofish", + "x.509", + "x509" + ], + "support": { + "issues": "https://github.com/phpseclib/phpseclib/issues", + "source": "https://github.com/phpseclib/phpseclib/tree/2.0.47" + }, + "funding": [ + { + "url": "https://github.com/terrafrost", + "type": "github" + }, + { + "url": "https://www.patreon.com/phpseclib", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpseclib/phpseclib", + "type": "tidelift" + } + ], + "time": "2024-02-26T04:55:38+00:00" + }, { "name": "psr/clock", "version": "1.0.0", @@ -3301,6 +3808,153 @@ ], "time": "2023-11-08T05:53:05+00:00" }, + { + "name": "simplito/bigint-wrapper-php", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/simplito/bigint-wrapper-php.git", + "reference": "cf21ec76d33f103add487b3eadbd9f5033a25930" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/simplito/bigint-wrapper-php/zipball/cf21ec76d33f103add487b3eadbd9f5033a25930", + "reference": "cf21ec76d33f103add487b3eadbd9f5033a25930", + "shasum": "" + }, + "type": "library", + "autoload": { + "psr-4": { + "BI\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Simplito Team", + "email": "s.smyczynski@simplito.com", + "homepage": "https://simplito.com" + } + ], + "description": "Common interface for php_gmp and php_bcmath modules", + "support": { + "issues": "https://github.com/simplito/bigint-wrapper-php/issues", + "source": "https://github.com/simplito/bigint-wrapper-php/tree/1.0.0" + }, + "time": "2018-02-27T12:38:08+00:00" + }, + { + "name": "simplito/bn-php", + "version": "1.1.4", + "source": { + "type": "git", + "url": "https://github.com/simplito/bn-php.git", + "reference": "83446756a81720eacc2ffb87ff97958431451fd6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/simplito/bn-php/zipball/83446756a81720eacc2ffb87ff97958431451fd6", + "reference": "83446756a81720eacc2ffb87ff97958431451fd6", + "shasum": "" + }, + "require": { + "simplito/bigint-wrapper-php": "~1.0.0" + }, + "require-dev": { + "phpunit/phpunit": "*" + }, + "type": "library", + "autoload": { + "psr-4": { + "BN\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Simplito Team", + "email": "s.smyczynski@simplito.com", + "homepage": "https://simplito.com" + } + ], + "description": "Big number implementation compatible with bn.js", + "support": { + "issues": "https://github.com/simplito/bn-php/issues", + "source": "https://github.com/simplito/bn-php/tree/1.1.4" + }, + "time": "2024-01-10T16:16:59+00:00" + }, + { + "name": "simplito/elliptic-php", + "version": "1.0.12", + "source": { + "type": "git", + "url": "https://github.com/simplito/elliptic-php.git", + "reference": "be321666781be2be2c89c79c43ffcac834bc8868" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/simplito/elliptic-php/zipball/be321666781be2be2c89c79c43ffcac834bc8868", + "reference": "be321666781be2be2c89c79c43ffcac834bc8868", + "shasum": "" + }, + "require": { + "ext-gmp": "*", + "simplito/bn-php": "~1.1.0" + }, + "require-dev": { + "phpbench/phpbench": "@dev", + "phpunit/phpunit": "*" + }, + "type": "library", + "autoload": { + "psr-4": { + "Elliptic\\": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Simplito Team", + "email": "s.smyczynski@simplito.com", + "homepage": "https://simplito.com" + } + ], + "description": "Fast elliptic curve cryptography", + "homepage": "https://github.com/simplito/elliptic-php", + "keywords": [ + "Curve25519", + "ECDSA", + "Ed25519", + "EdDSA", + "cryptography", + "curve", + "curve25519-weier", + "ecc", + "ecdh", + "elliptic", + "nistp192", + "nistp224", + "nistp256", + "nistp384", + "nistp521", + "secp256k1" + ], + "support": { + "issues": "https://github.com/simplito/elliptic-php/issues", + "source": "https://github.com/simplito/elliptic-php/tree/1.0.12" + }, + "time": "2024-01-09T14:57:04+00:00" + }, { "name": "symfony/console", "version": "v6.4.1", @@ -8272,7 +8926,8 @@ "prefer-lowest": false, "platform": { "php": "^8.1", - "ext-bcmath": "*" + "ext-bcmath": "*", + "ext-gmp": "*" }, "platform-dev": [], "plugin-api-version": "2.6.0" diff --git a/sdk/Wallet/Http.php b/sdk/Wallet/Http.php new file mode 100644 index 0000000..19212ce --- /dev/null +++ b/sdk/Wallet/Http.php @@ -0,0 +1,33 @@ +httpClient = $client; + } + + function getClient() + { + return $this->httpClient; + } + + function get(string $endpoint, array $data = []) + { + $stream = (string)$this->getClient()->get($endpoint, ['query' => $data])->getBody(); + $body = json_decode($stream, false); + return $body; + } + + function post(string $endpoint, array $data = []) + { + $stream = (string)$this->getClient()->post($endpoint, ['json' => $data])->getBody(); + $body = json_decode($stream, false); + return $body; + } + +} diff --git a/sdk/Wallet/TokenAddress.php b/sdk/Wallet/TokenAddress.php new file mode 100644 index 0000000..56edd41 --- /dev/null +++ b/sdk/Wallet/TokenAddress.php @@ -0,0 +1,72 @@ +address2HexString($address); + if (!empty($hexAddress) && empty($address)) $address = $this->hexString2Address($hexAddress); + + $this->privateKey = $privateKey; + $this->address = $address; + $this->hexAddress = $hexAddress; + } + + /** + * Dont rely on this. Always use Wallet::validateAddress to double check + * against tronGrid. + * + * @return bool + */ + public function isValid(): bool + { + if (strlen($this->address) !== self::ADDRESS_SIZE) { + return false; + } + + $address = Base58Check::decode($this->address, false, 0, false); + $utf8 = hex2bin($address); + + if (strlen($utf8) !== 25) { + return false; + } + + if (strpos($utf8, chr(self::ADDRESS_PREFIX_BYTE)) !== 0) { + return false; + } + + $checkSum = substr($utf8, 21); + $address = substr($utf8, 0, 21); + + $hash0 = Hash::SHA256($address); + $hash1 = Hash::SHA256($hash0); + $checkSum1 = substr($hash1, 0, 4); + + if ($checkSum === $checkSum1) { + return true; + } + + return false; + } + +} diff --git a/sdk/Wallet/Tools/Formatter.php b/sdk/Wallet/Tools/Formatter.php new file mode 100644 index 0000000..85f67d1 --- /dev/null +++ b/sdk/Wallet/Tools/Formatter.php @@ -0,0 +1,57 @@ +toHex(true); + $padded = mb_substr($bnHex, 0, 1); + + if ($padded !== 'f') { + $padded = '0'; + } + return implode('', array_fill(0, $digit - mb_strlen($bnHex), $padded)) . $bnHex; + } +} diff --git a/sdk/Wallet/Tools/Key.php b/sdk/Wallet/Tools/Key.php new file mode 100644 index 0000000..3253310 --- /dev/null +++ b/sdk/Wallet/Tools/Key.php @@ -0,0 +1,82 @@ +keyFromPrivate($privateKey, 'hex'); + $publicKey = $privateKey->getPublic(false, 'hex'); + + return $publicKey; + } + + public static function getBase58CheckAddress(string $addressHex): string + { + $addressBin = hex2bin($addressHex); + $hash0 = Hash::SHA256($addressBin); + $hash1 = Hash::SHA256($hash0); + $checksum = substr($hash1, 0, 4); + $checksum = $addressBin . $checksum; + + return Base58::encode(Crypto::bin2bc($checksum)); + } +} diff --git a/sdk/Wallet/Tools/Tools.php b/sdk/Wallet/Tools/Tools.php new file mode 100644 index 0000000..9947d4d --- /dev/null +++ b/sdk/Wallet/Tools/Tools.php @@ -0,0 +1,9 @@ +toHex(true); + $hex = preg_replace('/^0+(?!$)/', '', $hex); + } elseif (is_string($value)) { + $value = self::stripZero($value); + $hex = implode('', unpack('H*', $value)); + } elseif ($value instanceof BigInteger) { + $hex = $value->toHex(true); + $hex = preg_replace('/^0+(?!$)/', '', $hex); + } else { + throw new InvalidArgumentException('The value to toHex function is not support.'); + } + if ($isPrefix) { + return '0x' . $hex; + } + return $hex; + } + + /** + * hexToBin + * + * @param string + * @return string + */ + public static function hexToBin($value) + { + if (!is_string($value)) { + throw new InvalidArgumentException('The value to hexToBin function must be string.'); + } + if (self::isZeroPrefixed($value)) { + $count = 1; + $value = str_replace('0x', '', $value, $count); + } + return pack('H*', $value); + } + + /** + * isZeroPrefixed + * + * @param string + * @return bool + */ + public static function isZeroPrefixed($value) + { + if (!is_string($value)) { + throw new InvalidArgumentException('The value to isZeroPrefixed function must be string.'); + } + return (strpos($value, '0x') === 0); + } + + /** + * stripZero + * + * @param string $value + * @return string + */ + public static function stripZero($value) + { + if (self::isZeroPrefixed($value)) { + $count = 1; + return str_replace('0x', '', $value, $count); + } + return $value; + } + + /** + * isNegative + * + * @param string + * @return bool + */ + public static function isNegative($value) + { + if (!is_string($value)) { + throw new InvalidArgumentException('The value to isNegative function must be string.'); + } + return (strpos($value, '-') === 0); + } + + /** + * isAddress + * + * @param string $value + * @return bool + */ + public static function isAddress($value) + { + if (!is_string($value)) { + throw new InvalidArgumentException('The value to isAddress function must be string.'); + } + if (preg_match('/^(0x|0X)?[a-f0-9A-F]{40}$/', $value) !== 1) { + return false; + } elseif (preg_match('/^(0x|0X)?[a-f0-9]{40}$/', $value) === 1 || preg_match('/^(0x|0X)?[A-F0-9]{40}$/', $value) === 1) { + return true; + } + return self::isAddressChecksum($value); + } + + /** + * isAddressChecksum + * + * @param string $value + * @return bool + */ + public static function isAddressChecksum($value) + { + if (!is_string($value)) { + throw new InvalidArgumentException('The value to isAddressChecksum function must be string.'); + } + $value = self::stripZero($value); + $hash = self::stripZero(self::sha3(mb_strtolower($value))); + + for ($i = 0; $i < 40; $i++) { + if ( + (intval($hash[$i], 16) > 7 && mb_strtoupper($value[$i]) !== $value[$i]) || + (intval($hash[$i], 16) <= 7 && mb_strtolower($value[$i]) !== $value[$i]) + ) { + return false; + } + } + return true; + } + + /** + * isHex + * + * @param string $value + * @return bool + */ + public static function isHex($value) + { + return (is_string($value) && preg_match('/^(0x)?[a-f0-9A-F]*$/', $value) === 1); + } + + /** + * sha3 + * keccak256 + * + * @param string $value + * @return string + */ + public static function sha3($value) + { + if (!is_string($value)) { + throw new InvalidArgumentException('The value to sha3 function must be string.'); + } + if (strpos($value, '0x') === 0) { + $value = self::hexToBin($value); + } + $hash = Keccak::hash($value, 256); + + if ($hash === self::SHA3_NULL_HASH) { + return null; + } + return $hash; + } + + /** + * toBn + * Change number or number string to BigInteger. + * + * @param BigInteger|string|int $number + * @return array|BigInteger + */ + public static function toBn($number) + { + if ($number instanceof BigInteger) { + $bn = $number; + } elseif (is_int($number)) { + $bn = new BigInteger($number); + } elseif (is_numeric($number)) { + $number = (string) $number; + + if (self::isNegative($number)) { + $count = 1; + $number = str_replace('-', '', $number, $count); + $negative1 = new BigInteger(-1); + } + if (strpos($number, '.') > 0) { + $comps = explode('.', $number); + + if (count($comps) > 2) { + throw new InvalidArgumentException('toBn number must be a valid number.'); + } + $whole = $comps[0]; + $fraction = $comps[1]; + + return [ + new BigInteger($whole), + new BigInteger($fraction), + strlen($comps[1]), + isset($negative1) ? $negative1 : false + ]; + } else { + $bn = new BigInteger($number); + } + if (isset($negative1)) { + $bn = $bn->multiply($negative1); + } + } elseif (is_string($number)) { + $number = mb_strtolower($number); + + if (self::isNegative($number)) { + $count = 1; + $number = str_replace('-', '', $number, $count); + $negative1 = new BigInteger(-1); + } + if (self::isZeroPrefixed($number) || preg_match('/[a-f]+/', $number) === 1) { + $number = self::stripZero($number); + $bn = new BigInteger($number, 16); + } elseif (empty($number)) { + $bn = new BigInteger(0); + } else { + throw new InvalidArgumentException('toBn number must be valid hex string.'); + } + if (isset($negative1)) { + $bn = $bn->multiply($negative1); + } + } else { + throw new InvalidArgumentException('toBn number must be BigInteger, string or int.'); + } + return $bn; + } + + /** + * 根据精度展示资产 + * @param $number + * @param int $decimals + * @return string + */ + public static function toDisplayAmount($number, int $decimals) + { + $number = number_format($number,0,'.','');//格式化 + $bn = self::toBn($number); + $bnt = self::toBn(pow(10, $decimals)); + + return self::divideDisplay($bn->divide($bnt), $decimals); + } + + public static function divideDisplay(array $divResult, int $decimals) + { + list($bnq, $bnr) = $divResult; + $ret = "$bnq->value"; + if ($bnr->value > 0) { + $ret .= '.' . rtrim(sprintf("%0{$decimals}d", $bnr->value), '0'); + } + + return $ret; + } + + public static function toMinUnitByDecimals($number, int $decimals) + { + $bn = self::toBn($number); + $bnt = self::toBn(pow(10, $decimals)); + + if (is_array($bn)) { + // fraction number + list($whole, $fraction, $fractionLength, $negative1) = $bn; + + $whole = $whole->multiply($bnt); + + switch (MATH_BIGINTEGER_MODE) { + case $whole::MODE_GMP: + static $two; + $powerBase = gmp_pow(gmp_init(10), (int) $fractionLength); + break; + case $whole::MODE_BCMATH: + $powerBase = bcpow('10', (string) $fractionLength, 0); + break; + default: + $powerBase = pow(10, (int) $fractionLength); + break; + } + $base = new BigInteger($powerBase); + $fraction = $fraction->multiply($bnt)->divide($base)[0]; + + if ($negative1 !== false) { + return $whole->add($fraction)->multiply($negative1); + } + return $whole->add($fraction); + } + + return $bn->multiply($bnt); + } +} diff --git a/sdk/Wallet/Trc20Sdk.php b/sdk/Wallet/Trc20Sdk.php new file mode 100644 index 0000000..8f41890 --- /dev/null +++ b/sdk/Wallet/Trc20Sdk.php @@ -0,0 +1,252 @@ +http = new Http($_api); + $this->contractAddress = new TokenAddress($contractAddress); + + $host = $this->getHttpClient()->getClient()->getConfig('base_uri')->getScheme() . '://' . $this->getHttpClient()->getClient()->getConfig('base_uri')->getHost(); + $fullNode = new HttpProvider($host); + $solidityNode = new HttpProvider($host); + $eventServer = new HttpProvider($host); + try { + $this->tron = new Tron($fullNode, $solidityNode, $eventServer); +// $this->tronContract = new TRC20Contract($this->tron,$contractAddress); + } catch (\Exception $e) { + throw new WalletSdkException($e->getMessage(), $e->getCode()); + } + } + + function getHttpClient(): Http + { + return $this->http; + } + + //获取当前最新区块事件 + function getLastBlockEvent(): NowBlockBean|bool + { + $data = [ + 'limit' => 1, + 'order_by' => 'block_timestamp,desc', + ]; + $res = $this->getHttpClient()->get('/v1/blocks/latest/events', $data); + if (!isset($res['data'][0])) return false; + $ResponseBean = new ResponseBean($res); + $item = $ResponseBean->getData()[0]; + return new NowBlockBean($item); + } + + //获取当前最新区块事件 + function getNowBlockNumber(): NowBlockBean|bool + { + return $this->getLastBlockEvent(); + } + + //根据区块高度获取交易信息 + public function getTrc20BlockEventsByBlockNumber(string|int $blockNumber, $fingerprint = null, $limit = 200): bool|ResponseBean + { + $path = '/v1/contracts/' . $this->contractAddress->address . '/events'; + $data = [ + 'block_number' => $blockNumber, + 'limit' => $limit, + 'only_confirmed' => true, + ]; + if (!empty($fingerprint)) $data['fingerprint'] = $fingerprint; + $res = $this->getHttpClient()->get($path, $data); + if (!isset($res['success'])) return false; + if ($res['success'] !== true) return false; + return new ResponseBean($res); + } + + //根据区块高度获取交易信息 + public function getTrc20BlockEventsTransferByBlockNumber(string|int $blockNumber, $fingerprint = null, $limit = 200): bool|ResponseBean + { + $path = '/v1/contracts/' . $this->contractAddress->address . '/events'; + $data = [ + 'event_name' => 'Transfer', + 'block_number' => $blockNumber, + 'limit' => $limit, + 'only_confirmed' => true, + 'order_by' => 'block_timestamp,asc', + ]; + if (!empty($fingerprint)) $data['fingerprint'] = $fingerprint; + $res = $this->getHttpClient()->get($path, $data); + if (!isset($res['success'])) return false; + if ($res['success'] !== true) return false; + return new ResponseBean($res); + } + + //获取账户合约交易记录 + public function getAccountTrc20Events(string $address, $fingerprint = null, $limit = 200): bool|ResponseBean + { + $path = '/v1/accounts/' . $address . '//transactions/trc20'; + $data = [ + 'limit' => $limit, + 'contract_address' => $this->contractAddress->address, + 'only_confirmed' => true, + 'order_by' => 'block_timestamp,desc', + ]; + if (!empty($fingerprint)) $data['fingerprint'] = $fingerprint; + $res = $this->getHttpClient()->get($path, $data); + if (!isset($res['success'])) return false; + if ($res['success'] !== true) return false; + return new ResponseBean($res); + } + + //获取TRC20余额 + function getTrc20Balance(string $address): float|string + { + $address = new TokenAddress($address); + $format = Formatter::toAddressFormat($address->hexAddress); + $res = $this->getHttpClient()->post('/wallet/triggersmartcontract', [ + 'contract_address' => $this->contractAddress->hexAddress, + 'function_selector' => 'balanceOf(address)', + 'parameter' => $format, + 'owner_address' => $address->hexAddress, + ]); + + if (!isset($res['result']['result'])) { + throw new WalletSdkException('getTrc20Balance error'); + } + if ($res['result']['result'] !== true) { + throw new WalletSdkException('getTrc20Balance error'); + } + + try { + $hex_value = $res['constant_result'][0]; + $balance = Math::valueToAmount(hexdec($hex_value), self::DECIMALS); + } catch (\Exception $e) { + throw new WalletSdkException($e->getMessage()); + } + return $balance; + } + + //获取TRX余额 + function getTrxBalance(string $address): float + { + $this->tron->setAddress($address); + return $this->tron->getBalance($address, true); + } + + //TRC20转账 + function trc20Transfer(TokenAddress $from, TokenAddress $to, float $amount): TransferTransactionBean|bool + { + $this->tron->setAddress($from->address); + $this->tron->setPrivateKey($from->privateKey); + + $toFormat = Formatter::toAddressFormat($to->hexAddress); + try { + $amount = Utils::toMinUnitByDecimals($amount, self::DECIMALS); + } catch (\Exception $e) { + throw new WalletSdkException($e->getMessage()); + } + $numberFormat = Formatter::toIntegerFormat($amount); + + $body = $this->getHttpClient()->post('/wallet/triggersmartcontract', [ + 'contract_address' => $this->contractAddress->hexAddress, + 'function_selector' => 'transfer(address,uint256)', + 'parameter' => "{$toFormat}{$numberFormat}", + 'fee_limit' => 30000000, + 'call_value' => 0, + 'owner_address' => $from->hexAddress, + ]); + + if (!isset($body['result']['result'])) { + throw new WalletSdkException(hex2bin($body['result']['message'])); + } + + try { + $tradeobj = $this->tron->signTransaction($body['transaction']); + $response = $this->tron->sendRawTransaction($tradeobj); + } catch (\Exception $e) { + throw new WalletSdkException($e->getMessage(), $e->getCode()); + } + + if (isset($response['result']) && $response['result'] == true) { + return new TransferTransactionBean($body['transaction']); + } else { + throw new WalletSdkException(hex2bin($response['result']['message'])); + } + return false; + } + + //TRX转账 + function trxTransfer(TokenAddress $from, TokenAddress $to, float $amount): TransferTransactionBean + { + $this->tron->setAddress($from->address); + $this->tron->setPrivateKey($from->privateKey); + + try { + $transaction = $this->tron->getTransactionBuilder()->sendTrx($to->address, $amount, $from->address); + $signedTransaction = $this->tron->signTransaction($transaction); + $response = $this->tron->sendRawTransaction($signedTransaction); + } catch (\Exception $e) { + throw new WalletSdkException($e->getMessage(), $e->getCode()); + } + + if (isset($response['result']) && $response['result'] == true) { + $TransferTransactionBean = new TransferTransactionBean($signedTransaction); + return $TransferTransactionBean; + } else { + throw new WalletSdkException(hex2bin($response['message'])); + } + + } + + //根据交易hash获取交易信息 + function getTransactionByTid(string $tid): array + { + try { + return $this->tron->getTransaction($tid); + } catch (\Exception $e) { + throw new WalletSdkException($e->getMessage(), $e->getCode()); + } + } + + //检测交易是否成功 + function checkTransactionByTid(string $tid): bool + { + $res = $this->getTransactionByTid($tid); + if (empty($res)) return false; + if (!isset($res['ret']['contractRet'])) return false; + if ($res['ret']['contractRet'] === 'SUCCESS') return true; + return false; + } + + //生成新地址 + function createAccount(): TokenAddressBean + { + try { + $res = $this->tron->createAccount(); + } catch (TronException $e) { + throw new WalletSdkException($e->getMessage(), $e->getCode()); + } + return new TokenAddressBean($res->getRawData()); + } + + +} diff --git a/sdk/Wallet/UsdtTrc20.php b/sdk/Wallet/UsdtTrc20.php new file mode 100644 index 0000000..c4e84aa --- /dev/null +++ b/sdk/Wallet/UsdtTrc20.php @@ -0,0 +1,32 @@ + self::API_SECRET, + 'Content-Type' => 'application/json', + ]; + $client = new Client(['base_uri' => self::RPC_URL, 'headers' => $headers]); + $trc20Wallet = new Trc20Sdk($client, self::CONTRACT_ADDRESS); + $this->sdk = $trc20Wallet; + } + + function getHandler(): Trc20Sdk + { + return $this->sdk; + } + + +}