Skip to content

Commit

Permalink
Update Array / Tuple decoder
Browse files Browse the repository at this point in the history
  • Loading branch information
sc0Vu committed Jan 25, 2024
1 parent 941251f commit a6725ec
Show file tree
Hide file tree
Showing 13 changed files with 108 additions and 190 deletions.
63 changes: 9 additions & 54 deletions src/Contracts/Ethabi.php
Original file line number Diff line number Diff line change
Expand Up @@ -307,41 +307,6 @@ protected function parseAbiTypes($types)
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;
}

/**
* encodeFunctionSignature
*
Expand Down Expand Up @@ -449,6 +414,7 @@ public function decodeParameters($types, $param)
}

// change json to array
$outputTypes = [];
if ($types instanceof stdClass && isset($types->outputs)) {
$types = Utils::jsonToArray($types, 2);
}
Expand All @@ -463,29 +429,18 @@ public function decodeParameters($types, $param)
}
}
$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));
$abiTypes = $this->parseAbiTypes($types);

for ($i=0; $i<$typesLength; $i++) {
// decode with tuple type
$results = [];
$decodeResults = $this->types['tuple']->decode(Utils::stripZero($param), 0, $abiTypes);
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]);
$results[$outputTypes['outputs'][$i]['name']] = $decodeResults[$i];
} else {
$result[$i] = $solidityTypes[$i]->decode($param, $offsets[$i], $types[$i]);
$results[$i] = $decodeResults[$i];
}
}

return $result;
return $results;
}
}
69 changes: 8 additions & 61 deletions src/Contracts/SolidityType.php
Original file line number Diff line number Diff line change
Expand Up @@ -198,76 +198,23 @@ public function isDynamicType()
*/
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;
// }
return $this->inputFormat($value, $name);
}

