├── .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 | [](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 |
--------------------------------------------------------------------------------