Adds ability to pass requested data layout to decoders and tuple support.

This commit is contained in:
slawomir 2022-10-16 09:25:40 +02:00
parent cede0cc410
commit c8e955a723
4 changed files with 72 additions and 16 deletions

View File

@ -26,6 +26,7 @@ use Web3\Contracts\Types\DynamicBytes;
use Web3\Contracts\Types\Integer;
use Web3\Contracts\Types\Str;
use Web3\Contracts\Types\Uinteger;
use Web3\Contracts\Types\Tuple;
use Web3\Validators\AddressValidator;
use Web3\Validators\HexValidator;
use Web3\Validators\StringValidator;
@ -154,15 +155,7 @@ class Contract
}
$this->abi = $abiArray;
$this->eth = new Eth($this->provider);
$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 = Ethabi::factory();
}
/**

View File

@ -13,6 +13,14 @@ namespace Web3\Contracts;
use InvalidArgumentException;
use stdClass;
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\Tuple;
use Web3\Contracts\Types\Uinteger;
use Web3\Utils;
use Web3\Formatters\IntegerFormatter;
@ -55,6 +63,20 @@ class Ethabi
return false;
}
public static function factory()
{
return new Ethabi([
'address' => new Address,
'bool' => new Boolean,
'bytes' => new Bytes,
'dynamicBytes' => new DynamicBytes,
'int' => new Integer,
'string' => new Str,
'uint' => new Uinteger,
'tuple' => new Tuple
]);
}
/**
* set
*
@ -235,11 +257,13 @@ class Ethabi
$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]);
}
$output_type_hint = $outputTypes['outputs'][$i] ?? false;
$name = $outputTypes['outputs'][$i]['name'] ?? "";
if (empty($name))
$name = $i;
$result[$name] = $solidityTypes[$i]->decode($param, $offsets[$i], $types[$i], $output_type_hint);
}
return $result;

View File

@ -229,7 +229,7 @@ class SolidityType
* @param string $name
* @return array
*/
public function decode($value, $offset, $name)
public function decode($value, $offset, $name, $output_type_hint = false)
{
if ($this->isDynamicArray($name)) {
$arrayOffset = (int) Utils::toBn('0x' . mb_substr($value, $offset * 2, 64))->toString();
@ -263,7 +263,7 @@ class SolidityType
$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);
return $this->outputFormat($param, $name, $output_type_hint);
}
$length = $this->staticPartLength($name);
$param = mb_substr($value, $offset * 2, $length * 2);

View File

@ -0,0 +1,39 @@
<?php
namespace Web3\Contracts\Types;
use Web3\Contracts\Ethabi;
use Web3\Contracts\SolidityType;
use Web3\Contracts\Types\IType;
class Tuple extends SolidityType implements IType
{
public function __construct()
{
}
public function isType($name)
{
return (preg_match('/^tuple(\[([0-9]*)\])*$/', $name) === 1);
}
public function isDynamicType()
{
return true;
}
public function inputFormat($value, $name)
{
return $value;
}
public function outputFormat($value, $name, $output_type_hint)
{
$ethabi = Ethabi::factory();
$types = $output_type_hint['components'] ?? false;
if (!is_array($types)) {
throw new InvalidArgumentException('Output type is required for tuple.');
}
return $ethabi->decodeParameters(['outputs'=>$types], $value);
}
}