/**
* decode
*
* @param mixed $value
* @param string $offset
* @param string $name
* @param string $value
* @param integer $offset
* @param array $abiTypes
* @return array
*/
public function decode($value, $offset, $name)
public function decode($value, $offset, $abiTypes)
{
if ($this->isDynamicArray($name)) {
$arrayOffset = (int) Utils::toBn('0x' . mb_substr($value, $offset * 2, 64))->toString();
$length = (int) Utils::toBn('0x' . mb_substr($value, $arrayOffset * 2, 64))->toString();
$arrayStart = $arrayOffset + 32;

$nestedName = $this->nestedName($name);
$nestedStaticPartLength = $this->staticPartLength($nestedName);
$roundedNestedStaticPartLength = floor(($nestedStaticPartLength + 31) / 32) * 32;
$result = [];

for ($i=0; $i<$length * $roundedNestedStaticPartLength; $i+=$roundedNestedStaticPartLength) {
$result[] = $this->decode($value, $arrayStart + $i, $nestedName);
}
return $result;
} elseif ($this->isStaticArray($name)) {
$length = $this->staticArrayLength($name);
$arrayStart = $offset;

$nestedName = $this->nestedName($name);
$nestedStaticPartLength = $this->staticPartLength($nestedName);
$roundedNestedStaticPartLength = floor(($nestedStaticPartLength + 31) / 32) * 32;
$result = [];

for ($i=0; $i<$length * $roundedNestedStaticPartLength; $i+=$roundedNestedStaticPartLength) {
$result[] = $this->decode($value, $arrayStart + $i, $nestedName);
}
return $result;
} elseif ($this->isDynamicType()) {
$dynamicOffset = (int) Utils::toBn('0x' . mb_substr($value, $offset * 2, 64))->toString();
$length = (int) Utils::toBn('0x' . mb_substr($value, $dynamicOffset * 2, 64))->toString();
$roundedLength = floor(($length + 31) / 32);
$param = mb_substr($value, $dynamicOffset * 2, ( 1 + $roundedLength) * 64);
return $this->outputFormat($param, $name);
if (!is_string($value)) {
throw new InvalidArgumentException('Decode value should be string');
}
$length = $this->staticPartLength($name);
$param = mb_substr($value, $offset * 2, $length * 2);

return $this->outputFormat($param, $name);
$value = mb_substr($value, $offset);
return $this->outputFormat($value, $abiTypes);
}
}
4 changes: 2 additions & 2 deletions src/Contracts/Types/Address.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,10 @@ public function inputFormat($value, $name)
* outputFormat
*
* @param mixed $value
* @param string $name
* @param array $abiType
* @return string
*/
public function outputFormat($value, $name)
public function outputFormat($value, $abiType)
{
return '0x' . mb_substr($value, 24, 40);
}
Expand Down
4 changes: 2 additions & 2 deletions src/Contracts/Types/Boolean.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,10 @@ public function inputFormat($value, $name)
* outputFormat
*
* @param mixed $value
* @param string $name
* @param array $abiType
* @return string
*/
public function outputFormat($value, $name)
public function outputFormat($value, $abiType)
{
$value = (int) mb_substr($value, 63, 1);

Expand Down
6 changes: 3 additions & 3 deletions src/Contracts/Types/Bytes.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,17 +80,17 @@ public function inputFormat($value, $name)
* outputFormat
*
* @param mixed $value
* @param string $name
* @param array $abiType
* @return string
*/
public function outputFormat($value, $name)
public function outputFormat($value, $abiType)
{
$checkZero = str_replace('0', '', $value);

if (empty($checkZero)) {
return '0';
}
if (preg_match('/^bytes([0-9]*)/', $name, $match) === 1) {
if (preg_match('/^bytes([0-9]*)/', $abiType['type'], $match) === 1) {
$size = intval($match[1]);
$length = 2 * $size;
$value = mb_substr($value, 0, $length);
Expand Down
28 changes: 15 additions & 13 deletions src/Contracts/Types/DynamicArray.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,22 +66,24 @@ public function inputFormat($value, $name)
/**
* outputFormat
*
* @param mixed $value
* @param string $name
* @return string
* @param string $value
* @param array $abiType
* @return array
*/
public function outputFormat($value, $name)
public function outputFormat($value, $abiType)
{
$checkZero = str_replace('0', '', $value);

if (empty($checkZero)) {
return '0';
if (!is_array($abiType)) {
throw new InvalidArgumentException('Invalid abiType to decode sized array, expected: array');
}
if (preg_match('/^bytes([0-9]*)/', $name, $match) === 1) {
$size = intval($match[1]);
$length = 2 * $size;
$value = mb_substr($value, 0, $length);
$lengthHex = mb_substr($value, 0, 64);
$length = (int) Utils::hexToNumber($lengthHex);
$offset = 64;
$results = [];
$decoder = $abiType['coders'];
for ($i = 0; $i < $length; $i++) {
$results[] = $decoder['solidityType']->decode($value, $offset, $decoder);
$offset += 64;
}
return '0x' . $value;
return $results;
}
}
4 changes: 2 additions & 2 deletions src/Contracts/Types/DynamicBytes.php
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,10 @@ public function inputFormat($value, $name)
* outputFormat
*
* @param mixed $value
* @param string $name
* @param array $abiType
* @return string
*/
public function outputFormat($value, $name)
public function outputFormat($value, $abiType)
{
$checkZero = str_replace('0', '', $value);

Expand Down
14 changes: 4 additions & 10 deletions src/Contracts/Types/Integer.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,11 @@ public function inputFormat($value, $name)
* outputFormat
*
* @param mixed $value
* @param string $name
* @return string
* @param array $abiType
* @return BigNumber
*/
public function outputFormat($value, $name)
public function outputFormat($value, $abiType)
{
$match = [];

if (preg_match('/^[0]+([a-f0-9]+)$/', $value, $match) === 1) {
// due to value without 0x prefix, we will parse as decimal
$value = '0x' . $match[1];
}
return BigNumberFormatter::format($value);
return BigNumberFormatter::format('0x' . mb_substr($value, 0, 64));
}
}
43 changes: 26 additions & 17 deletions src/Contracts/Types/SizedArray.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,40 +53,49 @@ public function isDynamicType()
* inputFormat
*
* @param mixed $value
* @param string $name
* @param array $abiType
* @return string
*/
public function inputFormat($value, $name)
public function inputFormat($value, $abiType)
{
if (!is_array($value)) {
throw new InvalidArgumentException('Encode value must be array');
}
$length = is_array($name) ? $this->staticArrayLength($name['type']) : 0;
$length = is_array($abiType) ? $this->staticArrayLength($abiType['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);
return parent::inputFormat($value, $abiType);
}

/**
* outputFormat
*
* @param mixed $value
* @param string $name
* @return string
* @param string $value
* @param array $abiType
* @return array
*/
public function outputFormat($value, $name)
public function outputFormat($value, $abiType)
{
$checkZero = str_replace('0', '', $value);

if (empty($checkZero)) {
return '0';
if (!is_array($abiType)) {
throw new InvalidArgumentException('Invalid abiType to decode sized array, expected: array');
}
$length = is_array($abiType) ? $this->staticArrayLength($abiType['type']) : 0;
$offset = 0;
if ($abiType['dynamic']) {
$valueLengthHex = mb_substr($value, 0, 64);
$valueLength = (int) Utils::hexToNumber($valueLengthHex) / 32;
if ($length !== $valueLength) {
throw new InvalidArgumentException('Invalid sized array length decode, expected: ' . $lenght . ', but got ' . $valueLength);
}
$offset += 64;
}
if (preg_match('/^bytes([0-9]*)/', $name, $match) === 1) {
$size = intval($match[1]);
$length = 2 * $size;
$value = mb_substr($value, 0, $length);
var_dump('Length: ' . $length . ' Decode length: ' . $valueLength, $abiType['coders']);
$results = [];
$decoder = $abiType['coders'];
for ($i = 0; $i < $length; $i++) {
$results[] = $decoder['solidityType']->decode($value, $offset, $decoder);
}
return '0x' . $value;
return $results;
}
}
4 changes: 2 additions & 2 deletions src/Contracts/Types/Str.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,10 @@ public function inputFormat($value, $name)
* outputFormat
*
* @param mixed $value
* @param string $name
* @param array $abiType
* @return string
*/
public function outputFormat($value, $name)
public function outputFormat($value, $abiType)
{
$strLen = mb_substr($value, 0, 64);
$strValue = mb_substr($value, 64);
Expand Down
Loading

0 comments on commit a6725ec

Please sign in to comment.