clients/js: Add support for NFT bridge transfers

commit-id:6b11415c
This commit is contained in:
Csongor Kiss 2022-06-29 20:12:07 +01:00
parent 465916c3f8
commit fa3cec16f6
8 changed files with 128 additions and 3 deletions

View File

@ -23,5 +23,9 @@ install: build
chmod +x build/main.js
npm link
.PHONY: test
test: build
./run_parse_tests
clean:
rm -rf build node_modules

View File

@ -221,6 +221,10 @@ export async function execute_evm(
console.log("Registering chain")
console.log("Hash: " + (await nb.registerChain(vaa, overrides)).hash)
break
case "Transfer":
console.log("Completing transfer")
console.log("Hash: " + (await nb.completeTransfer(vaa, overrides)).hash)
break
default:
impossible(payload)

View File

@ -0,0 +1,24 @@
{
version: 1,
guardianSetIndex: 0,
signatures: [],
timestamp: 1,
nonce: 1,
emitterChain: 1,
emitterAddress: '0x0000000000000000000000000000000000000000000000000000000000000004',
sequence: 41401099n,
consistencyLevel: 0,
payload: {
module: 'NFTBridge',
type: 'Transfer',
tokenAddress: '0x0000000000000000000000000000000000000000000000000000000000000004',
tokenChain: 1,
tokenSymbol: 'FOO',
tokenName: 'BAR',
tokenId: 10n,
tokenURI: 'google.com',
toAddress: '0x0000000000000000000000000000000000000000000000000000000000000004',
chain: 10
},
digest: '0xe2a7a0f5d67018c74683851fca870403455f89d9f474e2af104740e31a00da63'
}

View File

@ -0,0 +1 @@
010000000000000000010000000100010000000000000000000000000000000000000000000000000000000000000004000000000277bb0b0001000000000000000000000000000000000000000000000000000000000000000400010000000000000000000000000000000000000000000000000000000000464f4f0000000000000000000000000000000000000000000000000000000000424152000000000000000000000000000000000000000000000000000000000000000a0a676f6f676c652e636f6d0000000000000000000000000000000000000000000000000000000000000004000a

View File

@ -42,7 +42,7 @@ for test in ${test_files[@]}; do
expected="$test_name.expected"
result=$(mktemp)
worm parse $(cat "$test") > "$result" 2>&1
node build/main.js parse $(cat "$test") > "$result" 2>&1
if [ $accept = true ]; then
echo "Updating $test_name"
cat "$result" > "$expected"

View File

@ -46,9 +46,11 @@ export async function execute_solana(
console.log("Registering chain")
ix = nft_bridge.register_chain_ix(nft_bridge_id.toString(), bridge_id.toString(), from.publicKey.toString(), vaa);
break
case "Transfer":
throw Error("Can't redeem NFTs from CLI")
// TODO: what's the authority account? just bail for now
default:
ix = impossible(v.payload)
}
break
case "TokenBridge":

View File

@ -72,6 +72,9 @@ export async function execute_terra(
case "RegisterChain":
console.log("Registering chain");
break;
case "Transfer":
console.log("Completing transfer");
break;
default:
impossible(payload);
}

View File

@ -63,7 +63,7 @@ export type Payload =
| TokenBridgeTransfer
| TokenBridgeTransferWithPayload
| TokenBridgeAttestMeta
// TODO: add other types of payloads
| NFTBridgeTransfer
export type ContractUpgrade =
CoreContractUpgrade
@ -81,7 +81,9 @@ export function parse(buffer: Buffer): VAA<Payload | null> {
.or(tokenBridgeTransferParser())
.or(tokenBridgeTransferWithPayloadParser())
.or(tokenBridgeAttestMetaParser())
.or(nftBridgeTransferParser())
const payload = parser.parse(vaa.payload)
delete payload['tokenURILength']
var myVAA = { ...vaa, payload }
return myVAA
@ -188,6 +190,9 @@ function vaaBody(vaa: VAA<Payload>) {
case "RegisterChain":
payload_str = serialisePortalRegisterChain(payload)
break
case "Transfer":
payload_str = serialiseNFTBridgeTransfer(payload)
break
default:
impossible(payload)
break
@ -650,6 +655,88 @@ function serialiseTokenBridgeTransferWithPayload(payload: TokenBridgeTransferWit
////////////////////////////////////////////////////////////////////////////////
// NFT bridge
export interface NFTBridgeTransfer {
module: "NFTBridge"
type: "Transfer"
tokenAddress: string
tokenChain: number
tokenSymbol: string
tokenName: string
tokenId: bigint
tokenURI: string
toAddress: string
chain: number
}
function nftBridgeTransferParser(): P<NFTBridgeTransfer> {
return new P(new Parser()
.endianess("big")
.string("module", {
length: (_) => 0,
formatter: (_) => "NFTBridge"
})
.uint8("type", {
assert: 1,
formatter: (_action) => "Transfer"
})
.array("tokenAddress", {
type: "uint8",
lengthInBytes: 32,
formatter: (arr) => "0x" + Buffer.from(arr).toString("hex")
})
.uint16("tokenChain")
.array("tokenSymbol", {
type: "uint8",
lengthInBytes: 32,
formatter: (arr: Uint8Array) => Buffer.from(arr).toString("utf8", arr.findIndex((val) => val != 0))
})
.array("tokenName", {
type: "uint8",
lengthInBytes: 32,
formatter: (arr: Uint8Array) => Buffer.from(arr).toString("utf8", arr.findIndex((val) => val != 0))
})
.array("tokenId", {
type: "uint8",
lengthInBytes: 32,
formatter: (bytes) => BigNumber.from(bytes).toBigInt()
})
.uint8("tokenURILength")
.array("tokenURI", {
type: "uint8",
lengthInBytes: function() {
return this.tokenURILength
},
formatter: (arr: Uint8Array) => Buffer.from(arr).toString("utf8")
})
.array("toAddress", {
type: "uint8",
lengthInBytes: 32,
formatter: (arr) => "0x" + Buffer.from(arr).toString("hex")
})
.uint16("chain")
.string("end", {
greedy: true,
assert: str => str === ""
})
)
}
function serialiseNFTBridgeTransfer(payload: NFTBridgeTransfer): string {
const body = [
encode("uint8", 1),
encode("bytes32", hex(payload.tokenAddress)),
encode("uint16", payload.tokenChain),
encode("bytes32", encodeString(payload.tokenSymbol)),
encode("bytes32", encodeString(payload.tokenName)),
encode("uint256", payload.tokenId),
encode("uint8", payload.tokenURI.length),
Buffer.from(payload.tokenURI, "utf8").toString("hex"),
encode("bytes32", hex(payload.toAddress)),
encode("uint16", payload.chain),
]
return body.join("")
}
// This function should be called after pattern matching on all possible options
// of an enum (union) type, so that typescript can derive that no other options
// are possible. If (from JavaScript land) an unsupported argument is passed