Skip to content

Commit fdb11a7

Browse files
committed
Lending-utils: Add parse reply instantiate data
1 parent 2126c85 commit fdb11a7

File tree

3 files changed

+172
-2
lines changed

3 files changed

+172
-2
lines changed

packages/lending_utils/src/interest.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
use cosmwasm_std::{Decimal, Fraction};
1+
use shade_protocol::c_std::{Decimal, Fraction};
22
use schemars::JsonSchema;
3+
use thiserror::Error;
34
use serde::{Deserialize, Serialize};
45

56
#[derive(Serialize, Deserialize, Clone, Eq, PartialEq, JsonSchema, Debug)]
@@ -88,8 +89,9 @@ impl ValidatedInterest {
8889
}
8990
}
9091

91-
#[derive(Debug, Eq, PartialEq)]
92+
#[derive(Debug, Error, Eq, PartialEq)]
9293
pub enum InterestError {
94+
#[error("InvalidOptimalUtilisation {0}")]
9395
InvalidOptimalUtilisation(Decimal),
9496
}
9597

packages/lending_utils/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ pub mod coin;
33
pub mod credit_line;
44
pub mod interest;
55
pub mod price;
6+
pub mod parse_reply;
67
pub mod token;
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
#! https://github.com/CosmWasm/cw-utils/blob/3d9c9dd64080d441b2484e036eb75a602526384f/src/parse_reply.rs
2+
3+
use thiserror::Error;
4+
5+
use shade_protocol::c_std::{Binary, Reply};
6+
7+
// Protobuf wire types (https://developers.google.com/protocol-buffers/docs/encoding)
8+
const WIRE_TYPE_LENGTH_DELIMITED: u8 = 2;
9+
// Up to 9 bytes of varints as a practical limit (https://github.com/multiformats/unsigned-varint#practical-maximum-of-9-bytes-for-security)
10+
const VARINT_MAX_BYTES: usize = 9;
11+
12+
#[derive(Clone, Debug, PartialEq, Eq)]
13+
pub struct MsgInstantiateContractResponse {
14+
pub contract_address: String,
15+
pub data: Option<Binary>,
16+
}
17+
18+
#[derive(Clone, Debug, PartialEq, Eq)]
19+
pub struct MsgExecuteContractResponse {
20+
pub data: Option<Binary>,
21+
}
22+
23+
/// Base128 varint decoding.
24+
/// The remaining of the data is kept in the data parameter.
25+
fn parse_protobuf_varint(data: &mut Vec<u8>, field_number: u8) -> Result<usize, ParseReplyError> {
26+
let data_len = data.len();
27+
let mut len: u64 = 0;
28+
let mut i = 0;
29+
while i < VARINT_MAX_BYTES {
30+
if data_len == i {
31+
return Err(ParseReplyError::ParseFailure(format!(
32+
"failed to decode Protobuf message: field #{}: varint data too short",
33+
field_number
34+
)));
35+
}
36+
len += ((data[i] & 0x7f) as u64) << (i * 7);
37+
if data[i] & 0x80 == 0 {
38+
break;
39+
}
40+
i += 1;
41+
}
42+
if i == VARINT_MAX_BYTES {
43+
return Err(ParseReplyError::ParseFailure(format!(
44+
"failed to decode Protobuf message: field #{}: varint data too long",
45+
field_number
46+
)));
47+
}
48+
*data = data[i + 1..].to_owned();
49+
50+
Ok(len as usize) // Gently fall back to the arch's max addressable size
51+
}
52+
53+
/// Helper function to parse length-prefixed protobuf fields.
54+
/// The remaining of the data is kept in the data parameter.
55+
fn parse_protobuf_length_prefixed(
56+
data: &mut Vec<u8>,
57+
field_number: u8,
58+
) -> Result<Vec<u8>, ParseReplyError> {
59+
if data.is_empty() {
60+
return Ok(vec![]);
61+
};
62+
let mut rest_1 = data.split_off(1);
63+
let wire_type = data[0] & 0b11;
64+
let field = data[0] >> 3;
65+
66+
if field != field_number {
67+
return Err(ParseReplyError::ParseFailure(format!(
68+
"failed to decode Protobuf message: invalid field #{} for field #{}",
69+
field, field_number
70+
)));
71+
}
72+
if wire_type != WIRE_TYPE_LENGTH_DELIMITED {
73+
return Err(ParseReplyError::ParseFailure(format!(
74+
"failed to decode Protobuf message: field #{}: invalid wire type {}",
75+
field_number, wire_type
76+
)));
77+
}
78+
79+
let len = parse_protobuf_varint(&mut rest_1, field_number)?;
80+
if rest_1.len() < len {
81+
return Err(ParseReplyError::ParseFailure(format!(
82+
"failed to decode Protobuf message: field #{}: message too short",
83+
field_number
84+
)));
85+
}
86+
*data = rest_1.split_off(len);
87+
88+
Ok(rest_1)
89+
}
90+
91+
fn parse_protobuf_string(data: &mut Vec<u8>, field_number: u8) -> Result<String, ParseReplyError> {
92+
let str_field = parse_protobuf_length_prefixed(data, field_number)?;
93+
Ok(String::from_utf8(str_field)?)
94+
}
95+
96+
fn parse_protobuf_bytes(
97+
data: &mut Vec<u8>,
98+
field_number: u8,
99+
) -> Result<Option<Binary>, ParseReplyError> {
100+
let bytes_field = parse_protobuf_length_prefixed(data, field_number)?;
101+
if bytes_field.is_empty() {
102+
Ok(None)
103+
} else {
104+
Ok(Some(Binary(bytes_field)))
105+
}
106+
}
107+
108+
pub fn parse_reply_instantiate_data(
109+
msg: Reply,
110+
) -> Result<MsgInstantiateContractResponse, ParseReplyError> {
111+
let data = msg
112+
.result
113+
.into_result()
114+
.map_err(ParseReplyError::SubMsgFailure)?
115+
.data
116+
.ok_or_else(|| ParseReplyError::ParseFailure("Missing reply data".to_owned()))?;
117+
parse_instantiate_response_data(&data.0)
118+
}
119+
120+
pub fn parse_reply_execute_data(msg: Reply) -> Result<MsgExecuteContractResponse, ParseReplyError> {
121+
let data = msg
122+
.result
123+
.into_result()
124+
.map_err(ParseReplyError::SubMsgFailure)?
125+
.data
126+
.ok_or_else(|| ParseReplyError::ParseFailure("Missing reply data".to_owned()))?;
127+
parse_execute_response_data(&data.0)
128+
}
129+
130+
pub fn parse_instantiate_response_data(
131+
data: &[u8],
132+
) -> Result<MsgInstantiateContractResponse, ParseReplyError> {
133+
// Manual protobuf decoding
134+
let mut data = data.to_vec();
135+
// Parse contract addr
136+
let contract_addr = parse_protobuf_string(&mut data, 1)?;
137+
138+
// Parse (optional) data
139+
let data = parse_protobuf_bytes(&mut data, 2)?;
140+
141+
Ok(MsgInstantiateContractResponse {
142+
contract_address: contract_addr,
143+
data,
144+
})
145+
}
146+
147+
pub fn parse_execute_response_data(
148+
data: &[u8],
149+
) -> Result<MsgExecuteContractResponse, ParseReplyError> {
150+
// Manual protobuf decoding
151+
let mut data = data.to_vec();
152+
let inner_data = parse_protobuf_bytes(&mut data, 1)?;
153+
154+
Ok(MsgExecuteContractResponse { data: inner_data })
155+
}
156+
157+
#[derive(Error, Debug, PartialEq, Eq)]
158+
pub enum ParseReplyError {
159+
#[error("Failure response from sub-message: {0}")]
160+
SubMsgFailure(String),
161+
162+
#[error("Invalid reply from sub-message: {0}")]
163+
ParseFailure(String),
164+
165+
#[error("Error occurred while converting from UTF-8")]
166+
BrokenUtf8(#[from] std::string::FromUtf8Error),
167+
}

0 commit comments

Comments
 (0)