Skip to content

Commit e2ea40c

Browse files
authored
feat(minor-multisig-prover): stellar encode execute data (#598)
1 parent bcc5dc1 commit e2ea40c

File tree

11 files changed

+415
-13
lines changed

11 files changed

+415
-13
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

contracts/multisig-prover/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ serde_json = "1.0.89"
5757
service-registry = { workspace = true }
5858
sha3 = { workspace = true }
5959
stellar = { workspace = true }
60+
stellar-xdr = { workspace = true }
6061
sui-gateway = { workspace = true }
6162
thiserror = { workspace = true }
6263
voting-verifier = { workspace = true, features = ["library"] }

contracts/multisig-prover/src/encoding/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ impl Encoder {
5757
&self.digest(domain_separator, verifier_set, payload)?,
5858
payload,
5959
),
60-
Encoder::StellarXdr => todo!(),
60+
Encoder::StellarXdr => stellar_xdr::encode_execute_data(verifier_set, sigs, payload),
6161
}
6262
}
6363
}
@@ -70,7 +70,7 @@ where
7070
let recovery_transform = match encoder {
7171
Encoder::Abi => add_27,
7272
Encoder::Bcs => no_op,
73-
Encoder::StellarXdr => no_op,
73+
_ => panic!("unsupported encoder"),
7474
};
7575
signers
7676
.into_iter()

contracts/multisig-prover/src/encoding/stellar_xdr.rs

Lines changed: 186 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
use axelar_wasm_std::hash::Hash;
22
use axelar_wasm_std::FnExt;
3+
use cosmwasm_std::HexBinary;
34
use error_stack::{Result, ResultExt};
5+
use multisig::msg::SignerWithSig;
46
use multisig::verifier_set::VerifierSet;
57
use sha3::{Digest, Keccak256};
6-
use stellar::{Message, Messages, WeightedSigners};
8+
use stellar::{Message, Messages, Proof, WeightedSigners};
9+
use stellar_xdr::curr::{Limits, ScVal, WriteXdr};
710

811
use crate::error::ContractError;
912
use crate::payload::Payload;
@@ -42,15 +45,49 @@ pub fn payload_digest(
4245
Ok(Keccak256::digest(unsigned).into())
4346
}
4447

48+
/// `encode_execute_data` returns the XDR encoded external gateway function call args.
49+
/// The relayer will use this data to submit the payload to the contract.
50+
pub fn encode_execute_data(
51+
verifier_set: &VerifierSet,
52+
signatures: Vec<SignerWithSig>,
53+
payload: &Payload,
54+
) -> Result<HexBinary, ContractError> {
55+
let payload = match payload {
56+
Payload::Messages(messages) => ScVal::try_from(
57+
messages
58+
.iter()
59+
.map(Message::try_from)
60+
.collect::<Result<Vec<_>, _>>()
61+
.change_context(ContractError::InvalidMessage)?
62+
.then(Messages::from),
63+
),
64+
Payload::VerifierSet(verifier_set) => ScVal::try_from(
65+
WeightedSigners::try_from(verifier_set)
66+
.change_context(ContractError::InvalidVerifierSet)?,
67+
),
68+
}
69+
.change_context(ContractError::SerializeData)?;
70+
71+
let proof =
72+
Proof::try_from((verifier_set.clone(), signatures)).change_context(ContractError::Proof)?;
73+
74+
let execute_data = ScVal::try_from((payload, proof))
75+
.expect("must convert tuple of size 2 to ScVec")
76+
.to_xdr(Limits::none())
77+
.change_context(ContractError::SerializeData)?;
78+
79+
Ok(execute_data.as_slice().into())
80+
}
4581
#[cfg(test)]
4682
mod tests {
4783
use cosmwasm_std::{Addr, HexBinary, Uint128};
48-
use multisig::key::KeyType;
49-
use multisig::msg::Signer;
84+
use multisig::key::KeyType::Ed25519;
85+
use multisig::key::Signature;
86+
use multisig::msg::{Signer, SignerWithSig};
5087
use multisig::verifier_set::VerifierSet;
5188
use router_api::{CrossChainId, Message};
5289

53-
use crate::encoding::stellar_xdr::payload_digest;
90+
use crate::encoding::stellar_xdr::{encode_execute_data, payload_digest};
5491
use crate::payload::Payload;
5592

5693
#[test]
@@ -87,7 +124,7 @@ mod tests {
87124
6u128,
88125
),
89126
];
90-
let verifier_set = gen_veifier_set(signers_data, 22, 2024);
127+
let verifier_set = gen_verifier_set(signers_data, 22, 2024);
91128

