123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399 |
- <?php
- namespace qiniu\services\blockchain\bsc\src\Contracts;
- use InvalidArgumentException;
- use stdClass;
- use qiniu\services\blockchain\bsc\src\Utils;
- use qiniu\services\blockchain\bsc\src\Formatters\IntegerFormatter;
- class Ethabi
- {
-
- protected $types = [];
-
- public function __construct($types=[])
- {
- if (!is_array($types)) {
- $types = [];
- }
- $this->types = $types;
- }
-
- public function __get($name)
- {
- $method = 'get' . ucfirst($name);
- if (method_exists($this, $method)) {
- return call_user_func_array([$this, $method], []);
- }
- return false;
- }
-
- public function __set($name, $value)
- {
- $method = 'set' . ucfirst($name);
- if (method_exists($this, $method)) {
- return call_user_func_array([$this, $method], [$value]);
- }
- return false;
- }
-
- public static function __callStatic($name, $arguments)
- {
-
- }
-
- public function encodeFunctionSignature($functionName)
- {
- if (!is_string($functionName)) {
- $functionName = Utils::jsonMethodToString($functionName);
- }
- return mb_substr(Utils::sha3($functionName), 0, 10);
- }
-
- public function encodeEventSignature($functionName)
- {
- if (!is_string($functionName)) {
- $functionName = Utils::jsonMethodToString($functionName);
- }
- return Utils::sha3($functionName);
- }
-
- public function encodeParameter($type, $param)
- {
- if (!is_string($type)) {
- throw new InvalidArgumentException('The type to encodeParameter must be string.');
- }
- return $this->encodeParameters([$type], [$param]);
- }
-
- public function encodeParameters($types, $params)
- {
-
- if ($types instanceof stdClass && isset($types->inputs)) {
- $types = Utils::jsonToArray($types, 2);
- }
- if (is_array($types) && isset($types['inputs'])) {
- $inputTypes = $types;
- $types = [];
- foreach ($inputTypes['inputs'] as $input) {
- if (isset($input['type'])) {
- $types[] = $input['type'];
- }
- }
- }
- if (count($types) !== count($params)) {
- throw new InvalidArgumentException('encodeParameters number of types must equal to number of params.');
- }
- $typesLength = count($types);
- $solidityTypes = $this->getSolidityTypes($types);
- foreach ($types as $key => $type) {
- $match = [];
- if (preg_match('/^([a-zA-Z]+)/', $type, $match) === 1) {
- if (isset($this->types[$match[0]])) {
- $className = $this->types[$match[0]];
- if (call_user_func([$this->types[$match[0]], 'isType'], $type) === false) {
- throw new InvalidArgumentException('Unsupport solidity parameter type: ' . $type);
- }
- $solidityTypes[$key] = $className;
- }
- }
- }
- $encodes = array_fill(0, $typesLength, '');
- foreach ($solidityTypes as $key => $type) {
- $encodes[$key] = call_user_func([$type, 'encode'], $params[$key], $types[$key]);
- }
- $dynamicOffset = 0;
- foreach ($solidityTypes as $key => $type) {
- $staticPartLength = $type->staticPartLength($types[$key]);
- $roundedStaticPartLength = floor(($staticPartLength + 31) / 32) * 32;
- if ($type->isDynamicType($types[$key]) || $type->isDynamicArray($types[$key])) {
- $dynamicOffset += 32;
- } else {
- $dynamicOffset += $roundedStaticPartLength;
- }
- }
- return '0x' . $this->encodeMultiWithOffset($types, $solidityTypes, $encodes, $dynamicOffset);
- }
-
- public function decodeParameter($type, $param)
- {
- if (!is_string($type)) {
- throw new InvalidArgumentException('The type to decodeParameter must be string.');
- }
- return $this->decodeParameters([$type], $param)[0];
- }
-
- public function decodeParameters($types, $param)
- {
- if (!is_string($param)) {
- throw new InvalidArgumentException('The type or param to decodeParameters must be string.');
- }
-
- if ($types instanceof stdClass && isset($types->outputs)) {
- $types = Utils::jsonToArray($types, 2);
- }
- if (is_array($types) && isset($types['outputs'])) {
- $outputTypes = $types;
- $types = [];
- foreach ($outputTypes['outputs'] as $output) {
- if (isset($output['type'])) {
- $types[] = $output['type'];
- }
- }
- }
- $typesLength = count($types);
- $solidityTypes = $this->getSolidityTypes($types);
- $offsets = array_fill(0, $typesLength, 0);
- for ($i=0; $i<$typesLength; $i++) {
- $offsets[$i] = $solidityTypes[$i]->staticPartLength($types[$i]);
- }
- for ($i=1; $i<$typesLength; $i++) {
- $offsets[$i] += $offsets[$i - 1];
- }
- for ($i=0; $i<$typesLength; $i++) {
- $offsets[$i] -= $solidityTypes[$i]->staticPartLength($types[$i]);
- }
- $result = [];
- $param = mb_strtolower(Utils::stripZero($param));
- for ($i=0; $i<$typesLength; $i++) {
- if (isset($outputTypes['outputs'][$i]['name']) && empty($outputTypes['outputs'][$i]['name']) === false) {
- $result[$outputTypes['outputs'][$i]['name']] = $solidityTypes[$i]->decode($param, $offsets[$i], $types[$i]);
- } else {
- $result[$i] = $solidityTypes[$i]->decode($param, $offsets[$i], $types[$i]);
- }
- }
- return $result;
- }
-
- protected function getSolidityTypes($types)
- {
- if (!is_array($types)) {
- throw new InvalidArgumentException('Types must be array');
- }
- $solidityTypes = array_fill(0, count($types), 0);
- foreach ($types as $key => $type) {
- $match = [];
- if (preg_match('/^([a-zA-Z]+)/', $type, $match) === 1) {
- if (isset($this->types[$match[0]])) {
- $className = $this->types[$match[0]];
- if (call_user_func([$this->types[$match[0]], 'isType'], $type) === false) {
-
- if ($match[0] === 'bytes') {
- $className = $this->types['dynamicBytes'];
- } else {
- throw new InvalidArgumentException('Unsupport solidity parameter type: ' . $type);
- }
- }
- $solidityTypes[$key] = $className;
- }
- }
- }
- return $solidityTypes;
- }
-
- protected function encodeWithOffset($type, $solidityType, $encoded, $offset)
- {
- if ($solidityType->isDynamicArray($type)) {
- $nestedName = $solidityType->nestedName($type);
- $nestedStaticPartLength = $solidityType->staticPartLength($type);
- $result = $encoded[0];
- if ($solidityType->isDynamicArray($nestedName)) {
- $previousLength = 2;
- for ($i=0; $i<count($encoded); $i++) {
- if (isset($encoded[$i - 1])) {
- $previousLength += abs($encoded[$i - 1][0]);
- }
- $result .= IntegerFormatter::format($offset + $i * $nestedStaticPartLength + $previousLength * 32);
- }
- }
- for ($i=0; $i<count($encoded); $i++) {
-
-
-
-
-
-
-
- $additionalOffset = floor(mb_strlen($result) / 2);
- $result .= $this->encodeWithOffset($nestedName, $solidityType, $encoded[$i], $offset + $additionalOffset);
- }
- return mb_substr($result, 64);
- } elseif ($solidityType->isStaticArray($type)) {
- $nestedName = $solidityType->nestedName($type);
- $nestedStaticPartLength = $solidityType->staticPartLength($type);
- $result = '';
- if ($solidityType->isDynamicArray($nestedName)) {
- $previousLength = 0;
- for ($i=0; $i<count($encoded); $i++) {
- if (isset($encoded[$i - 1])) {
- $previousLength += abs($encoded[$i - 1])[0];
- }
- $result .= IntegerFormatter::format($offset + $i * $nestedStaticPartLength + $previousLength * 32);
- }
- }
- for ($i=0; $i<count($encoded); $i++) {
-
-
-
-
-
-
-
- $additionalOffset = floor(mb_strlen($result) / 2);
- $result .= $this->encodeWithOffset($nestedName, $solidityType, $encoded[$i], $offset + $additionalOffset);
- }
- return $result;
- }
- return $encoded;
- }
-
- protected function encodeMultiWithOffset($types, $solidityTypes, $encodes, $dynamicOffset)
- {
- $result = '';
- foreach ($solidityTypes as $key => $type) {
- if ($type->isDynamicType($types[$key]) || $type->isDynamicArray($types[$key])) {
- $result .= IntegerFormatter::format($dynamicOffset);
- $e = $this->encodeWithOffset($types[$key], $type, $encodes[$key], $dynamicOffset);
- $dynamicOffset += floor(mb_strlen($e) / 2);
- } else {
- $result .= $this->encodeWithOffset($types[$key], $type, $encodes[$key], $dynamicOffset);
- }
- }
- foreach ($solidityTypes as $key => $type) {
- if ($type->isDynamicType($types[$key]) || $type->isDynamicArray($types[$key])) {
- $e = $this->encodeWithOffset($types[$key], $type, $encodes[$key], $dynamicOffset);
-
- $result .= $e;
- }
- }
- return $result;
- }
- }
|