Skip to content

Commit e0cc5a2

Browse files
authored
feat(svm): borsh serialise in scripts (#802)
* feat(svm): use borsh serializer in scripts Signed-off-by: Pablo Maldonado <[email protected]> * feat(svm): use borsh serializer in scripts Signed-off-by: Pablo Maldonado <[email protected]> --------- Signed-off-by: Pablo Maldonado <[email protected]>
1 parent 78a248d commit e0cc5a2

File tree

1 file changed

+103
-45
lines changed

1 file changed

+103
-45
lines changed

src/svm/relayHashUtils.ts

Lines changed: 103 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { BN } from "@coral-xyz/anchor";
22
import { ethers } from "ethers";
33
import { RelayerRefundLeaf, RelayerRefundLeafSolana, SlowFillLeaf } from "../types/svm";
4+
import { serialize } from "borsh";
45

56
/**
67
* Calculates the relay hash from relay data and chain ID.
@@ -75,36 +76,56 @@ export function hashNonEmptyMessage(message: Buffer) {
7576
return new Uint8Array(32);
7677
}
7778

79+
/**
80+
* Class for relay data.
81+
*/
82+
class RelayData {
83+
constructor(properties: any) {
84+
Object.assign(this, properties);
85+
}
86+
}
87+
88+
/**
89+
* Schema for relay data.
90+
*/
91+
const relayDataSchema = new Map([
92+
[
93+
RelayData,
94+
{
95+
kind: "struct",
96+
fields: [
97+
["amountToReturn", "u64"],
98+
["chainId", "u64"],
99+
["refundAmounts", ["u64"]],
100+
["leafId", "u32"],
101+
["mintPublicKey", [32]],
102+
["refundAddresses", [[32]]],
103+
],
104+
},
105+
],
106+
]);
107+
78108
/**
79109
* Calculates the relayer refund leaf hash for Solana.
80110
*/
81111
export function calculateRelayerRefundLeafHashUint8Array(relayData: RelayerRefundLeafSolana): string {
82-
const refundAmountsBuffer = Buffer.concat(
83-
relayData.refundAmounts.map((amount) => {
84-
const buf = Buffer.alloc(8);
85-
amount.toArrayLike(Buffer, "le", 8).copy(buf);
86-
return buf;
87-
})
88-
);
112+
const refundAddresses = relayData.refundAddresses.map((address) => address.toBuffer());
89113

90-
const refundAddressesBuffer = Buffer.concat(relayData.refundAddresses.map((address) => address.toBuffer()));
114+
const data = new RelayData({
115+
amountToReturn: relayData.amountToReturn,
116+
chainId: relayData.chainId,
117+
refundAmounts: relayData.refundAmounts,
118+
leafId: relayData.leafId,
119+
mintPublicKey: relayData.mintPublicKey.toBuffer(),
120+
refundAddresses: refundAddresses,
121+
});
91122

92-
// TODO: We better consider reusing Borch serializer in production.
93-
const contentToHash = Buffer.concat([
94-
// SVM leaves require the first 64 bytes to be 0 to ensure EVM leaves can never be played on SVM and vice versa.
95-
Buffer.alloc(64, 0),
96-
relayData.amountToReturn.toArrayLike(Buffer, "le", 8),
97-
relayData.chainId.toArrayLike(Buffer, "le", 8),
98-
new BN(relayData.refundAmounts.length).toArrayLike(Buffer, "le", 4),
99-
refundAmountsBuffer,
100-
relayData.leafId.toArrayLike(Buffer, "le", 4),
101-
relayData.mintPublicKey.toBuffer(),
102-
new BN(relayData.refundAddresses.length).toArrayLike(Buffer, "le", 4),
103-
refundAddressesBuffer,
104-
]);
123+
const serializedData = serialize(relayDataSchema, data);
105124

106-
const relayHash = ethers.utils.keccak256(contentToHash);
107-
return relayHash;
125+
// SVM leaves require the first 64 bytes to be 0 to ensure EVM leaves can never be played on SVM and vice versa.
126+
const contentToHash = Buffer.concat([Buffer.alloc(64, 0), serializedData]);
127+
128+
return ethers.utils.keccak256(contentToHash);
108129
}
109130

110131
/**
@@ -134,31 +155,68 @@ export const relayerRefundHashFn = (input: RelayerRefundLeaf | RelayerRefundLeaf
134155
}
135156
};
136157

158+
/**
159+
* Class for slow fill data.
160+
*/
161+
class SlowFillData {
162+
constructor(properties: any) {
163+
Object.assign(this, properties);
164+
}
165+
}
166+
167+
/**
168+
* Schema for slow fill data.
169+
*/
170+
const slowFillDataSchema = new Map([
171+
[
172+
SlowFillData,
173+
{
174+
kind: "struct",
175+
fields: [
176+
["depositor", [32]],
177+
["recipient", [32]],
178+
["exclusiveRelayer", [32]],
179+
["inputToken", [32]],
180+
["outputToken", [32]],
181+
["inputAmount", "u64"],
182+
["outputAmount", "u64"],
183+
["originChainId", "u64"],
184+
["depositId", [32]],
185+
["fillDeadline", "u32"],
186+
["exclusivityDeadline", "u32"],
187+
["message", ["u8"]],
188+
["chainId", "u64"],
189+
["updatedOutputAmount", "u64"],
190+
],
191+
},
192+
],
193+
]);
194+
137195
/**
138196
* Hash function for slow fill leaves.
139197
*/
140-
// TODO: We better consider reusing Borch serializer in production.
141198
export function slowFillHashFn(slowFillLeaf: SlowFillLeaf): string {
142-
const contentToHash = Buffer.concat([
143-
// SVM leaves require the first 64 bytes to be 0 to ensure EVM leaves can never be played on SVM and vice versa.
144-
Buffer.alloc(64, 0),
145-
slowFillLeaf.relayData.depositor.toBuffer(),
146-
slowFillLeaf.relayData.recipient.toBuffer(),
147-
slowFillLeaf.relayData.exclusiveRelayer.toBuffer(),
148-
slowFillLeaf.relayData.inputToken.toBuffer(),
149-
slowFillLeaf.relayData.outputToken.toBuffer(),
150-
slowFillLeaf.relayData.inputAmount.toArrayLike(Buffer, "le", 8),
151-
slowFillLeaf.relayData.outputAmount.toArrayLike(Buffer, "le", 8),
152-
slowFillLeaf.relayData.originChainId.toArrayLike(Buffer, "le", 8),
153-
Buffer.from(slowFillLeaf.relayData.depositId),
154-
new BN(slowFillLeaf.relayData.fillDeadline).toArrayLike(Buffer, "le", 4),
155-
new BN(slowFillLeaf.relayData.exclusivityDeadline).toArrayLike(Buffer, "le", 4),
156-
new BN(slowFillLeaf.relayData.message.length).toArrayLike(Buffer, "le", 4),
157-
slowFillLeaf.relayData.message,
158-
slowFillLeaf.chainId.toArrayLike(Buffer, "le", 8),
159-
slowFillLeaf.updatedOutputAmount.toArrayLike(Buffer, "le", 8),
160-
]);
199+
const data = new SlowFillData({
200+
depositor: Uint8Array.from(slowFillLeaf.relayData.depositor.toBuffer()),
201+
recipient: Uint8Array.from(slowFillLeaf.relayData.recipient.toBuffer()),
202+
exclusiveRelayer: Uint8Array.from(slowFillLeaf.relayData.exclusiveRelayer.toBuffer()),
203+
inputToken: Uint8Array.from(slowFillLeaf.relayData.inputToken.toBuffer()),
204+
outputToken: Uint8Array.from(slowFillLeaf.relayData.outputToken.toBuffer()),
205+
inputAmount: slowFillLeaf.relayData.inputAmount,
206+
outputAmount: slowFillLeaf.relayData.outputAmount,
207+
originChainId: slowFillLeaf.relayData.originChainId,
208+
depositId: Uint8Array.from(Buffer.from(slowFillLeaf.relayData.depositId)),
209+
fillDeadline: slowFillLeaf.relayData.fillDeadline,
210+
exclusivityDeadline: slowFillLeaf.relayData.exclusivityDeadline,
211+
message: Uint8Array.from(slowFillLeaf.relayData.message),
212+
chainId: slowFillLeaf.chainId,
213+
updatedOutputAmount: slowFillLeaf.updatedOutputAmount,
214+
});
215+
216+
const serializedData = serialize(slowFillDataSchema, data);
217+
218+
// SVM leaves require the first 64 bytes to be 0 to ensure EVM leaves cannot be played on SVM and vice versa
219+
const contentToHash = Buffer.concat([Buffer.alloc(64, 0), serializedData]);
161220

162-
const slowFillHash = ethers.utils.keccak256(contentToHash);
163-
return slowFillHash;
221+
return ethers.utils.keccak256(contentToHash);
164222
}

0 commit comments

Comments
 (0)