├── .gitignore ├── LICENSE ├── README.md ├── composer.json ├── phpunit.xml.dist ├── src ├── Api.php ├── Exceptions │ ├── ChiaErrorException.php │ └── TransactionException.php ├── FullNode.php ├── Interfaces │ ├── FullNodeInterface.php │ └── WalletInterface.php ├── Types │ ├── Address.php │ ├── Block.php │ └── Transaction.php └── Wallet.php └── tests ├── FullNodeTest.php ├── WalletTest.php ├── private_full_node.crt ├── private_full_node.key ├── private_wallet.crt └── private_wallet.key /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | vendor 3 | *.lock -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Fenguoz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

Chia-PHP

2 | 3 | ## 概述 4 | 5 | Chia-PHP 支持奇亚的 XCH 中获取当前区块链信息、获取当前高度、获取当前网络信息、创建新钱包、生成助记词、发起交易、获取交易记录等功能。 6 | 7 | ## 支持方法 8 | 9 | ### 节点 10 | 11 | #### 区块链 12 | 13 | - ✅当前区块链信息 `getBlockchainState()` 14 | - ✅通过 `header_hash` 获取完整区块 `getBlock()` 15 | - ✅获取完整区块列表 `getBlocks()` 16 | - ✅通过 `height` 获取块记录 `getBlockRecordByHeight()` 17 | - ✅通过 `header_hash` 获取块记录 `getBlockRecord()` 18 | - ✅获取块记录列表 `getBlockRecords()` 19 | - ✅获取未完成的头部块 `getUnfinishedBlockHeaders()` 20 | - ✅获取总绘制空间的估计值 `getNetworkSpace()` 21 | - ✅获取块的币种增删记录 `getAdditionsAndRemovals()` 22 | - ✅获取区块链的初始冻结期 `getInitialFreezePeriod()` 23 | - ✅获取当前网络信息 `getNetworkInfo()` 24 | 25 | #### 币种 26 | 27 | - ✅通过 `PuzzleHash` 获取币种记录 `getCoinRecordsByPuzzleHash()` 28 | - ✅通过数组 `PuzzleHash` 获取币种记录 `getCoinRecordsByPuzzleHashes()` 29 | - ✅通过 `币种名称/ID` 获取币种记录 `getCoinRecordByName()` 30 | - 🚧 推送交易包到内存池和区块链 `pushTx()` 31 | 32 | #### 内存池 33 | 34 | - ✅获取交易ID(花费捆绑哈希)列表`getAllMempoolTxIds()` 35 | - ✅获取内存池项目 `getAllMempoolItems()` 36 | - ✅通过 `交易ID` 获取内存池项目 `getMempoolItemByTxId()` 37 | 38 | ### 钱包 39 | 40 | #### 密钥管理 41 | 42 | - ✅指定 `finger` 为激活状态 `logIn()` 43 | - ✅获取钱包公钥 `getPublicKeys()` 44 | - ✅获取钱包私钥 `getPrivateKey()` 45 | - ✅生成助记词 `generateMnemonic()` 46 | - ✅添加钥匙串 `addKey()` 47 | - ✅删除私钥 `deleteKey()` 48 | - ✅删除所有私钥 `deleteAllKeys()` 49 | 50 | #### 钱包节点 51 | 52 | - ✅获取钱包同步状态 `getSyncStatus()` 53 | - ✅获取当前高度 `getHeightInfo()` 54 | - ✅农场块`farmBlock()` 55 | - ✅获取区块链初始冻结期 `getInitialFreezePeriod()` 56 | - ✅获取当前网络信息 `getNetworkInfo()` 57 | 58 | #### 钱包管理 59 | 60 | - ✅获取钱包列表 `getWallets()` 61 | - 🚧 创建新钱包 `createNewWallet()` 62 | 63 | #### 钱包 64 | 65 | - ✅获取钱包余额 `getWalletBalance()` 66 | - ✅通过 `交易hash` 获取交易记录 `getTransaction()` 67 | - ✅获取交易记录 `getTransactions()` 68 | - ✅获取新地址 `getNextAddress()` 69 | - ✅发起交易 `sendTransaction()` 70 | - ✅创建备份 `createBackup()` 71 | - ✅获取钱包交易数量 `getTransactionCount()` 72 | - ✅获取农场奖励信息 `getFarmedAmount()` 73 | - 🚧 `createSignedTransaction()` 74 | 75 | #### 其他币种和交易 🚧 76 | #### DID 钱包 🚧 77 | #### RL 钱包 🚧 78 | 79 | ## 快速开始 80 | 81 | ### 安装 82 | 83 | ``` php 84 | composer require fenguoz/chia-php 85 | ``` 86 | 87 | ### 接口调用 88 | 89 | ``` php 90 | /* 节点(Full Node) */ 91 | $fullNodeConfig = [ 92 | 'base_uri' => 'https://localhost:8555', 93 | 'verify' => false, 94 | 'cert' => '/your/private_full_node.crt/path',// private_full_node.crt 95 | 'ssl_key' => '/your/private_full_node.key/path',// private_full_node.key 96 | ]; 97 | 98 | $api = new \Chia\Api(new \GuzzleHttp\Client($fullNodeConfig)); 99 | $fullNode = new Chia\FullNode($api); 100 | $info = $fullNode->getNetworkInfo(); 101 | // $info->network_name mainnet 102 | // $info->network_prefix xch 103 | 104 | /* 钱包(Wallet) */ 105 | $walletConfig = [ 106 | 'base_uri' => 'https://localhost:9256', 107 | 'verify' => false, 108 | 'cert' => '/your/private_wallet.crt/path',// private_wallet.crt 109 | 'ssl_key' => '/your/private_wallet.key/path', // private_wallet.key 110 | ]; 111 | 112 | $api = new \Chia\Api(new \GuzzleHttp\Client($walletConfig)); 113 | $wallet = new Chia\Wallet($api); 114 | $info = $wallet->getNetworkInfo(); 115 | ``` 116 | 117 | ## 计划 118 | 119 | - 新增新接口 120 | - 新增参数和响应检验类 121 | - 完善文档 122 | - ... 123 | 124 | ## 🌟🌟 125 | 126 | [![Stargazers over time](https://starchart.cc/Fenguoz/chia-php.svg)](https://starchart.cc/Fenguoz/chia-php) 127 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "fenguoz/chia-php", 3 | "description": "Supports functions such as obtaining current blockchain information, obtaining current altitude, obtaining current network information, creating a new wallet, generating mnemonic words, initiating transactions, and obtaining transaction records in Chia’s XCH.", 4 | "keywords": [ 5 | "php", 6 | "rpc", 7 | "chia", 8 | "xch" 9 | ], 10 | "type": "library", 11 | "homepage": "https://github.com/Fenguoz/chia-php", 12 | "license": "MIT", 13 | "authors": [ 14 | { 15 | "name": "Fenguoz", 16 | "email": "243944672@qq.com" 17 | } 18 | ], 19 | "require": { 20 | "guzzlehttp/guzzle": "^6.0 || ^7.0" 21 | }, 22 | "require-dev": { 23 | "phpunit/phpunit": "^5.7 || ^7.5" 24 | }, 25 | "autoload": { 26 | "psr-4": { 27 | "Chia\\": "src/" 28 | } 29 | }, 30 | "autoload-dev": { 31 | "psr-4": { 32 | "Test\\": "tests/" 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 4 | 5 | 6 | 7 | ./tests/ 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/Api.php: -------------------------------------------------------------------------------- 1 | _client = $client; 15 | } 16 | 17 | public function getClient(): Client 18 | { 19 | return $this->_client; 20 | } 21 | 22 | /** 23 | * Abstracts some common functionality like formatting the post data 24 | * along with error handling. 25 | * 26 | * @throws ChiaErrorException 27 | */ 28 | public function post(string $endpoint, array $data = [], bool $returnAssoc = false) 29 | { 30 | if (sizeof($data)) { 31 | $data = ['json' => $data]; 32 | }else{ 33 | $data = ['json' => []]; 34 | } 35 | 36 | $stream = (string)$this->getClient()->post($endpoint, $data)->getBody(); 37 | $body = json_decode($stream, $returnAssoc); 38 | 39 | $this->checkForErrorResponse($returnAssoc, $body); 40 | 41 | return $body; 42 | } 43 | 44 | /** 45 | * Check if the response has an error and throw it. 46 | * 47 | * @param bool $returnAssoc 48 | * @param $body 49 | * @throws ChiaErrorException 50 | */ 51 | private function checkForErrorResponse(bool $returnAssoc, $body) 52 | { 53 | if ($returnAssoc) { 54 | if (isset($body['Error'])) { 55 | throw new ChiaErrorException($body['Error']); 56 | } elseif (isset($body['code']) && isset($body['message'])) { 57 | throw new ChiaErrorException($body['code'] . ': ' . hex2bin($body['message'])); 58 | } 59 | } 60 | 61 | if (isset($body->Error)) { 62 | throw new ChiaErrorException($body->Error); 63 | } elseif (isset($body->code) && isset($body->message)) { 64 | throw new ChiaErrorException($body->code . ': ' . hex2bin($body->message)); 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Exceptions/ChiaErrorException.php: -------------------------------------------------------------------------------- 1 | _api = $_api; 13 | } 14 | 15 | public function getBlockchainState() 16 | { 17 | $body = $this->_api->post('/get_blockchain_state'); 18 | 19 | if ($body->success == false) { 20 | throw new ChiaErrorException($body->error); 21 | } 22 | return $body->blockchain_state; 23 | } 24 | 25 | public function getBlock(string $headerHash) 26 | { 27 | $body = $this->_api->post('/get_block', [ 28 | 'header_hash' => $headerHash 29 | ]); 30 | 31 | if ($body->success == false) { 32 | throw new ChiaErrorException($body->error); 33 | } 34 | return $body->block; 35 | } 36 | 37 | public function getBlocks(int $start, int $end, $excludeHeaderHash = null) 38 | { 39 | $params = []; 40 | $params['start'] = $start; 41 | $params['end'] = $end; 42 | if ($excludeHeaderHash) $params['exclude_header_hash'] = $excludeHeaderHash; 43 | $body = $this->_api->post('/get_blocks', $params); 44 | 45 | if ($body->success == false) { 46 | throw new ChiaErrorException($body->error); 47 | } 48 | return $body->blocks; 49 | } 50 | 51 | public function getBlockRecordByHeight(int $height) 52 | { 53 | $body = $this->_api->post('/get_block_record_by_height', [ 54 | 'height' => $height 55 | ]); 56 | 57 | if ($body->success == false) { 58 | throw new ChiaErrorException($body->error); 59 | } 60 | return $body->block_record; 61 | } 62 | 63 | public function getBlockRecord(string $headerHash) 64 | { 65 | $body = $this->_api->post('/get_block_record', [ 66 | 'header_hash' => $headerHash 67 | ]); 68 | 69 | if ($body->success == false) { 70 | throw new ChiaErrorException($body->error); 71 | } 72 | return $body->block_record; 73 | } 74 | 75 | public function getBlockRecords(int $start, int $end) 76 | { 77 | $body = $this->_api->post('/get_block_records', [ 78 | 'start' => $start, 79 | 'end' => $end 80 | ]); 81 | 82 | if ($body->success == false) { 83 | throw new ChiaErrorException($body->error); 84 | } 85 | return $body->block_records; 86 | } 87 | 88 | public function getUnfinishedBlockHeaders() 89 | { 90 | $body = $this->_api->post('/get_unfinished_block_headers'); 91 | 92 | if ($body->success == false) { 93 | throw new ChiaErrorException($body->error); 94 | } 95 | return $body->headers; 96 | } 97 | 98 | public function getNetworkSpace(string $newerBlockHeaderHash, string $olderBlockHeaderHash) 99 | { 100 | $body = $this->_api->post('/get_network_space', [ 101 | 'newer_block_header_hash' => $newerBlockHeaderHash, 102 | 'older_block_header_hash' => $olderBlockHeaderHash 103 | ]); 104 | 105 | if ($body->success == false) { 106 | throw new ChiaErrorException($body->error); 107 | } 108 | return $body->space; 109 | } 110 | 111 | public function getAdditionsAndRemovals(string $headerHash) 112 | { 113 | $body = $this->_api->post('/get_additions_and_removals', [ 114 | 'header_hash' => $headerHash 115 | ]); 116 | 117 | if ($body->success == false) { 118 | throw new ChiaErrorException($body->error); 119 | } 120 | unset($body->success); 121 | return $body; 122 | } 123 | 124 | public function getInitialFreezePeriod() 125 | { 126 | $body = $this->_api->post('/get_initial_freeze_period'); 127 | 128 | if ($body->success == false) { 129 | throw new ChiaErrorException($body->error); 130 | } 131 | return $body->INITIAL_FREEZE_END_TIMESTAMP; 132 | } 133 | 134 | public function getNetworkInfo() 135 | { 136 | $body = $this->_api->post('/get_network_info'); 137 | 138 | if ($body->success == false) { 139 | throw new ChiaErrorException($body->error); 140 | } 141 | unset($body->success); 142 | return $body; 143 | } 144 | 145 | public function getCoinRecordsByPuzzleHash(string $puzzleHash, int $startHeight = null, int $endHeight = null, $includeSpentCoins = null) 146 | { 147 | $params = []; 148 | $params['puzzle_hash'] = $puzzleHash; 149 | if ($startHeight) $params['start_height'] = $startHeight; 150 | if ($endHeight) $params['end_height'] = $endHeight; 151 | if ($includeSpentCoins) $params['include_spent_coins'] = $includeSpentCoins; 152 | $body = $this->_api->post('/get_coin_records_by_puzzle_hash', $params); 153 | 154 | if ($body->success == false) { 155 | throw new ChiaErrorException($body->error); 156 | } 157 | return $body->coin_records; 158 | } 159 | 160 | public function getCoinRecordsByPuzzleHashes(array $puzzleHashs, int $startHeight = null, int $endHeight = null, $includeSpentCoins = null) 161 | { 162 | $params = []; 163 | $params['puzzle_hashes'] = $puzzleHashs; 164 | if ($startHeight) $params['start_height'] = $startHeight; 165 | if ($endHeight) $params['end_height'] = $endHeight; 166 | if ($includeSpentCoins) $params['include_spent_coins'] = $includeSpentCoins; 167 | $body = $this->_api->post('/get_coin_records_by_puzzle_hashes', $params); 168 | 169 | if ($body->success == false) { 170 | throw new ChiaErrorException($body->error); 171 | } 172 | return $body->coin_records; 173 | } 174 | 175 | public function getCoinRecordByName(string $coinName) 176 | { 177 | $body = $this->_api->post('/get_coin_record_by_name', [ 178 | 'name' => $coinName 179 | ]); 180 | 181 | if ($body->success == false) { 182 | throw new ChiaErrorException($body->error); 183 | } 184 | return $body->coin_record; 185 | } 186 | 187 | public function pushTx(array $spendBundle) 188 | { 189 | $body = $this->_api->post('/push_tx', [ 190 | 'spend_bundle' => json_encode($spendBundle) 191 | ]); 192 | 193 | if ($body->success == false) { 194 | throw new ChiaErrorException($body->error); 195 | } 196 | return $body->status; 197 | } 198 | 199 | public function getAllMempoolTxIds() 200 | { 201 | $body = $this->_api->post('/get_all_mempool_tx_ids'); 202 | 203 | if ($body->success == false) { 204 | throw new ChiaErrorException($body->error); 205 | } 206 | return $body->tx_ids; 207 | } 208 | 209 | public function getAllMempoolItems() 210 | { 211 | $body = $this->_api->post('/get_all_mempool_items'); 212 | 213 | if ($body->success == false) { 214 | throw new ChiaErrorException($body->error); 215 | } 216 | return $body->mempool_items; 217 | } 218 | 219 | public function getMempoolItemByTxId(string $txId) 220 | { 221 | $body = $this->_api->post('/get_mempool_item_by_tx_id', [ 222 | 'tx_id' => $txId 223 | ]); 224 | 225 | if ($body->success == false) { 226 | throw new ChiaErrorException($body->error); 227 | } 228 | return $body->mempool_item; 229 | } 230 | } 231 | -------------------------------------------------------------------------------- /src/Interfaces/FullNodeInterface.php: -------------------------------------------------------------------------------- 1 | privateKey = $privateKey; 25 | $this->address = $address; 26 | } 27 | 28 | /** 29 | * Dont rely on this. Always use Wallet::validateAddress to double check 30 | * against tronGrid. 31 | * 32 | * @return bool 33 | */ 34 | public function isValid(): bool 35 | { 36 | if (strlen($this->address) !== Address::ADDRESS_SIZE) { 37 | return false; 38 | } 39 | 40 | $address = Base58Check::decode($this->address, false, 0, false); 41 | $utf8 = hex2bin($address); 42 | 43 | if (strlen($utf8) !== 25) { 44 | return false; 45 | } 46 | 47 | if (strpos($utf8, self::ADDRESS_PREFIX_BYTE) !== 0) { 48 | return false; 49 | } 50 | 51 | $checkSum = substr($utf8, 21); 52 | $address = substr($utf8, 0, 21); 53 | 54 | $hash0 = Hash::SHA256($address); 55 | $hash1 = Hash::SHA256($hash0); 56 | $checkSum1 = substr($hash1, 0, 4); 57 | 58 | if ($checkSum === $checkSum1) { 59 | return true; 60 | } 61 | 62 | return false; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Types/Block.php: -------------------------------------------------------------------------------- 1 | block_id = $blockID; 18 | $this->block_header = $blockHeader; 19 | $this->transactions = $transactions; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Types/Transaction.php: -------------------------------------------------------------------------------- 1 | tx_id = $txID; 15 | $this->raw_data = $rawData; 16 | $this->contract_ret = $contractRet; 17 | } 18 | 19 | public function isSigned(): bool 20 | { 21 | return (bool)sizeof($this->signature); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Wallet.php: -------------------------------------------------------------------------------- 1 | _api = $_api; 14 | } 15 | 16 | public function logIn(int $fingerprint) 17 | { 18 | $body = $this->_api->post('/log_in', [ 19 | 'fingerprint' => $fingerprint 20 | ]); 21 | 22 | if ($body->success == false) { 23 | throw new ChiaErrorException($body->error); 24 | } 25 | return true; 26 | } 27 | 28 | public function getPublicKeys() 29 | { 30 | $body = $this->_api->post('/get_public_keys'); 31 | 32 | if ($body->success == false) { 33 | throw new ChiaErrorException($body->error); 34 | } 35 | return $body->public_key_fingerprints; 36 | } 37 | 38 | public function getPrivateKey(int $fingerprint) 39 | { 40 | $body = $this->_api->post('/get_private_key', [ 41 | 'fingerprint' => $fingerprint 42 | ]); 43 | 44 | if ($body->success == false) { 45 | throw new ChiaErrorException('The fingerprint not exist'); 46 | } 47 | return $body->private_key; 48 | } 49 | 50 | public function generateMnemonic() 51 | { 52 | $body = $this->_api->post('/generate_mnemonic'); 53 | 54 | if ($body->success == false) { 55 | throw new ChiaErrorException($body->error); 56 | } 57 | return $body->mnemonic; 58 | } 59 | 60 | public function addKey(array $mnemonic, string $type = 'new_wallet') 61 | { 62 | $body = $this->_api->post('/add_key', [ 63 | 'mnemonic' => $mnemonic, 64 | 'type' => $type, 65 | ]); 66 | 67 | if ($body->success == false) { 68 | throw new ChiaErrorException($body->error); 69 | } 70 | return $body->fingerprint; 71 | } 72 | 73 | public function deleteKey(int $fingerprint) 74 | { 75 | $body = $this->_api->post('/delete_key', [ 76 | 'fingerprint' => $fingerprint 77 | ]); 78 | 79 | if ($body->success == false) { 80 | throw new ChiaErrorException($body->error); 81 | } 82 | return true; 83 | } 84 | 85 | public function deleteAllKeys() 86 | { 87 | $body = $this->_api->post('/delete_all_keys'); 88 | 89 | if ($body->success == false) { 90 | throw new ChiaErrorException($body->error); 91 | } 92 | return true; 93 | } 94 | 95 | public function getSyncStatus() 96 | { 97 | $body = $this->_api->post('/get_sync_status'); 98 | 99 | if ($body->success == false) { 100 | throw new ChiaErrorException($body->error); 101 | } 102 | unset($body->success); 103 | return $body; 104 | } 105 | 106 | public function getHeightInfo() 107 | { 108 | $body = $this->_api->post('/get_height_info'); 109 | 110 | if ($body->success == false) { 111 | throw new ChiaErrorException($body->error); 112 | } 113 | return $body->height; 114 | } 115 | 116 | public function getNetworkInfo() 117 | { 118 | $body = $this->_api->post('/get_network_info'); 119 | 120 | if ($body->success == false) { 121 | throw new ChiaErrorException($body->error); 122 | } 123 | unset($body->success); 124 | return $body; 125 | } 126 | 127 | public function getWallets() 128 | { 129 | $body = $this->_api->post('/get_wallets'); 130 | 131 | if ($body->success == false) { 132 | throw new ChiaErrorException($body->error); 133 | } 134 | return $body->wallets; 135 | } 136 | 137 | public function createNewWallet($params) 138 | { 139 | if (!isset($params['host']) || empty($params['host'])) { 140 | throw new ChiaErrorException('host cannot be empty'); 141 | } 142 | if (!isset($params['wallet_type']) || empty($params['wallet_type'])) { 143 | throw new ChiaErrorException('wallet_type cannot be empty'); 144 | } 145 | 146 | if (!in_array($params['wallet_type'], ['cc_wallet', 'rl_wallet', 'did_wallet'])) { 147 | throw new ChiaErrorException('wallet_type error'); 148 | } 149 | 150 | if ($params['wallet_type'] == 'cc_wallet') { 151 | if (!isset($params['mode']) || empty($params['mode'])) { 152 | throw new ChiaErrorException('mode cannot be empty'); 153 | } 154 | if ($params['mode'] == 'new') { 155 | } elseif ($params['mode'] == 'existing') { 156 | } 157 | } elseif ($params['wallet_type'] == 'rl_wallet') { 158 | if (!isset($params['rl_type']) || empty($params['rl_type'])) { 159 | throw new ChiaErrorException('rl_type cannot be empty'); 160 | } 161 | if ($params['rl_type'] == 'admin') { 162 | } elseif ($params['rl_type'] == 'user') { 163 | } 164 | } elseif ($params['wallet_type'] == 'did_wallet') { 165 | if (!isset($params['did_type']) || empty($params['did_type'])) { 166 | throw new ChiaErrorException('did_type cannot be empty'); 167 | } 168 | if ($params['did_type'] == 'new') { 169 | } elseif ($params['did_type'] == 'recovery') { 170 | } 171 | } 172 | 173 | $body = $this->_api->post('/create_new_wallet', $params); 174 | 175 | if ($body->success == false) { 176 | throw new ChiaErrorException($body->error); 177 | } 178 | return true; 179 | } 180 | 181 | public function getWalletBalance(int $walletId) 182 | { 183 | $body = $this->_api->post('/get_wallet_balance', [ 184 | 'wallet_id' => $walletId 185 | ]); 186 | 187 | if ($body->success == false) { 188 | throw new ChiaErrorException($body->error); 189 | } 190 | return $body->wallet_balance; 191 | } 192 | public function getTransaction(string $transactionId) 193 | { 194 | $body = $this->_api->post('/get_transaction', [ 195 | 'transaction_id' => $transactionId 196 | ]); 197 | 198 | if ($body->success == false) { 199 | throw new ChiaErrorException($body->error); 200 | } 201 | unset($body->success); 202 | return $body; 203 | } 204 | 205 | public function getTransactions(int $walletId) 206 | { 207 | $body = $this->_api->post('/get_transactions', [ 208 | 'wallet_id' => $walletId 209 | ]); 210 | 211 | if ($body->success == false) { 212 | throw new ChiaErrorException($body->error); 213 | } 214 | return $body->transactions; 215 | } 216 | 217 | public function getNextAddress(int $walletId, bool $newAddress = true): Address 218 | { 219 | $body = $this->_api->post('/get_next_address', [ 220 | 'wallet_id' => $walletId, 221 | 'new_address' => $newAddress 222 | ]); 223 | 224 | if ($body->success == false) { 225 | throw new ChiaErrorException($body->error); 226 | } 227 | return new Address($body->address); 228 | } 229 | 230 | public function sendTransaction($walletId, $address, $amount, $fee) 231 | { 232 | $body = $this->_api->post('/send_transaction', [ 233 | 'wallet_id' => $walletId, 234 | 'address' => $address, 235 | 'amount' => $amount, 236 | 'fee' => $fee 237 | ]); 238 | 239 | if ($body->success == false) { 240 | throw new ChiaErrorException($body->error); 241 | } 242 | unset($body->success); 243 | return $body; 244 | } 245 | 246 | public function createBackup($filePath) 247 | { 248 | $body = $this->_api->post('/create_backup', [ 249 | 'file_path' => $filePath 250 | ]); 251 | 252 | if ($body->success == false) { 253 | throw new ChiaErrorException($body->error); 254 | } 255 | return $body; 256 | } 257 | 258 | public function getTransactionCount(int $walletId) 259 | { 260 | $body = $this->_api->post('/get_transaction_count', [ 261 | 'wallet_id' => $walletId 262 | ]); 263 | 264 | if ($body->success == false) { 265 | throw new ChiaErrorException($body->error); 266 | } 267 | return $body->count; 268 | } 269 | 270 | public function getFarmedAmount() 271 | { 272 | $body = $this->_api->post('/get_farmed_amount'); 273 | 274 | if ($body->success == false) { 275 | throw new ChiaErrorException($body->error); 276 | } 277 | unset($body->success); 278 | return $body; 279 | } 280 | 281 | public function farmBlock(string $address) 282 | { 283 | $body = $this->_api->post('/farm_block', [ 284 | 'address' => $address 285 | ]); 286 | 287 | if ($body->success == false) { 288 | throw new ChiaErrorException($body->error); 289 | } 290 | return true; 291 | } 292 | 293 | public function getInitialFreezePeriod() 294 | { 295 | $body = $this->_api->post('/get_initial_freeze_period'); 296 | 297 | if ($body->success == false) { 298 | throw new ChiaErrorException($body->error); 299 | } 300 | return $body->INITIAL_FREEZE_END_TIMESTAMP; 301 | } 302 | 303 | public function createSignedTransaction() 304 | { 305 | $body = $this->_api->post('/create_signed_transaction'); 306 | 307 | if ($body->success == false) { 308 | throw new ChiaErrorException($body->error); 309 | } 310 | return $body; 311 | } 312 | } 313 | -------------------------------------------------------------------------------- /tests/FullNodeTest.php: -------------------------------------------------------------------------------- 1 | 9 | * @license https://github.com/Fenguoz/chia-php/blob/master/LICENSE MIT 10 | * @link https://github.com/Fenguoz/chia-php 11 | */ 12 | 13 | namespace Tests; 14 | 15 | use Chia\Api; 16 | use Chia\FullNode; 17 | use GuzzleHttp\Client; 18 | use PHPUnit\Framework\TestCase; 19 | 20 | class FullNodeTest extends TestCase 21 | { 22 | const HEIGHT = 10000; 23 | const HEADER_HASH = '0x7b1f89923b5d7a5fafbb5a9c379adb4fc8c49be491e12fbddd19c7317544bdd0'; 24 | const NEWER_BLOCK_HEADER_HASH = '0xb9663a08958712cd0dc9e736e39103d8b837b90dcd41c8c3ad2c75703c3e1497'; 25 | const OLDER_BLOCK_HEADER_HASH = '0x75083cc77cce34680d5a1a2e576e4072e3fba1cee4d7336f5a0ebc2497019bea'; 26 | const PUZZLE_HASH = '0xae2910a112f9e6bf435a4b1fa96fd899ec12902312f89f67061b6d61fc3ee3ef'; 27 | const COIN_NAME = '0x6670bce2194f74bc02c9becc6266fa7935166cf204859a6760c451b1f1d3ca8d'; 28 | const MEMPOOL_TX_ID = '0xe3438724619b62e63bfedeb7e2ae8a6130dc58948a4a3d7bbde876ed40b03dd3'; 29 | const START = 1; 30 | const END = 2; 31 | 32 | private function fullNode() 33 | { 34 | $config = [ 35 | 'base_uri' => 'https://localhost:8555', 36 | 'verify' => false, 37 | 'cert' => __DIR__ . '/private_full_node.crt', 38 | 'ssl_key' => __DIR__ . '/private_full_node.key', 39 | 'headers' => [ 40 | 'Content-Type' => 'application/json' 41 | ] 42 | ]; 43 | $api = new Api(new Client($config)); 44 | $fullNode = new FullNode($api, []); 45 | return $fullNode; 46 | } 47 | 48 | public function testGetBlockchainState() 49 | { 50 | $data = $this->fullNode()->getBlockchainState(); 51 | // var_dump($data); 52 | $this->assertTrue(true); 53 | } 54 | 55 | public function testGetBlock() 56 | { 57 | $data = $this->fullNode()->getBlock(self::HEADER_HASH); 58 | // var_dump($data); 59 | $this->assertTrue(true); 60 | } 61 | 62 | public function testGetBlocks() 63 | { 64 | $data = $this->fullNode()->getBlocks(self::START,self::END); 65 | // var_dump($data); 66 | $this->assertTrue(true); 67 | } 68 | 69 | public function testGetBlockRecordByHeight() 70 | { 71 | $data = $this->fullNode()->getBlockRecordByHeight(self::HEIGHT); 72 | // var_dump($data); 73 | $this->assertTrue(true); 74 | } 75 | 76 | public function testGetBlockRecord() 77 | { 78 | $data = $this->fullNode()->getBlockRecord(self::HEADER_HASH); 79 | // var_dump($data); 80 | $this->assertTrue(true); 81 | } 82 | 83 | public function testGetBlockRecords() 84 | { 85 | $data = $this->fullNode()->getBlockRecords(self::START, self::END); 86 | // var_dump($data); 87 | $this->assertTrue(true); 88 | } 89 | 90 | public function testGetUnfinishedBlockHeaders() 91 | { 92 | $data = $this->fullNode()->getUnfinishedBlockHeaders(); 93 | // var_dump($data); 94 | $this->assertTrue(true); 95 | } 96 | 97 | public function testGetNetworkSpace() 98 | { 99 | $data = $this->fullNode()->getNetworkSpace(self::NEWER_BLOCK_HEADER_HASH, self::OLDER_BLOCK_HEADER_HASH); 100 | // var_dump($data); 101 | $this->assertTrue(true); 102 | } 103 | 104 | public function testGetAdditionsAndRemovals() 105 | { 106 | $data = $this->fullNode()->getAdditionsAndRemovals(self::HEADER_HASH); 107 | // var_dump($data); 108 | $this->assertTrue(true); 109 | } 110 | 111 | public function testGetInitialFreezePeriod() 112 | { 113 | $data = $this->fullNode()->getInitialFreezePeriod(); 114 | // var_dump($data); 115 | $this->assertTrue(true); 116 | } 117 | 118 | public function testGetNetworkInfo() 119 | { 120 | $data = $this->fullNode()->getNetworkInfo(); 121 | // var_dump($data); 122 | $this->assertTrue(true); 123 | } 124 | 125 | public function testGetCoinRecordsByPuzzleHash() 126 | { 127 | $data = $this->fullNode()->getCoinRecordsByPuzzleHash(self::PUZZLE_HASH); 128 | // var_dump($data); 129 | $this->assertTrue(true); 130 | } 131 | 132 | public function testGetCoinRecordsByPuzzleHashes() 133 | { 134 | $data = $this->fullNode()->getCoinRecordsByPuzzleHashes([self::PUZZLE_HASH]); 135 | // var_dump($data); 136 | $this->assertTrue(true); 137 | } 138 | 139 | public function testGetCoinRecordByName() 140 | { 141 | $data = $this->fullNode()->getCoinRecordByName(self::COIN_NAME); 142 | // var_dump($data); 143 | $this->assertTrue(true); 144 | } 145 | 146 | // public function testPushTx() 147 | // { 148 | // $data = $this->fullNode()->pushTx(); 149 | // var_dump($data); 150 | // $this->assertTrue(true); 151 | // } 152 | 153 | public function testGetAllMempoolTxIds() 154 | { 155 | $data = $this->fullNode()->getAllMempoolTxIds(); 156 | // var_dump($data); 157 | $this->assertTrue(true); 158 | } 159 | 160 | public function testGetAllMempoolItems() 161 | { 162 | $data = $this->fullNode()->getAllMempoolItems(); 163 | // var_dump($data); 164 | $this->assertTrue(true); 165 | } 166 | 167 | public function testGetMempoolItemByTxId() 168 | { 169 | $data = $this->fullNode()->getMempoolItemByTxId(self::MEMPOOL_TX_ID); 170 | // var_dump($data); 171 | $this->assertTrue(true); 172 | } 173 | 174 | } 175 | -------------------------------------------------------------------------------- /tests/WalletTest.php: -------------------------------------------------------------------------------- 1 | 9 | * @license https://github.com/Fenguoz/chia-php/blob/master/LICENSE MIT 10 | * @link https://github.com/Fenguoz/chia-php 11 | */ 12 | 13 | namespace Tests; 14 | 15 | use Chia\Api; 16 | use Chia\Wallet; 17 | use GuzzleHttp\Client; 18 | use PHPUnit\Framework\TestCase; 19 | 20 | class WalletTest extends TestCase 21 | { 22 | const WALLET_ID = 1; 23 | const FINGERPTINT = 10000000000; 24 | const MNEMONIC = [ 25 | 'this', 26 | 'is', 27 | 'your', 28 | 'mnemonic' 29 | ]; 30 | const ADDRESS = 'xch14c5....'; 31 | const COIN_NAME = '0x6670bce2194f74bc02c9becc6266fa7935166cf204859a6760c451b1f1d3ca8d'; 32 | const PUZZLE_HASH = '0xae2910a112f9e6bf435a4b1fa96fd899ec12902312f89f67061b6d61fc3ee3ef'; 33 | const FILE_PATH = '/this/is/file/path'; 34 | 35 | private function wallet() 36 | { 37 | $config = [ 38 | 'base_uri' => 'https://localhost:9256', 39 | 'verify' => false, 40 | 'cert' => __DIR__ . '/private_wallet.crt', 41 | 'ssl_key' => __DIR__ . '/private_wallet.key', 42 | 'headers' => [ 43 | 'Content-Type' => 'application/json' 44 | ] 45 | ]; 46 | $api = new Api(new Client($config)); 47 | $wallet = new Wallet($api, []); 48 | return $wallet; 49 | } 50 | 51 | public function testLogIn() 52 | { 53 | $data = $this->wallet()->logIn(self::FINGERPTINT); 54 | // var_dump($data); 55 | $this->assertTrue(true); 56 | } 57 | 58 | public function testGetPublicKeys() 59 | { 60 | $data = $this->wallet()->getPublicKeys(); 61 | // var_dump($data); 62 | $this->assertTrue(true); 63 | } 64 | 65 | public function testGetPrivateKey() 66 | { 67 | $data = $this->wallet()->getPrivateKey(self::FINGERPTINT); 68 | // var_dump($data); 69 | $this->assertTrue(true); 70 | } 71 | 72 | public function testGenerateMnemonic() 73 | { 74 | $data = $this->wallet()->generateMnemonic(); 75 | // var_dump($data); 76 | $this->assertTrue(true); 77 | } 78 | 79 | public function testAddKey() 80 | { 81 | $data = $this->wallet()->addKey(self::MNEMONIC); 82 | // var_dump($data); 83 | $this->assertTrue(true); 84 | } 85 | 86 | // public function testDeleteKey() 87 | // { 88 | // $data = $this->wallet()->deleteKey(self::FINGERPTINT); 89 | // // var_dump($data); 90 | // $this->assertTrue(true); 91 | // } 92 | // public function testDeleteAllKeys() 93 | // { 94 | // $data = $this->wallet()->deleteAllKeys(); 95 | // // var_dump($data); 96 | // $this->assertTrue(true); 97 | // } 98 | 99 | public function testGetSyncStatus() 100 | { 101 | $data = $this->wallet()->getSyncStatus(); 102 | // var_dump($data); 103 | $this->assertTrue(true); 104 | } 105 | 106 | public function testGetHeightInfo() 107 | { 108 | $data = $this->wallet()->getHeightInfo(); 109 | // var_dump($data); 110 | $this->assertTrue(true); 111 | } 112 | public function testFarmBlock() 113 | { 114 | $data = $this->wallet()->farmBlock(self::ADDRESS); 115 | // var_dump($data); 116 | $this->assertTrue(true); 117 | } 118 | 119 | public function testGetInitialFreezePeriod() 120 | { 121 | $data = $this->wallet()->getInitialFreezePeriod(); 122 | // var_dump($data); 123 | $this->assertTrue(true); 124 | } 125 | 126 | public function testGetNetworkInfo() 127 | { 128 | $data = $this->wallet()->getNetworkInfo(); 129 | // var_dump($data); 130 | $this->assertTrue(true); 131 | } 132 | 133 | public function testGetWallets() 134 | { 135 | $data = $this->wallet()->getWallets(); 136 | // var_dump($data); 137 | $this->assertTrue(true); 138 | } 139 | 140 | // public function testCreateNewWallet() 141 | // { 142 | // $params = []; 143 | // $data = $this->wallet()->createNewWallet($params); 144 | // $this->assertTrue(true); 145 | // } 146 | 147 | public function testGetWalletBalance() 148 | { 149 | $data = $this->wallet()->getWalletBalance(self::WALLET_ID); 150 | // var_dump($data); 151 | $this->assertTrue(true); 152 | } 153 | 154 | public function testGetTransaction() 155 | { 156 | $data = $this->wallet()->getTransaction(self::COIN_NAME); 157 | // var_dump($data); 158 | $this->assertTrue(true); 159 | } 160 | 161 | public function testGetTransactions() 162 | { 163 | $data = $this->wallet()->getTransactions(self::WALLET_ID); 164 | // var_dump($data); 165 | $this->assertTrue(true); 166 | } 167 | 168 | public function testGetNextAddress() 169 | { 170 | $data = $this->wallet()->getNextAddress(self::WALLET_ID); 171 | // var_dump($data); 172 | $this->assertTrue(true); 173 | } 174 | 175 | // public function testSendTransaction() 176 | // { 177 | // $amount = 1; 178 | // $fee = 0; 179 | // $data = $this->wallet()->sendTransaction(self::WALLET_ID, self::ADDRESS, $amount, $fee); 180 | // // var_dump($data); 181 | // $this->assertTrue(true); 182 | // } 183 | 184 | // public function testCreateBackup() 185 | // { 186 | // $data = $this->wallet()->createBackup(self::FILE_PATH); 187 | // // var_dump($data); 188 | // $this->assertTrue(true); 189 | // } 190 | 191 | public function testGetTransactionCount() 192 | { 193 | $data = $this->wallet()->getTransactionCount(self::WALLET_ID); 194 | // var_dump($data); 195 | $this->assertTrue(true); 196 | } 197 | 198 | public function testGetFarmedAmount() 199 | { 200 | $data = $this->wallet()->getFarmedAmount(self::WALLET_ID); 201 | // var_dump($data); 202 | $this->assertTrue(true); 203 | } 204 | 205 | // public function testCreateSignedTransaction() 206 | // { 207 | // $data = $this->wallet()->createSignedTransaction(self::WALLET_ID); 208 | // // var_dump($data); 209 | // $this->assertTrue(true); 210 | // } 211 | } 212 | -------------------------------------------------------------------------------- /tests/private_full_node.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | -----END CERTIFICATE----- 3 | -------------------------------------------------------------------------------- /tests/private_full_node.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | -----END RSA PRIVATE KEY----- 3 | -------------------------------------------------------------------------------- /tests/private_wallet.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | -----END CERTIFICATE----- 3 | -------------------------------------------------------------------------------- /tests/private_wallet.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | -----END RSA PRIVATE KEY----- 3 | --------------------------------------------------------------------------------