Contract.php 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860
  1. <?php
  2. /**
  3. * This file is part of web3.php package.
  4. *
  5. * (c) Kuan-Cheng,Lai <alk03073135@gmail.com>
  6. *
  7. * @author Peter Lai <alk03073135@gmail.com>
  8. * @license MIT
  9. */
  10. namespace Web3;
  11. use InvalidArgumentException;
  12. use Web3\Providers\Provider;
  13. use Web3\Providers\HttpProvider;
  14. use Web3\RequestManagers\RequestManager;
  15. use Web3\RequestManagers\HttpRequestManager;
  16. use Web3\Utils;
  17. use Web3\Eth;
  18. use Web3\Contracts\Ethabi;
  19. use Web3\Contracts\Types\Address;
  20. use Web3\Contracts\Types\Boolean;
  21. use Web3\Contracts\Types\Bytes;
  22. use Web3\Contracts\Types\DynamicBytes;
  23. use Web3\Contracts\Types\Integer;
  24. use Web3\Contracts\Types\Str;
  25. use Web3\Contracts\Types\Uinteger;
  26. use Web3\Validators\AddressValidator;
  27. use Web3\Validators\HexValidator;
  28. use Web3\Validators\StringValidator;
  29. use Web3\Validators\TagValidator;
  30. use Web3\Validators\QuantityValidator;
  31. use Web3\Formatters\AddressFormatter;
  32. class Contract
  33. {
  34. /**
  35. * provider
  36. *
  37. * @var \Web3\Providers\Provider
  38. */
  39. protected $provider;
  40. /**
  41. * abi
  42. *
  43. * @var array
  44. */
  45. protected $abi;
  46. /**
  47. * constructor
  48. *
  49. * @var array
  50. */
  51. protected $constructor = [];
  52. /**
  53. * functions
  54. *
  55. * @var array
  56. */
  57. protected $functions = [];
  58. /**
  59. * events
  60. *
  61. * @var array
  62. */
  63. protected $events = [];
  64. /**
  65. * toAddress
  66. *
  67. * @var string
  68. */
  69. protected $toAddress;
  70. /**
  71. * bytecode
  72. *
  73. * @var string
  74. */
  75. protected $bytecode;
  76. /**
  77. * eth
  78. *
  79. * @var \Web3\Eth
  80. */
  81. protected $eth;
  82. /**
  83. * ethabi
  84. *
  85. * @var \Web3\Contracts\Ethabi
  86. */
  87. protected $ethabi;
  88. /**
  89. * defaultBlock
  90. *
  91. * @var mixed
  92. */
  93. protected $defaultBlock;
  94. /**
  95. * construct
  96. *
  97. * @param string|\Web3\Providers\Provider $provider
  98. * @param string|\stdClass|array $abi
  99. * @param mixed $defaultBlock
  100. * @return void
  101. */
  102. public function __construct($provider, $abi, $defaultBlock = 'latest')
  103. {
  104. if (is_string($provider) && (filter_var($provider, FILTER_VALIDATE_URL) !== false)) {
  105. // check the uri schema
  106. if (preg_match('/^https?:\/\//', $provider) === 1) {
  107. $requestManager = new HttpRequestManager($provider);
  108. $this->provider = new HttpProvider($requestManager);
  109. }
  110. } else if ($provider instanceof Provider) {
  111. $this->provider = $provider;
  112. }
  113. $abiArray = [];
  114. if (is_string($abi)) {
  115. $abiArray = json_decode($abi, true);
  116. if (JSON_ERROR_NONE !== json_last_error()) {
  117. throw new InvalidArgumentException('abi decode error: ' . json_last_error_msg());
  118. }
  119. } else {
  120. $abiArray = Utils::jsonToArray($abi);
  121. }
  122. foreach ($abiArray as $item) {
  123. if (isset($item['type'])) {
  124. if ($item['type'] === 'function') {
  125. $this->functions[] = $item;
  126. } elseif ($item['type'] === 'constructor') {
  127. $this->constructor = $item;
  128. } elseif ($item['type'] === 'event') {
  129. $this->events[$item['name']] = $item;
  130. }
  131. }
  132. }
  133. if (TagValidator::validate($defaultBlock) || QuantityValidator::validate($defaultBlock)) {
  134. $this->defaultBlock = $defaultBlock;
  135. } else {
  136. $this->$defaultBlock = 'latest';
  137. }
  138. $this->abi = $abiArray;
  139. $this->eth = new Eth($this->provider);
  140. $this->ethabi = new Ethabi([
  141. 'address' => new Address,
  142. 'bool' => new Boolean,
  143. 'bytes' => new Bytes,
  144. 'dynamicBytes' => new DynamicBytes,
  145. 'int' => new Integer,
  146. 'string' => new Str,
  147. 'uint' => new Uinteger,
  148. ]);
  149. }
  150. /**
  151. * call
  152. *
  153. * @param string $name
  154. * @param array $arguments
  155. * @return void
  156. */
  157. // public function __call($name, $arguments)
  158. // {
  159. // if (empty($this->provider)) {
  160. // throw new \RuntimeException('Please set provider first.');
  161. // }
  162. // $class = explode('\\', get_class());
  163. // if (preg_match('/^[a-zA-Z0-9]+$/', $name) === 1) {
  164. // }
  165. // }
  166. /**
  167. * get
  168. *
  169. * @param string $name
  170. * @return mixed
  171. */
  172. public function __get($name)
  173. {
  174. $method = 'get' . ucfirst($name);
  175. if (method_exists($this, $method)) {
  176. return call_user_func_array([$this, $method], []);
  177. }
  178. return false;
  179. }
  180. /**
  181. * set
  182. *
  183. * @param string $name
  184. * @param mixed $value
  185. * @return mixed
  186. */
  187. public function __set($name, $value)
  188. {
  189. $method = 'set' . ucfirst($name);
  190. if (method_exists($this, $method)) {
  191. return call_user_func_array([$this, $method], [$value]);
  192. }
  193. return false;
  194. }
  195. /**
  196. * getProvider
  197. *
  198. * @return \Web3\Providers\Provider
  199. */
  200. public function getProvider()
  201. {
  202. return $this->provider;
  203. }
  204. /**
  205. * setProvider
  206. *
  207. * @param \Web3\Providers\Provider $provider
  208. * @return $this
  209. */
  210. public function setProvider($provider)
  211. {
  212. if ($provider instanceof Provider) {
  213. $this->provider = $provider;
  214. }
  215. return $this;
  216. }
  217. /**
  218. * getDefaultBlock
  219. *
  220. * @return string
  221. */
  222. public function getDefaultBlock()
  223. {
  224. return $this->defaultBlock;
  225. }
  226. /**
  227. * setDefaultBlock
  228. *
  229. * @param mixed $defaultBlock
  230. * @return $this
  231. */
  232. public function setDefaultBlock($defaultBlock)
  233. {
  234. if (TagValidator::validate($defaultBlock) || QuantityValidator::validate($defaultBlock)) {
  235. $this->defaultBlock = $defaultBlock;
  236. } else {
  237. $this->$defaultBlock = 'latest';
  238. }
  239. return $this;
  240. }
  241. /**
  242. * getFunctions
  243. *
  244. * @return array
  245. */
  246. public function getFunctions()
  247. {
  248. return $this->functions;
  249. }
  250. /**
  251. * getEvents
  252. *
  253. * @return array
  254. */
  255. public function getEvents()
  256. {
  257. return $this->events;
  258. }
  259. /**
  260. * @return string
  261. */
  262. public function getToAddress()
  263. {
  264. return $this->toAddress;
  265. }
  266. /**
  267. * getConstructor
  268. *
  269. * @return array
  270. */
  271. public function getConstructor()
  272. {
  273. return $this->constructor;
  274. }
  275. /**
  276. * getAbi
  277. *
  278. * @return array
  279. */
  280. public function getAbi()
  281. {
  282. return $this->abi;
  283. }
  284. /**
  285. * setAbi
  286. *
  287. * @param string $abi
  288. * @return $this
  289. */
  290. public function setAbi($abi)
  291. {
  292. return $this->abi($abi);
  293. }
  294. /**
  295. * getEthabi
  296. *
  297. * @return array
  298. */
  299. public function getEthabi()
  300. {
  301. return $this->ethabi;
  302. }
  303. /**
  304. * getEth
  305. *
  306. * @return \Web3\Eth
  307. */
  308. public function getEth()
  309. {
  310. return $this->eth;
  311. }
  312. /**
  313. * setBytecode
  314. *
  315. * @param string $bytecode
  316. * @return $this
  317. */
  318. public function setBytecode($bytecode)
  319. {
  320. return $this->bytecode($bytecode);
  321. }
  322. /**
  323. * setToAddress
  324. *
  325. * @param string $bytecode
  326. * @return $this
  327. */
  328. public function setToAddress($address)
  329. {
  330. return $this->at($address);
  331. }
  332. /**
  333. * at
  334. *
  335. * @param string $address
  336. * @return $this
  337. */
  338. public function at($address)
  339. {
  340. if (AddressValidator::validate($address) === false) {
  341. throw new InvalidArgumentException('Please make sure address is valid.');
  342. }
  343. $this->toAddress = AddressFormatter::format($address);
  344. return $this;
  345. }
  346. /**
  347. * bytecode
  348. *
  349. * @param string $bytecode
  350. * @return $this
  351. */
  352. public function bytecode($bytecode)
  353. {
  354. if (HexValidator::validate($bytecode) === false) {
  355. throw new InvalidArgumentException('Please make sure bytecode is valid.');
  356. }
  357. $this->bytecode = Utils::stripZero($bytecode);
  358. return $this;
  359. }
  360. /**
  361. * abi
  362. *
  363. * @param string $abi
  364. * @return $this
  365. */
  366. public function abi($abi)
  367. {
  368. if (StringValidator::validate($abi) === false) {
  369. throw new InvalidArgumentException('Please make sure abi is valid.');
  370. }
  371. $abiArray = [];
  372. if (is_string($abi)) {
  373. $abiArray = json_decode($abi, true);
  374. if (JSON_ERROR_NONE !== json_last_error()) {
  375. throw new InvalidArgumentException('abi decode error: ' . json_last_error_msg());
  376. }
  377. } else {
  378. $abiArray = Utils::jsonToArray($abi);
  379. }
  380. foreach ($abiArray as $item) {
  381. if (isset($item['type'])) {
  382. if ($item['type'] === 'function') {
  383. $this->functions[] = $item;
  384. } elseif ($item['type'] === 'constructor') {
  385. $this->constructor = $item;
  386. } elseif ($item['type'] === 'event') {
  387. $this->events[$item['name']] = $item;
  388. }
  389. }
  390. }
  391. $this->abi = $abiArray;
  392. return $this;
  393. }
  394. /**
  395. * new
  396. * Deploy a contruct with params.
  397. *
  398. * @param mixed
  399. * @return void
  400. */
  401. public function new()
  402. {
  403. if (isset($this->constructor)) {
  404. $constructor = $this->constructor;
  405. $arguments = func_get_args();
  406. $callback = array_pop($arguments);
  407. $input_count = isset($constructor['inputs']) ? count($constructor['inputs']) : 0;
  408. if (count($arguments) < $input_count) {
  409. throw new InvalidArgumentException('Please make sure you have put all constructor params and callback.');
  410. }
  411. if (is_callable($callback) !== true) {
  412. throw new \InvalidArgumentException('The last param must be callback function.');
  413. }
  414. if (!isset($this->bytecode)) {
  415. throw new \InvalidArgumentException('Please call bytecode($bytecode) before new().');
  416. }
  417. $params = array_splice($arguments, 0, $input_count);
  418. $data = $this->ethabi->encodeParameters($constructor, $params);
  419. $transaction = [];
  420. if (count($arguments) > 0) {
  421. $transaction = $arguments[0];
  422. }
  423. $transaction['data'] = '0x' . $this->bytecode . Utils::stripZero($data);
  424. $this->eth->sendTransaction($transaction, function ($err, $transaction) use ($callback){
  425. if ($err !== null) {
  426. return call_user_func($callback, $err, null);
  427. }
  428. return call_user_func($callback, null, $transaction);
  429. });
  430. }
  431. }
  432. /**
  433. * send
  434. * Send function method.
  435. *
  436. * @param mixed
  437. * @return void
  438. */
  439. public function send()
  440. {
  441. if (isset($this->functions)) {
  442. $arguments = func_get_args();
  443. $method = array_splice($arguments, 0, 1)[0];
  444. $callback = array_pop($arguments);
  445. if (!is_string($method)) {
  446. throw new InvalidArgumentException('Please make sure the method is string.');
  447. }
  448. $functions = [];
  449. foreach ($this->functions as $function) {
  450. if ($function["name"] === $method) {
  451. $functions[] = $function;
  452. }
  453. };
  454. if (count($functions) < 1) {
  455. throw new InvalidArgumentException('Please make sure the method exists.');
  456. }
  457. if (is_callable($callback) !== true) {
  458. throw new \InvalidArgumentException('The last param must be callback function.');
  459. }
  460. // check the last one in arguments is transaction object
  461. $argsLen = count($arguments);
  462. $transaction = [];
  463. $hasTransaction = false;
  464. if ($argsLen > 0) {
  465. $transaction = $arguments[$argsLen - 1];
  466. }
  467. if (
  468. isset($transaction["from"]) ||
  469. isset($transaction["to"]) ||
  470. isset($transaction["gas"]) ||
  471. isset($transaction["gasPrice"]) ||
  472. isset($transaction["value"]) ||
  473. isset($transaction["data"]) ||
  474. isset($transaction["nonce"])
  475. ) {
  476. $hasTransaction = true;
  477. } else {
  478. $transaction = [];
  479. }
  480. $params = [];
  481. $data = "";
  482. $functionName = "";
  483. foreach ($functions as $function) {
  484. if ($hasTransaction) {
  485. if ($argsLen - 1 !== count($function['inputs'])) {
  486. continue;
  487. } else {
  488. $paramsLen = $argsLen - 1;
  489. }
  490. } else {
  491. if ($argsLen !== count($function['inputs'])) {
  492. continue;
  493. } else {
  494. $paramsLen = $argsLen;
  495. }
  496. }
  497. try {
  498. $params = array_splice($arguments, 0, $paramsLen);
  499. $data = $this->ethabi->encodeParameters($function, $params);
  500. $functionName = Utils::jsonMethodToString($function);
  501. } catch (InvalidArgumentException $e) {
  502. continue;
  503. }
  504. break;
  505. }
  506. if (empty($data) || empty($functionName)) {
  507. throw new InvalidArgumentException('Please make sure you have put all function params and callback.');
  508. }
  509. $functionSignature = $this->ethabi->encodeFunctionSignature($functionName);
  510. $transaction['to'] = $this->toAddress;
  511. $transaction['data'] = $functionSignature . Utils::stripZero($data);
  512. $this->eth->sendTransaction($transaction, function ($err, $transaction) use ($callback){
  513. if ($err !== null) {
  514. return call_user_func($callback, $err, null);
  515. }
  516. return call_user_func($callback, null, $transaction);
  517. });
  518. }
  519. }
  520. /**
  521. * call
  522. * Call function method.
  523. *
  524. * @param mixed
  525. * @return void
  526. */
  527. public function call()
  528. {
  529. if (isset($this->functions)) {
  530. $arguments = func_get_args();
  531. $method = array_splice($arguments, 0, 1)[0];
  532. $callback = array_pop($arguments);
  533. if (!is_string($method)) {
  534. throw new InvalidArgumentException('Please make sure the method is string.');
  535. }
  536. $functions = [];
  537. foreach ($this->functions as $function) {
  538. if ($function["name"] === $method) {
  539. $functions[] = $function;
  540. }
  541. };
  542. if (count($functions) < 1) {
  543. throw new InvalidArgumentException('Please make sure the method exists.');
  544. }
  545. if (is_callable($callback) !== true) {
  546. throw new \InvalidArgumentException('The last param must be callback function.');
  547. }
  548. // check the arguments
  549. $argsLen = count($arguments);
  550. $transaction = [];
  551. $defaultBlock = $this->defaultBlock;
  552. $params = [];
  553. $data = "";
  554. $functionName = "";
  555. foreach ($functions as $function) {
  556. try {
  557. $paramsLen = count($function['inputs']);
  558. $params = array_slice($arguments, 0, $paramsLen);
  559. $data = $this->ethabi->encodeParameters($function, $params);
  560. $functionName = Utils::jsonMethodToString($function);
  561. } catch (InvalidArgumentException $e) {
  562. continue;
  563. }
  564. break;
  565. }
  566. if (empty($data) || empty($functionName)) {
  567. throw new InvalidArgumentException('Please make sure you have put all function params and callback.');
  568. }
  569. // remove arguments
  570. array_splice($arguments, 0, $paramsLen);
  571. $argsLen -= $paramsLen;
  572. if ($argsLen > 1) {
  573. $defaultBlock = $arguments[$argsLen - 1];
  574. $transaction = $arguments[$argsLen - 2];
  575. } else if ($argsLen > 0) {
  576. if (is_array($arguments[$argsLen - 1])) {
  577. $transaction = $arguments[$argsLen - 1];
  578. } else {
  579. $defaultBlock = $arguments[$argsLen - 1];
  580. }
  581. }
  582. if (!TagValidator::validate($defaultBlock) && !QuantityValidator::validate($defaultBlock)) {
  583. $defaultBlock = $this->defaultBlock;
  584. }
  585. if (
  586. !is_array($transaction) &&
  587. !isset($transaction["from"]) &&
  588. !isset($transaction["to"]) &&
  589. !isset($transaction["gas"]) &&
  590. !isset($transaction["gasPrice"]) &&
  591. !isset($transaction["value"]) &&
  592. !isset($transaction["data"]) &&
  593. !isset($transaction["nonce"])
  594. ) {
  595. $transaction = [];
  596. }
  597. $functionSignature = $this->ethabi->encodeFunctionSignature($functionName);
  598. $transaction['to'] = $this->toAddress;
  599. $transaction['data'] = $functionSignature . Utils::stripZero($data);
  600. $this->eth->call($transaction, $defaultBlock, function ($err, $transaction) use ($callback, $function){
  601. if ($err !== null) {
  602. return call_user_func($callback, $err, null);
  603. }
  604. $decodedTransaction = $this->ethabi->decodeParameters($function, $transaction);
  605. return call_user_func($callback, null, $decodedTransaction);
  606. });
  607. }
  608. }
  609. /**
  610. * estimateGas
  611. * Estimate function gas.
  612. *
  613. * @param mixed
  614. * @return void
  615. */
  616. public function estimateGas()
  617. {
  618. if (isset($this->functions) || isset($this->constructor)) {
  619. $arguments = func_get_args();
  620. $callback = array_pop($arguments);
  621. if (empty($this->toAddress) && !empty($this->bytecode)) {
  622. $constructor = $this->constructor;
  623. if (count($arguments) < count($constructor['inputs'])) {
  624. throw new InvalidArgumentException('Please make sure you have put all constructor params and callback.');
  625. }
  626. if (is_callable($callback) !== true) {
  627. throw new \InvalidArgumentException('The last param must be callback function.');
  628. }
  629. if (!isset($this->bytecode)) {
  630. throw new \InvalidArgumentException('Please call bytecode($bytecode) before estimateGas().');
  631. }
  632. $params = array_splice($arguments, 0, count($constructor['inputs']));
  633. $data = $this->ethabi->encodeParameters($constructor, $params);
  634. $transaction = [];
  635. if (count($arguments) > 0) {
  636. $transaction = $arguments[0];
  637. }
  638. $transaction['data'] = '0x' . $this->bytecode . Utils::stripZero($data);
  639. } else {
  640. $method = array_splice($arguments, 0, 1)[0];
  641. if (!is_string($method)) {
  642. throw new InvalidArgumentException('Please make sure the method is string.');
  643. }
  644. $functions = [];
  645. foreach ($this->functions as $function) {
  646. if ($function["name"] === $method) {
  647. $functions[] = $function;
  648. }
  649. };
  650. if (count($functions) < 1) {
  651. throw new InvalidArgumentException('Please make sure the method exists.');
  652. }
  653. if (is_callable($callback) !== true) {
  654. throw new \InvalidArgumentException('The last param must be callback function.');
  655. }
  656. // check the last one in arguments is transaction object
  657. $argsLen = count($arguments);
  658. $transaction = [];
  659. $hasTransaction = false;
  660. if ($argsLen > 0) {
  661. $transaction = $arguments[$argsLen - 1];
  662. }
  663. if (
  664. isset($transaction["from"]) ||
  665. isset($transaction["to"]) ||
  666. isset($transaction["gas"]) ||
  667. isset($transaction["gasPrice"]) ||
  668. isset($transaction["value"]) ||
  669. isset($transaction["data"]) ||
  670. isset($transaction["nonce"])
  671. ) {
  672. $hasTransaction = true;
  673. } else {
  674. $transaction = [];
  675. }
  676. $params = [];
  677. $data = "";
  678. $functionName = "";
  679. foreach ($functions as $function) {
  680. if ($hasTransaction) {
  681. if ($argsLen - 1 !== count($function['inputs'])) {
  682. continue;
  683. } else {
  684. $paramsLen = $argsLen - 1;
  685. }
  686. } else {
  687. if ($argsLen !== count($function['inputs'])) {
  688. continue;
  689. } else {
  690. $paramsLen = $argsLen;
  691. }
  692. }
  693. try {
  694. $params = array_splice($arguments, 0, $paramsLen);
  695. $data = $this->ethabi->encodeParameters($function, $params);
  696. $functionName = Utils::jsonMethodToString($function);
  697. } catch (InvalidArgumentException $e) {
  698. continue;
  699. }
  700. break;
  701. }
  702. if (empty($data) || empty($functionName)) {
  703. throw new InvalidArgumentException('Please make sure you have put all function params and callback.');
  704. }
  705. $functionSignature = $this->ethabi->encodeFunctionSignature($functionName);
  706. $transaction['to'] = $this->toAddress;
  707. $transaction['data'] = $functionSignature . Utils::stripZero($data);
  708. }
  709. $this->eth->estimateGas($transaction, function ($err, $gas) use ($callback) {
  710. if ($err !== null) {
  711. return call_user_func($callback, $err, null);
  712. }
  713. return call_user_func($callback, null, $gas);
  714. });
  715. }
  716. }
  717. /**
  718. * getData
  719. * Get the function method call data.
  720. * With this function, you can send signed contract function transaction.
  721. * 1. Get the funtion data with params.
  722. * 2. Sign the data with user private key.
  723. * 3. Call sendRawTransaction.
  724. *
  725. * @param mixed
  726. * @return void
  727. */
  728. public function getData()
  729. {
  730. if (isset($this->functions) || isset($this->constructor)) {
  731. $arguments = func_get_args();
  732. $functionData = '';
  733. if (empty($this->toAddress) && !empty($this->bytecode)) {
  734. $constructor = $this->constructor;
  735. if (count($arguments) < count($constructor['inputs'])) {
  736. throw new InvalidArgumentException('Please make sure you have put all constructor params and callback.');
  737. }
  738. if (!isset($this->bytecode)) {
  739. throw new \InvalidArgumentException('Please call bytecode($bytecode) before getData().');
  740. }
  741. $params = array_splice($arguments, 0, count($constructor['inputs']));
  742. $data = $this->ethabi->encodeParameters($constructor, $params);
  743. $functionData = $this->bytecode . Utils::stripZero($data);
  744. } else {
  745. $method = array_splice($arguments, 0, 1)[0];
  746. if (!is_string($method)) {
  747. throw new InvalidArgumentException('Please make sure the method is string.');
  748. }
  749. $functions = [];
  750. foreach ($this->functions as $function) {
  751. if ($function["name"] === $method) {
  752. $functions[] = $function;
  753. }
  754. };
  755. if (count($functions) < 1) {
  756. throw new InvalidArgumentException('Please make sure the method exists.');
  757. }
  758. $params = $arguments;
  759. $data = "";
  760. $functionName = "";
  761. foreach ($functions as $function) {
  762. if (count($arguments) !== count($function['inputs'])) {
  763. continue;
  764. }
  765. try {
  766. $data = $this->ethabi->encodeParameters($function, $params);
  767. $functionName = Utils::jsonMethodToString($function);
  768. } catch (InvalidArgumentException $e) {
  769. continue;
  770. }
  771. break;
  772. }
  773. if (empty($data) || empty($functionName)) {
  774. throw new InvalidArgumentException('Please make sure you have put all function params and callback.');
  775. }
  776. $functionSignature = $this->ethabi->encodeFunctionSignature($functionName);
  777. $functionData = Utils::stripZero($functionSignature) . Utils::stripZero($data);
  778. }
  779. return $functionData;
  780. }
  781. }
  782. }