92129
let payload = Payload::Messages(vec![Message {
93130
cc_id: CrossChainId {
@@ -120,7 +157,7 @@ mod tests {
120157

121158
#[test]
122159
fn stellar_verifier_set_payload_digest() {
123-
let verifier_set = gen_veifier_set(
160+
let verifier_set = gen_verifier_set(
124161
vec![(
125162
"addr_1",
126163
"bf95c447eb2e694974ee2cf5f17e7165bc884a0cb676bb4de50c604bb7a6ea77",
@@ -156,7 +193,7 @@ mod tests {
156193
7u128,
157194
),
158195
];
159-
let payload = Payload::VerifierSet(gen_veifier_set(signers_data, 27, 2024));
196+
let payload = Payload::VerifierSet(gen_verifier_set(signers_data, 27, 2024));
160197
let domain_separator: [u8; 32] =
161198
HexBinary::from_hex("6773bd037510492f863cba62a0f3c55ac846883f33cae7266aff8be5eb9681e8")
162199
.unwrap()
@@ -168,7 +205,130 @@ mod tests {
168205
));
169206
}
170207

171-
fn gen_veifier_set(
208+
#[test]
209+
fn stellar_approve_messages_execute_data() {
210+
let signers_data = vec![
211+
(
212+
"addr_1",
213+
"12f7d9a9463212335914b39ee90bfa2045f90b64c1f2d7b58ed335282abac4a4",
214+
8u128,
215+
"b5b3b0749aa585f866d802e32ca4a6356f82eb52e2a1b4797cbaa30f3d755462f2eb995c70d9099e436b8a48498e4d613ff2d3ca7618973a36c2fde17493180f",
216+
),
217+
(
218+
"addr_2",
219+
"4c3863e4b0252a8674c1c6ad70b3ca3002b400b49ddfae5583b21907e65c5dd8",
220+
1u128,
221+
"cb8a1b98ec7678d5eb965d47c449b2b8396d170e53ad7b5f65a7c0fdf2aebe206b65be7cb2e81c7ddd8924acb2ffc2d463b678993227fdfbfc3ef03a8ffa030c",
222+
),
223+
(
224+
"addr_3",
225+
"c35aa94d2038f258ecb1bb28fbc8a83ab79d2dc0a7223fd528a8f52a14c03292",
226+
7u128,
227+
"28e2c8accfa1c2db93349c6d3f783004d6a92cdbf322b92b3555315999e0eaf5d8bdf9deb58d798168a880972e81b8513dcb942de44862317d501cf7445c660a"
228+
),
229+
230+
];
231+
232+
let verifier_set = gen_verifier_set(
233+
signers_data
234+
.iter()
235+
.map(|(t1, t2, t3, _)| (*t1, *t2, *t3))
236+
.collect(),
237+
10,
238+
2024,
239+
);
240+
241+
let signer_with_sig = gen_signers_with_sig(signers_data);
242+
243+
let payload = Payload::Messages(vec![Message {
244+
cc_id: CrossChainId {
245+
source_chain: "source".parse().unwrap(),
246+
message_id: "test".parse().unwrap(),
247+
},
248+
source_address: "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHK3M"
249+
.parse()
250+
.unwrap(),
251+
destination_chain: "stellar".parse().unwrap(),
252+
destination_address: "CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMDR4"
253+
.parse()
254+
.unwrap(),
255+
payload_hash: HexBinary::from_hex(
256+
"595c9108df17d1cc43e8268ec1516064299c1388bcc86fdd566bcdf400a0a1ed",
257+
)
258+
.unwrap()
259+
.to_array()
260+
.unwrap(),
261+
}]);
262+
263+
goldie::assert!(
264+
encode_execute_data(&verifier_set, signer_with_sig, &payload)
265+
.unwrap()
266+
.to_hex()
267+
);
268+
}
269+
270+
#[test]
271+
fn stellar_rotate_signers_execute_data() {
272+
let signers_data = vec![
273+
(
274+
"addr_1",
275+
"77dd4768dda195f8080fe970be8fec5fee9cea781718158ce19d4a331442fd57",
276+
2u128,
277+
"91db8ad94ab379ee9021caeb3ee852582d09d06801213256cbd2937f2ad8182f518fde7a7f8c801adde7161e05cbbb9841ac0bf3290831570a54c6ae3d089703",
278+
),
279+
];
280+
281+
let verifier_set = gen_verifier_set(
282+
signers_data
283+
.iter()
284+
.map(|(t1, t2, t3, _)| (*t1, *t2, *t3))
285+
.collect(),
286+
1,
287+
2024,
288+
);
289+
290+
let signer_with_sig = gen_signers_with_sig(signers_data);
291+
292+
let payload = Payload::VerifierSet(gen_verifier_set(
293+
vec![
294+
(
295+
"addr_1",
296+
"358a2305fc783b6072049ee6f5f76fb14c3a14d7c01e36d9ef502661bf46a011",
297+
9u128,
298+
),
299+
(
300+
"addr_2",
301+
"3b1caf530189a9a65ae347b18cb8bf88729ba90d2aeaf7f185b600400ab49891",
302+
1u128,
303+
),
304+
(
305+
"addr_3",
306+
"531616448afd45c0e3e053622cbccb65d8fc99cd2f02636d728739811e72eafb",
307+
3u128,
308+
),
309+
(
310+
"addr_4",
311+
"5e4c8ec6569774adf69cb6e2bc4ef556c2fc6b412c85d6a5e0b18d54b069e594",
312+
7u128,
313+
),
314+
(
315+
"addr_5",
316+
"8097528d987899f887c08c23a928dfe6fe9550010d19c7be0b46b5d0596997cc",
317+
3u128,
318+
),
319+
],
320+
17,
321+
2024,
322+
));
323+
324+
goldie::assert!(
325+
encode_execute_data(&verifier_set, signer_with_sig, &payload)
326+
.unwrap()
327+
.to_hex()
328+
);
329+
}
330+
331+
fn gen_verifier_set(
172332
signers_data: Vec<(&str, &str, u128)>,
173333
threshold: u128,
174334
created_at: u64,
@@ -181,7 +341,7 @@ mod tests {
181341
addr.to_string(),
182342
Signer {
183343
address: Addr::unchecked(addr),
184-
pub_key: (KeyType::Ed25519, HexBinary::from_hex(pub_key).unwrap())
344+
pub_key: (Ed25519, HexBinary::from_hex(pub_key).unwrap())
185345
.try_into()
186346
.unwrap(),
187347
weight: Uint128::from(weight),
@@ -193,4 +353,21 @@ mod tests {
193353
created_at,
194354
}
195355
}
356+
fn gen_signers_with_sig(signers_data: Vec<(&str, &str, u128, &str)>) -> Vec<SignerWithSig> {
357+
signers_data
358+
.into_iter()
359+
.map(|(addr, pub_key, weight, sig)| {
360+
Signer {
361+
address: Addr::unchecked(addr),
362+
pub_key: (Ed25519, HexBinary::from_hex(pub_key).unwrap())
363+
.try_into()
364+
.unwrap(),
365+
weight: Uint128::from(weight),
366+
}
367+
.with_sig(
368+
Signature::try_from((Ed25519, HexBinary::from_hex(sig).unwrap())).unwrap(),
369+
)
370+
})
371+
.collect::<Vec<_>>()
372+
}
196373
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
0000001000000001000000020000001000000001000000010000001100000001000000050000000f00000010636f6e74726163745f61646472657373000000120000000100000000000000000000000000000000000000000000000000000000000000060000000f0000000a6d6573736167655f696400000000000e00000004746573740000000f0000000c7061796c6f61645f686173680000000d00000020595c9108df17d1cc43e8268ec1516064299c1388bcc86fdd566bcdf400a0a1ed0000000f0000000e736f757263655f6164647265737300000000000e0000003843414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141414141484b334d0000000f0000000c736f757263655f636861696e0000000e00000006736f7572636500000000001100000001000000030000000f000000056e6f6e63650000000000000d0000002000000000000000000000000000000000000000000000000000000000000007e80000000f000000077369676e657273000000001000000001000000030000001100000001000000020000000f000000097369676e61747572650000000000001000000001000000020000000f000000065369676e656400000000000d00000040b5b3b0749aa585f866d802e32ca4a6356f82eb52e2a1b4797cbaa30f3d755462f2eb995c70d9099e436b8a48498e4d613ff2d3ca7618973a36c2fde17493180f0000000f000000067369676e657200000000001100000001000000020000000f000000067369676e657200000000000d0000002012f7d9a9463212335914b39ee90bfa2045f90b64c1f2d7b58ed335282abac4a40000000f00000006776569676874000000000009000000000000000000000000000000080000001100000001000000020000000f000000097369676e61747572650000000000001000000001000000020000000f000000065369676e656400000000000d00000040cb8a1b98ec7678d5eb965d47c449b2b8396d170e53ad7b5f65a7c0fdf2aebe206b65be7cb2e81c7ddd8924acb2ffc2d463b678993227fdfbfc3ef03a8ffa030c0000000f000000067369676e657200000000001100000001000000020000000f000000067369676e657200000000000d000000204c3863e4b0252a8674c1c6ad70b3ca3002b400b49ddfae5583b21907e65c5dd80000000f00000006776569676874000000000009000000000000000000000000000000010000001100000001000000020000000f000000097369676e61747572650000000000001000000001000000020000000f000000065369676e656400000000000d0000004028e2c8accfa1c2db93349c6d3f783004d6a92cdbf322b92b3555315999e0eaf5d8bdf9deb58d798168a880972e81b8513dcb942de44862317d501cf7445c660a0000000f000000067369676e657200000000001100000001000000020000000f000000067369676e657200000000000d00000020c35aa94d2038f258ecb1bb28fbc8a83ab79d2dc0a7223fd528a8f52a14c032920000000f00000006776569676874000000000009000000000000000000000000000000070000000f000000097468726573686f6c64000000000000090000000000000000000000000000000a
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
0000001000000001000000020000001100000001000000030000000f000000056e6f6e63650000000000000d0000002000000000000000000000000000000000000000000000000000000000000007e80000000f000000077369676e657273000000001000000001000000050000001100000001000000020000000f000000067369676e657200000000000d00000020358a2305fc783b6072049ee6f5f76fb14c3a14d7c01e36d9ef502661bf46a0110000000f00000006776569676874000000000009000000000000000000000000000000090000001100000001000000020000000f000000067369676e657200000000000d000000203b1caf530189a9a65ae347b18cb8bf88729ba90d2aeaf7f185b600400ab498910000000f00000006776569676874000000000009000000000000000000000000000000010000001100000001000000020000000f000000067369676e657200000000000d00000020531616448afd45c0e3e053622cbccb65d8fc99cd2f02636d728739811e72eafb0000000f00000006776569676874000000000009000000000000000000000000000000030000001100000001000000020000000f000000067369676e657200000000000d000000205e4c8ec6569774adf69cb6e2bc4ef556c2fc6b412c85d6a5e0b18d54b069e5940000000f00000006776569676874000000000009000000000000000000000000000000070000001100000001000000020000000f000000067369676e657200000000000d000000208097528d987899f887c08c23a928dfe6fe9550010d19c7be0b46b5d0596997cc0000000f00000006776569676874000000000009000000000000000000000000000000030000000f000000097468726573686f6c6400000000000009000000000000000000000000000000110000001100000001000000030000000f000000056e6f6e63650000000000000d0000002000000000000000000000000000000000000000000000000000000000000007e80000000f000000077369676e657273000000001000000001000000010000001100000001000000020000000f000000097369676e61747572650000000000001000000001000000020000000f000000065369676e656400000000000d0000004091db8ad94ab379ee9021caeb3ee852582d09d06801213256cbd2937f2ad8182f518fde7a7f8c801adde7161e05cbbb9841ac0bf3290831570a54c6ae3d0897030000000f000000067369676e657200000000001100000001000000020000000f000000067369676e657200000000000d0000002077dd4768dda195f8080fe970be8fec5fee9cea781718158ce19d4a331442fd570000000f00000006776569676874000000000009000000000000000000000000000000020000000f000000097468726573686f6c640000000000000900000000000000000000000000000001

external-gateways/stellar/src/error.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,8 @@ pub enum Error {
88
InvalidPublicKey,
99
#[error("invalid destination address")]
1010
InvalidDestinationAddress,
11+
#[error("unsupported type of signature")]
12+
UnsupportedSignature,
13+
#[error("invalid signature")]
14+
InvalidSignature,
1115
}

0 commit comments

Comments
 (0)