-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Added SerialzedType "XchainBridge"
- Loading branch information
1 parent
b568a3b
commit e692ba8
Showing
2 changed files
with
172 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
<?php declare(strict_types=1); | ||
/** | ||
* XRPL-PHP | ||
* | ||
* Copyright (c) Alexander Busse | Hardcastle Technologies | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace XRPL_PHP\Core\RippleBinaryCodec\Types; | ||
|
||
use Exception; | ||
use XRPL_PHP\Core\Buffer; | ||
use XRPL_PHP\Core\RippleBinaryCodec\Serdes\BinaryParser; | ||
|
||
class XchainBridge extends SerializedType | ||
{ | ||
public const TYPE_ORDER = [ | ||
[ 'name' => 'LockingChainDoor', 'type' => AccountId::class ], | ||
[ 'name' => 'LockingChainIssue', 'type' => Issue::class ], | ||
[ 'name' => 'IssuingChainDoor', 'type' => AccountId::class ], | ||
[ 'name' => 'IssuingChainIssue', 'type' => Issue::class ] | ||
]; | ||
/** | ||
* Class for serializing/Deserializing a cross-chain bridge | ||
* | ||
* @param Buffer|null $bytes | ||
* @throws Exception | ||
*/ | ||
public function __construct(?Buffer $bytes = null) | ||
{ | ||
if (!$bytes) { | ||
$bytes = Buffer::concat([ | ||
Buffer::from([0x14]), | ||
Buffer::alloc(40), | ||
Buffer::from([0x14]), | ||
Buffer::from([0x14]) | ||
]); | ||
} | ||
|
||
parent::__construct($bytes); | ||
} | ||
|
||
/** | ||
* Construct a cross-chain bridge from a BinaryParser | ||
* | ||
* @param BinaryParser $parser | ||
* @param int|null $lengthHint | ||
* @return SerializedType | ||
* @throws Exception | ||
*/ | ||
public static function fromParser(BinaryParser $parser, ?int $lengthHint = null): SerializedType | ||
{ | ||
$bufferArray = []; | ||
foreach (self::TYPE_ORDER as $item) { | ||
[$type] = [$item['type']]; | ||
if ($type === AccountId::class) { | ||
$parser->skip(1); | ||
$bufferArray[] = Buffer::from([0x14]); | ||
} | ||
$object = call_user_func($type .'::fromParser', $parser); | ||
$bufferArray[] = $object->toBytes(); | ||
} | ||
|
||
return new XchainBridge(Buffer::concat($bufferArray)); | ||
} | ||
|
||
/** | ||
* Construct a cross-chain bridge from a JSON string | ||
* | ||
* @param string $serializedJson | ||
* @return SerializedType | ||
* @throws Exception | ||
*/ | ||
public static function fromJson(string $serializedJson): SerializedType | ||
{ | ||
$json = json_decode($serializedJson, true); | ||
|
||
if (!self::isXchainBridgeObject($json)) { | ||
throw new Exception('Invalid type to construct an XChainBridge'); | ||
} | ||
|
||
$bufferArray = []; | ||
foreach (self::TYPE_ORDER as $item) { | ||
[$name, $type] = [$item['name'], $item['type']]; | ||
if ($type === AccountId::class) { | ||
$bufferArray[] = Buffer::from([0x14]); | ||
} | ||
$object = call_user_func($type . '::fromJson', is_string($json[$name]) ? $json[$name] : json_encode($json[$name])); | ||
$bufferArray[] = $object->toBytes(); | ||
} | ||
|
||
return new XchainBridge(Buffer::concat($bufferArray)); | ||
} | ||
|
||
/** | ||
* Returns the JSON representation of this XChainBridge as an array | ||
* | ||
* @return string|array | ||
* @throws Exception | ||
*/ | ||
public function toJson(): string|array | ||
{ | ||
$parser = new BinaryParser($this->toHex()); | ||
$json = []; | ||
foreach (self::TYPE_ORDER as $item) { | ||
[$name, $type] = [$item['name'], $item['type']]; | ||
if ($type === AccountId::class) { | ||
$parser->skip(1); | ||
} | ||
$object = call_user_func($type .'::fromParser', $parser)->toJson(); | ||
$json[$name] = $object; | ||
} | ||
|
||
return $json; | ||
} | ||
|
||
/** | ||
* Type guard for XchainBridge object | ||
* | ||
* @param array $json | ||
* @return bool | ||
*/ | ||
private static function isXchainBridgeObject(array $json): bool | ||
{ | ||
$keys = array_keys($json); | ||
sort($keys); | ||
|
||
return ( | ||
count($keys) === 4 && | ||
$keys[0] === 'IssuingChainDoor' && | ||
$keys[1] === 'IssuingChainIssue' && | ||
$keys[2] === 'LockingChainDoor' && | ||
$keys[3] === 'LockingChainIssue' | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
<?php declare(strict_types=1); | ||
|
||
namespace XRPL_PHP\Test\Core\RippleBinaryCodec\Types; | ||
|
||
use PHPUnit\Framework\TestCase; | ||
use XRPL_PHP\Core\RippleBinaryCodec\Types\XchainBridge; | ||
|
||
final class XchainBridgeTest extends TestCase | ||
{ | ||
private string $hex = "14AF80285F637EE4AF3C20378F9DFB12511ACB8D27000000000000000000000000000000000000000014550FC62003E785DC231A1058A05E56E3F09CF4E60000000000000000000000000000000000000000"; | ||
|
||
private array $json = [ | ||
"LockingChainDoor" => "rGzx83BVoqTYbGn7tiVAnFw7cbxjin13jL", | ||
"LockingChainIssue" => ["currency" => "XRP"], | ||
"IssuingChainDoor" => "r3kmLJN5D28dHuH8vZNUZpMC43pEHpaocV", | ||
"IssuingChainIssue" => ["currency" => "XRP"] | ||
]; | ||
|
||
public function testDecode(): void | ||
{ | ||
$this->assertEquals( | ||
$this->json, | ||
XchainBridge::fromHex($this->hex)->toJson() | ||
); | ||
} | ||
|
||
public function testEncode(): void | ||
{ | ||
$this->assertEquals( | ||
$this->hex, | ||
XchainBridge::fromJson(json_encode($this->json))->toHex() | ||
); | ||
} | ||
} |