diff --git a/src/Contracts/Ethabi.php b/src/Contracts/Ethabi.php index 694a563..01ed4e0 100644 --- a/src/Contracts/Ethabi.php +++ b/src/Contracts/Ethabi.php @@ -15,6 +15,16 @@ use stdClass; use Web3\Utils; use Web3\Formatters\IntegerFormatter; +use Web3\Contracts\Types\Address; +use Web3\Contracts\Types\Boolean; +use Web3\Contracts\Types\Bytes; +use Web3\Contracts\Types\DynamicBytes; +use Web3\Contracts\Types\Integer; +use Web3\Contracts\Types\Str; +use Web3\Contracts\Types\Uinteger; +use Web3\Contracts\Types\SizedArray; +use Web3\Contracts\Types\DynamicArray; +use Web3\Contracts\Types\Tuple; class Ethabi { @@ -36,7 +46,18 @@ public function __construct($types=[]) if (!is_array($types)) { $types = []; } - $this->types = $types; + $this->types = array_merge($types, [ + 'address' => new Address, + 'bool' => new Boolean, + 'bytes' => new Bytes, + 'dynamicBytes' => new DynamicBytes, + 'int' => new Integer, + 'string' => new Str, + 'uint' => new Uinteger, + 'sizedArray' => new SizedArray, + 'dynamicArray' => new DynamicArray, + 'tuple' => new Tuple, + ]); } /** @@ -79,9 +100,246 @@ public function __set($name, $value) * @param array $arguments * @return void */ - public static function __callStatic($name, $arguments) + // public static function __callStatic($name, $arguments) {} + + /** + * nestedTypes + * + * @param string $name + * @return mixed + */ + public function nestedTypes($name) + { + if (!is_string($name)) { + throw new InvalidArgumentException('nestedTypes name must string.'); + } + $matches = []; + + if (preg_match_all('/(\[[0-9]*\])/', $name, $matches, PREG_PATTERN_ORDER) >= 1) { + return $matches[0]; + } + return false; + } + + /** + * nestedName + * + * @param string $name + * @return string + */ + public function nestedName($name) + { + if (!is_string($name)) { + throw new InvalidArgumentException('nestedName name must string.'); + } + $nestedTypes = $this->nestedTypes($name); + + if ($nestedTypes === false) { + return $name; + } + return mb_substr($name, 0, mb_strlen($name) - mb_strlen($nestedTypes[count($nestedTypes) - 1])); + } + + /** + * isDynamicArray + * + * @param string $name + * @return bool + */ + public function isDynamicArray($name) + { + $nestedTypes = $this->nestedTypes($name); + + return $nestedTypes && preg_match('/[0-9]{1,}/', $nestedTypes[count($nestedTypes) - 1]) !== 1; + } + + /** + * isStaticArray + * + * @param string $name + * @return bool + */ + public function isStaticArray($name) + { + $nestedTypes = $this->nestedTypes($name); + + return $nestedTypes && preg_match('/[0-9]{1,}/', $nestedTypes[count($nestedTypes) - 1]) === 1; + } + + /** + * isTuple + * + * @param string $name + * @return bool + */ + public function isTuple($name) + { + if (preg_match_all('/(tuple)?\((.*)\)/', $name, $matches, PREG_PATTERN_ORDER) >= 1) { + return true; + } + return false; + } + + /** + * parseTupleType + * + * @param string $name + * @return bool + */ + public function parseTupleType($name) { - // + $matches = []; + + if (preg_match_all('/(tuple)?\((.*)\)/', $name, $matches, PREG_PATTERN_ORDER) >= 1) { + return $matches[2][0]; + } + return false; + } + + /** + * findAbiType + * + * @param string $type + * @return array + */ + protected function findAbiType($type) + { + $result = []; + if (!is_string($type)) { + throw new InvalidArgumentException('type should be string'); + } + $solidityType = $this->getSolidityType($type); + if ($this->isDynamicArray($type)) { + $nestedType = $this->nestedName($type); + + $result = [ + 'type' => $type, + 'dynamic' => true, + 'solidityType' => $solidityType, + 'coders' => $this->findAbiType($nestedType) + ]; + return $result; + } elseif ($this->isStaticArray($type)) { + $nestedType = $this->nestedName($type); + + $result = [ + 'type' => $type, + 'dynamic' => false, + 'solidityType' => $solidityType, + 'coders' => $this->findAbiType($nestedType) + ]; + if ($result['coders']['dynamic']) { + $result['dynamic'] = true; + } + return $result; + } elseif ($this->isTuple($type)) { + $nestedType = $this->parseTupleType($type); + $parsedNestedTypes = preg_split('/,/', $nestedType); + $tupleAbi = [ + 'type' => $type, + 'dynamic' => false, + 'solidityType' => $solidityType, + 'coders' => [] + ]; + + foreach ($parsedNestedTypes as $type_) { + $parsedType = $this->findAbiType($type_); + if ($parsedType['dynamic']) { + $tupleAbi['dynamic'] = true; + } + $tupleAbi['coders'][] = $parsedType; + } + $result = $tupleAbi; + return $result; + } + $result = [ + 'type' => $type, + 'solidityType' => $solidityType, + 'dynamic' => $solidityType->isDynamicType() + ]; + return $result; + } + + /** + * getSolidityType + * + * @param string $type + * @return SolidityType + */ + protected function getSolidityType($type) + { + $match = []; + if ($this->isDynamicArray($type)) { + return $this->types['dynamicArray']; + } elseif ($this->isStaticArray($type)) { + return $this->types['sizedArray']; + } elseif ($this->isTuple($type)) { + return $this->types['tuple']; + } + + if (preg_match('/^([a-zA-Z]+)/', $type, $match) === 1) { + $className = (array_key_exists($match[0], $this->types)) ? $this->types[$match[0]] : null; + if (isset($className)) { + if (call_user_func([$className, 'isType'], $type) === false) { + // check dynamic bytes + if ($match[0] === 'bytes') { + $className = $this->types['dynamicBytes']; + } + } + return $className; + } + } + throw new InvalidArgumentException('Unsupport solidity parameter type: ' . $type); + } + + /** + * parseAbiTypes + * + * @param array $types + * @return array + */ + protected function parseAbiTypes($types) + { + $result = []; + foreach ($types as $type) { + $result[] = $this->findAbiType($type); + } + return $result; + } + + /** + * getSolidityTypes + * + * @param array $types + * @return array + */ + 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) { + // check dynamic bytes + if ($match[0] === 'bytes') { + $className = $this->types['dynamicBytes']; + } else { + throw new InvalidArgumentException('Unsupport solidity parameter type: ' . $type); + } + } + $solidityTypes[$key] = $className; + } + } + } + return $solidityTypes; } /** @@ -155,25 +413,11 @@ public function encodeParameters($types, $params) throw new InvalidArgumentException('encodeParameters number of types must equal to number of params.'); } $typesLength = count($types); - $solidityTypes = $this->getSolidityTypes($types); $encodes = array_fill(0, $typesLength, ''); + $abiTypes = $this->parseAbiTypes($types); - 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); + // encode with tuple type + return '0x' . $this->types['tuple']->encode($params, $abiTypes); } /** @@ -244,142 +488,4 @@ public function decodeParameters($types, $param) return $result; } - - /** - * getSolidityTypes - * - * @param array $types - * @return array - */ - 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) { - // check dynamic bytes - if ($match[0] === 'bytes') { - $className = $this->types['dynamicBytes']; - } else { - throw new InvalidArgumentException('Unsupport solidity parameter type: ' . $type); - } - } - $solidityTypes[$key] = $className; - } - } - } - return $solidityTypes; - } - - /** - * encodeWithOffset - * - * @param string $type - * @param \Web3\Contracts\SolidityType $solidityType - * @param mixed $encode - * @param int $offset - * @return string - */ - 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; $idivide(Utils::toBn(2)); - - // if (is_array($divided)) { - // $additionalOffset = (int) $divided[0]->toString(); - // } else { - // $additionalOffset = 0; - // } - $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; $idivide(Utils::toBn(2)); - - // if (is_array($divided)) { - // $additionalOffset = (int) $divided[0]->toString(); - // } else { - // $additionalOffset = 0; - // } - $additionalOffset = floor(mb_strlen($result) / 2); - $result .= $this->encodeWithOffset($nestedName, $solidityType, $encoded[$i], $offset + $additionalOffset); - } - return $result; - } - return $encoded; - } - - /** - * encodeMultiWithOffset - * - * @param array $types - * @param array $solidityTypes - * @param array $encodes - * @param int $dynamicOffset - * @return string - */ - 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); - // $dynamicOffset += floor(mb_strlen($e) / 2); - $result .= $e; - } - } - return $result; - } } \ No newline at end of file diff --git a/src/Contracts/SolidityType.php b/src/Contracts/SolidityType.php index 5adf572..53c005c 100644 --- a/src/Contracts/SolidityType.php +++ b/src/Contracts/SolidityType.php @@ -193,31 +193,31 @@ public function isDynamicType() * encode * * @param mixed $value - * @param string $name + * @param mixed $name * @return string */ public function encode($value, $name) { - if ($this->isDynamicArray($name)) { - $length = count($value); - $nestedName = $this->nestedName($name); - $result = []; - $result[] = IntegerFormatter::format($length); - - foreach ($value as $val) { - $result[] = $this->encode($val, $nestedName); - } - return $result; - } elseif ($this->isStaticArray($name)) { - $length = $this->staticArrayLength($name); - $nestedName = $this->nestedName($name); - $result = []; - - foreach ($value as $val) { - $result[] = $this->encode($val, $nestedName); - } - return $result; - } + // if ($this->isDynamicArray($name)) { + // $length = count($value); + // $nestedName = $this->nestedName($name); + // $result = []; + // $result[] = IntegerFormatter::format($length); + + // foreach ($value as $val) { + // $result[] = $this->encode($val, $nestedName); + // } + // return $result; + // } elseif ($this->isStaticArray($name)) { + // $length = $this->staticArrayLength($name); + // $nestedName = $this->nestedName($name); + // $result = []; + + // foreach ($value as $val) { + // $result[] = $this->encode($val, $nestedName); + // } + // return $result; + // } return $this->inputFormat($value, $name); } diff --git a/src/Contracts/TypedDataEncoder.php b/src/Contracts/TypedDataEncoder.php index 21afea0..45e29f8 100644 --- a/src/Contracts/TypedDataEncoder.php +++ b/src/Contracts/TypedDataEncoder.php @@ -15,13 +15,6 @@ use Web3\Utils; use Web3\Formatters\IntegerFormatter; use Web3\Contracts\Ethabi; -use Web3\Contracts\Types\Address; -use Web3\Contracts\Types\Boolean; -use Web3\Contracts\Types\Bytes; -use Web3\Contracts\Types\DynamicBytes; -use Web3\Contracts\Types\Integer; -use Web3\Contracts\Types\Str; -use Web3\Contracts\Types\Uinteger; class TypedDataEncoder { @@ -51,15 +44,7 @@ class TypedDataEncoder */ public function __construct() { - $this->ethabi = new Ethabi([ - 'address' => new Address, - 'bool' => new Boolean, - 'bytes' => new Bytes, - 'dynamicBytes' => new DynamicBytes, - 'int' => new Integer, - 'string' => new Str, - 'uint' => new Uinteger, - ]); + $this->ethabi = new Ethabi(); } /** @@ -95,6 +80,16 @@ public function __set($name, $value) return false; } + /** + * getEthabi + * + * @return \Web3\Contracts\Ethabi + */ + public function getEthabi() + { + return $this->ethabi; + } + /** * encodeField * diff --git a/src/Contracts/Types/Address.php b/src/Contracts/Types/Address.php index 58de9c7..3f0d9ac 100644 --- a/src/Contracts/Types/Address.php +++ b/src/Contracts/Types/Address.php @@ -37,7 +37,7 @@ public function __construct() */ public function isType($name) { - return (preg_match('/^address(\[([0-9]*)\])*$/', $name) === 1); + return (preg_match('/^address/', $name) === 1); } /** diff --git a/src/Contracts/Types/BaseArray.php b/src/Contracts/Types/BaseArray.php new file mode 100644 index 0000000..92f8649 --- /dev/null +++ b/src/Contracts/Types/BaseArray.php @@ -0,0 +1,124 @@ + + * + * @author Peter Lai + * @license MIT + */ + +namespace Web3\Contracts\Types; + +use InvalidArgumentException; +use Web3\Utils; +use Web3\Contracts\SolidityType; +use Web3\Contracts\Types\IType; +use Web3\Formatters\IntegerFormatter; + +class BaseArray extends SolidityType implements IType +{ + /** + * construct + * + * @return void + */ + public function __construct() + { + // + } + + /** + * isType + * + * @param string $name + * @return bool + */ + public function isType($name) + { + return (preg_match('/(\[([0-9]*)\])/', $name) === 1); + } + + /** + * isDynamicType + * + * @return bool + */ + public function isDynamicType() + { + return true; + } + + /** + * encodeElements + * + * @param mixed $value + * @param string $name + * @return array + */ + public function encodeElements($value, $name) + { + if (!is_array($value)) { + throw new InvalidArgumentException('Encode value must be array'); + } + $results = []; + $itemsAreDynamic = false; + foreach ($value as $key => $val) { + $results[] = $name['coders']['solidityType']->encode($val, $name['coders']); + if ($name['coders']['dynamic']) { + $itemsAreDynamic = true; + } + } + if (!$itemsAreDynamic) { + return $results; + } + $headLength = 32 * count($value); + $tailOffsets = [0]; + foreach ($results as $key => $val) { + if ($key === count($results) - 1) { + break; + } + $tailOffsets[] = (int) mb_strlen($val) / 2; + } + $headChunks = []; + foreach ($tailOffsets as $offset) { + $headChunks[] = IntegerFormatter::format($headLength + $offset); + } + return array_merge($headChunks, $results); + } + + /** + * inputFormat + * + * @param mixed $value + * @param string $name + * @return string + */ + public function inputFormat($value, $name) + { + return implode('', $this->encodeElements($value, $name)); + } + + /** + * outputFormat + * + * @param mixed $value + * @param string $name + * @return string + */ + public function outputFormat($value, $name) + { + $checkZero = str_replace('0', '', $value); + + if (empty($checkZero)) { + return '0'; + } + if (preg_match('/^bytes([0-9]*)/', $name, $match) === 1) { + $size = intval($match[1]); + $length = 2 * $size; + $value = mb_substr($value, 0, $length); + } + return '0x' . $value; + } +} \ No newline at end of file diff --git a/src/Contracts/Types/Boolean.php b/src/Contracts/Types/Boolean.php index f997ac9..b63671a 100644 --- a/src/Contracts/Types/Boolean.php +++ b/src/Contracts/Types/Boolean.php @@ -35,7 +35,7 @@ public function __construct() */ public function isType($name) { - return (preg_match('/^bool(\[([0-9]*)\])*$/', $name) === 1); + return (preg_match('/^bool/', $name) === 1); } /** diff --git a/src/Contracts/Types/Bytes.php b/src/Contracts/Types/Bytes.php index df5985a..84af2d2 100644 --- a/src/Contracts/Types/Bytes.php +++ b/src/Contracts/Types/Bytes.php @@ -36,7 +36,7 @@ public function __construct() */ public function isType($name) { - return (preg_match('/^bytes([0-9]{1,})(\[([0-9]*)\])*$/', $name) === 1); + return (preg_match('/^bytes([0-9]{1,})/', $name) === 1); } /** diff --git a/src/Contracts/Types/DynamicArray.php b/src/Contracts/Types/DynamicArray.php new file mode 100644 index 0000000..9b89f15 --- /dev/null +++ b/src/Contracts/Types/DynamicArray.php @@ -0,0 +1,87 @@ + + * + * @author Peter Lai + * @license MIT + */ + +namespace Web3\Contracts\Types; + +use InvalidArgumentException; +use Web3\Utils; +use Web3\Contracts\Types\BaseArray; +use Web3\Formatters\IntegerFormatter; + +class DynamicArray extends BaseArray +{ + /** + * construct + * + * @return void + */ + public function __construct() + { + // + } + + /** + * isType + * + * @param string $name + * @return bool + */ + public function isType($name) + { + return (preg_match('/(\[\])/', $name) === 1); + } + + /** + * isDynamicType + * + * @return bool + */ + public function isDynamicType() + { + return true; + } + + /** + * inputFormat + * + * @param mixed $value + * @param string $name + * @return string + */ + public function inputFormat($value, $name) + { + $results = $this->encodeElements($value, $name); + $encodeSize = IntegerFormatter::format(count($value)); + return $encodeSize . implode('', $results); + } + + /** + * outputFormat + * + * @param mixed $value + * @param string $name + * @return string + */ + public function outputFormat($value, $name) + { + $checkZero = str_replace('0', '', $value); + + if (empty($checkZero)) { + return '0'; + } + if (preg_match('/^bytes([0-9]*)/', $name, $match) === 1) { + $size = intval($match[1]); + $length = 2 * $size; + $value = mb_substr($value, 0, $length); + } + return '0x' . $value; + } +} \ No newline at end of file diff --git a/src/Contracts/Types/Integer.php b/src/Contracts/Types/Integer.php index 4d6dae0..da12a51 100644 --- a/src/Contracts/Types/Integer.php +++ b/src/Contracts/Types/Integer.php @@ -37,7 +37,7 @@ public function __construct() */ public function isType($name) { - return (preg_match('/^int([0-9]{1,})?(\[([0-9]*)\])*$/', $name) === 1); + return (preg_match('/^int([0-9]{1,})?/', $name) === 1); } /** diff --git a/src/Contracts/Types/SizedArray.php b/src/Contracts/Types/SizedArray.php new file mode 100644 index 0000000..9bed51a --- /dev/null +++ b/src/Contracts/Types/SizedArray.php @@ -0,0 +1,92 @@ + + * + * @author Peter Lai + * @license MIT + */ + +namespace Web3\Contracts\Types; + +use InvalidArgumentException; +use Web3\Utils; +use Web3\Contracts\Types\BaseArray; +use Web3\Formatters\IntegerFormatter; + +class SizedArray extends BaseArray +{ + /** + * construct + * + * @return void + */ + public function __construct() + { + // + } + + /** + * isType + * + * @param string $name + * @return bool + */ + public function isType($name) + { + return (preg_match('/(\[([0-9]*)\])/', $name) === 1); + } + + /** + * isDynamicType + * + * @return bool + */ + public function isDynamicType() + { + return false; + } + + /** + * inputFormat + * + * @param mixed $value + * @param string $name + * @return string + */ + public function inputFormat($value, $name) + { + if (!is_array($value)) { + throw new InvalidArgumentException('Encode value must be array'); + } + $length = is_array($name) ? $this->staticArrayLength($name['type']) : 0; + if ($length === 0 || count($value) > $length) { + throw new InvalidArgumentException('Invalid value to encode sized array, expected: ' . $length . ', but got ' . count($value)); + } + return parent::inputFormat($value, $name); + } + + /** + * outputFormat + * + * @param mixed $value + * @param string $name + * @return string + */ + public function outputFormat($value, $name) + { + $checkZero = str_replace('0', '', $value); + + if (empty($checkZero)) { + return '0'; + } + if (preg_match('/^bytes([0-9]*)/', $name, $match) === 1) { + $size = intval($match[1]); + $length = 2 * $size; + $value = mb_substr($value, 0, $length); + } + return '0x' . $value; + } +} \ No newline at end of file diff --git a/src/Contracts/Types/Str.php b/src/Contracts/Types/Str.php index 51cf974..c8d8fc4 100644 --- a/src/Contracts/Types/Str.php +++ b/src/Contracts/Types/Str.php @@ -37,7 +37,7 @@ public function __construct() */ public function isType($name) { - return (preg_match('/^string(\[([0-9]*)\])*$/', $name) === 1); + return (preg_match('/^string/', $name) === 1); } /** diff --git a/src/Contracts/Types/Tuple.php b/src/Contracts/Types/Tuple.php new file mode 100644 index 0000000..6b58c3c --- /dev/null +++ b/src/Contracts/Types/Tuple.php @@ -0,0 +1,123 @@ + + * + * @author Peter Lai + * @license MIT + */ + +namespace Web3\Contracts\Types; + +use InvalidArgumentException; +use Web3\Utils; +use Web3\Contracts\SolidityType; +use Web3\Contracts\Types\IType; +use Web3\Formatters\IntegerFormatter; + +class Tuple extends SolidityType implements IType +{ + /** + * construct + * + * @return void + */ + public function __construct() + { + // + } + + /** + * isType + * + * @param string $name + * @return bool + */ + public function isType($name) + { + return (preg_match('/(tuple)?\((.*)\)/', $name) === 1); + } + + /** + * isDynamicType + * + * @return bool + */ + public function isDynamicType() + { + return false; + } + + /** + * inputFormat + * + * @param mixed $value + * @param string $name + * @return string + */ + public function inputFormat($params, $abiTypes) + { + $result = []; + $rawHead = []; + $tail = []; + foreach ($abiTypes as $key => $abiType) { + if ($abiType['dynamic']) { + $rawHead[] = null; + $tail[] = $abiType['solidityType']->encode($params[$key], $abiType); + } else { + $rawHead[] = $abiType['solidityType']->encode($params[$key], $abiType); + $tail[] = ''; + } + } + $headLength = 0; + foreach ($rawHead as $head) { + if (is_null($head)) { + $headLength += 32; + continue; + } + $headLength += (int) mb_strlen($head) / 2; + } + $tailOffsets = [0]; + foreach ($tail as $key => $val) { + if ($key === count($tail) - 1) { + break; + } + $tailOffsets[] = (int) (mb_strlen($val) / 2); + } + $headChunks = []; + foreach ($rawHead as $key => $head) { + if (!array_key_exists($key, $tail)) continue; + $offset = $tailOffsets[$key]; + if (is_null($head)) { + $headChunks[] = IntegerFormatter::format($headLength + $offset); + continue; + } + $headChunks[] = $head; + } + return implode('', array_merge($headChunks, $tail)); + } + + /** + * outputFormat + * + * @param mixed $value + * @param string $name + * @return string + */ + public function outputFormat($value, $name) + { + $checkZero = str_replace('0', '', $value); + + if (empty($checkZero)) { + return '0'; + } + if (preg_match('/^bytes([0-9]*)/', $name, $match) === 1) { + $size = intval($match[1]); + $length = 2 * $size; + $value = mb_substr($value, 0, $length); + } + return '0x' . $value; + } +} \ No newline at end of file diff --git a/src/Contracts/Types/Uinteger.php b/src/Contracts/Types/Uinteger.php index c2099ed..566413d 100644 --- a/src/Contracts/Types/Uinteger.php +++ b/src/Contracts/Types/Uinteger.php @@ -37,7 +37,7 @@ public function __construct() */ public function isType($name) { - return (preg_match('/^uint([0-9]{1,})?(\[([0-9]*)\])*$/', $name) === 1); + return (preg_match('/^uint([0-9]{1,})?/', $name) === 1); } /**