Skip to content

Commit 8fe095f

Browse files
authored
Merge pull request #1943 from CosmWasm/go-gen-fixes
go-gen fixes
2 parents ddcd300 + f9d365c commit 8fe095f

File tree

7 files changed

+347
-18
lines changed

7 files changed

+347
-18
lines changed

packages/go-gen/src/main.rs

Lines changed: 96 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,22 @@ fn main() -> Result<()> {
2121

2222
/// Generates the Go code for the given schema
2323
fn generate_go(root: RootSchema) -> Result<String> {
24-
let title = replace_acronyms(
25-
root.schema
26-
.metadata
27-
.as_ref()
28-
.and_then(|m| m.title.as_ref())
29-
.context("failed to get type name")?,
30-
);
24+
let title = root
25+
.schema
26+
.metadata
27+
.as_ref()
28+
.and_then(|m| m.title.as_ref())
29+
.context("failed to get type name")?;
3130

3231
let mut types = vec![];
33-
build_type(&title, &root.schema, &mut types)
32+
build_type(title, &root.schema, &mut types)
3433
.with_context(|| format!("failed to generate {title}"))?;
3534

3635
// go through additional definitions
3736
for (name, additional_type) in &root.definitions {
3837
additional_type
3938
.object()
40-
.map(|def| build_type(&replace_acronyms(name), def, &mut types))
39+
.map(|def| build_type(name, def, &mut types))
4140
.and_then(|r| r)
4241
.context("failed to generate additional definitions")?;
4342
}
@@ -107,7 +106,7 @@ pub fn build_struct(
107106
let fields = fields.collect::<Result<Vec<_>>>()?;
108107

109108
Ok(GoStruct {
110-
name: to_pascal_case(name),
109+
name: replace_acronyms(to_pascal_case(name)),
111110
docs,
112111
fields,
113112
})
@@ -121,6 +120,7 @@ pub fn build_enum<'a>(
121120
variants: impl Iterator<Item = &'a Schema>,
122121
additional_structs: &mut Vec<GoStruct>,
123122
) -> Result<GoStruct> {
123+
let name = replace_acronyms(name);
124124
let docs = documentation(enm);
125125

126126
// go through all fields
@@ -131,18 +131,14 @@ pub fn build_enum<'a>(
131131
.with_context(|| format!("expected schema object for enum variants of {name}"))?;
132132

133133
// analyze the variant
134-
let variant_field = build_enum_variant(v, name, additional_structs)
134+
let variant_field = build_enum_variant(v, &name, additional_structs)
135135
.context("failed to extract enum variant")?;
136136

137137
anyhow::Ok(variant_field)
138138
});
139139
let fields = fields.collect::<Result<Vec<_>>>()?;
140140

141-
Ok(GoStruct {
142-
name: name.to_string(),
143-
docs,
144-
fields,
145-
})
141+
Ok(GoStruct { name, docs, fields })
146142
}
147143

148144
/// Tries to extract the name and type of the given enum variant and returns it as a `GoField`.
@@ -433,6 +429,16 @@ mod tests {
433429
compare_codes!(cosmwasm_std::WasmQuery);
434430
}
435431

432+
#[test]
433+
fn messages_work() {
434+
compare_codes!(cosmwasm_std::BankMsg);
435+
compare_codes!(cosmwasm_std::StakingMsg);
436+
compare_codes!(cosmwasm_std::DistributionMsg);
437+
compare_codes!(cosmwasm_std::IbcMsg);
438+
compare_codes!(cosmwasm_std::WasmMsg);
439+
// compare_codes!(cosmwasm_std::GovMsg); // TODO: currently fails because of VoteOption
440+
}
441+
436442
#[test]
437443
fn array_item_type_works() {
438444
#[cw_serde]
@@ -468,4 +474,78 @@ mod tests {
468474
}"#,
469475
);
470476
}
477+
478+
#[test]
479+
fn accronym_replacement_works() {
480+
#[cw_serde]
481+
struct IbcStruct {
482+
a: IbcSubStruct,
483+
b: IbcSubEnum,
484+
}
485+
#[cw_serde]
486+
enum IbcEnum {
487+
A(IbcSubStruct),
488+
B(IbcSubEnum),
489+
}
490+
#[cw_serde]
491+
struct IbcSubStruct {}
492+
#[cw_serde]
493+
enum IbcSubEnum {
494+
A(String),
495+
}
496+
497+
let code = generate_go(cosmwasm_schema::schema_for!(IbcStruct)).unwrap();
498+
assert_code_eq(
499+
code,
500+
r#"
501+
type IBCStruct struct {
502+
A IBCSubStruct `json:"a"`
503+
B IBCSubEnum `json:"b"`
504+
}
505+
type IBCSubEnum struct {
506+
A string `json:"a,omitempty"`
507+
}
508+
type IBCSubStruct struct {
509+
}
510+
"#,
511+
);
512+
513+
let code = generate_go(cosmwasm_schema::schema_for!(IbcEnum)).unwrap();
514+
assert_code_eq(
515+
code,
516+
r#"
517+
type IBCEnum struct {
518+
A *IBCSubStruct `json:"a,omitempty"`
519+
B *IBCSubEnum `json:"b,omitempty"`
520+
}
521+
type IBCSubEnum struct {
522+
A string `json:"a,omitempty"`
523+
}
524+
type IBCSubStruct struct {
525+
}
526+
"#,
527+
);
528+
}
529+
530+
#[test]
531+
fn timestamp_works() {
532+
use cosmwasm_std::Timestamp;
533+
534+
#[cw_serde]
535+
struct A {
536+
a: Timestamp,
537+
b: Option<Timestamp>,
538+
}
539+
540+
let code = generate_go(cosmwasm_schema::schema_for!(A)).unwrap();
541+
assert_code_eq(
542+
code,
543+
r#"
544+
type A struct {
545+
A Uint64 `json:"a"`
546+
B *Uint64 `json:"b,omitempty"`
547+
}
548+
"#,
549+
);
550+
}
471551
}

packages/go-gen/src/schema.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,12 @@ pub fn schema_object_type(
4343
replace_custom_type(title)
4444
} else if let Some(reference) = &schema.reference {
4545
// if it has a reference, strip the path and use that
46-
replace_custom_type(
46+
replace_custom_type(&replace_acronyms(
4747
reference
4848
.split('/')
4949
.last()
5050
.expect("split should always return at least one item"),
51-
)
51+
))
5252
} else if let Some(t) = &schema.instance_type {
5353
type_from_instance_type(schema, type_context, t, additional_structs)?
5454
} else if let Some(subschemas) = schema.subschemas.as_ref().and_then(|s| s.any_of.as_ref()) {
@@ -259,13 +259,19 @@ pub fn documentation(schema: &SchemaObject) -> Option<String> {
259259
/// If the given type is not a special type, returns `None`.
260260
pub fn custom_type_of(ty: &str) -> Option<&str> {
261261
match ty {
262+
"Uint64" => Some("Uint64"),
262263
"Uint128" => Some("string"),
264+
"Int64" => Some("Int64"),
265+
"Int128" => Some("string"),
263266
"Binary" => Some("[]byte"),
264267
"HexBinary" => Some("string"),
265268
"Checksum" => Some("Checksum"),
266269
"Addr" => Some("string"),
267270
"Decimal" => Some("string"),
268271
"Decimal256" => Some("string"),
272+
"SignedDecimal" => Some("string"),
273+
"SignedDecimal256" => Some("string"),
274+
"Timestamp" => Some("Uint64"),
269275
_ => None,
270276
}
271277
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// SendMsg contains instructions for a Cosmos-SDK/SendMsg
2+
// It has a fixed interface here and should be converted into the proper SDK format before dispatching
3+
type SendMsg struct {
4+
Amount []Coin `json:"amount"`
5+
ToAddress string `json:"to_address"`
6+
}
7+
8+
// BurnMsg will burn the given coins from the contract's account.
9+
// There is no Cosmos SDK message that performs this, but it can be done by calling the bank keeper.
10+
// Important if a contract controls significant token supply that must be retired.
11+
type BurnMsg struct {
12+
Amount []Coin `json:"amount"`
13+
}
14+
15+
type BankMsg struct {
16+
Send *SendMsg `json:"send,omitempty"`
17+
Burn *BurnMsg `json:"burn,omitempty"`
18+
}
19+
20+
// Coin is a string representation of the sdk.Coin type (more portable than sdk.Int)
21+
type Coin struct {
22+
Amount string `json:"amount"` // string encoing of decimal value, eg. "12.3456"
23+
Denom string `json:"denom"` // type, eg. "ATOM"
24+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// SetWithdrawAddressMsg is translated to a [MsgSetWithdrawAddress](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L29-L37).
2+
// `delegator_address` is automatically filled with the current contract's address.
3+
type SetWithdrawAddressMsg struct {
4+
// Address contains the `delegator_address` of a MsgSetWithdrawAddress
5+
Address string `json:"address"`
6+
}
7+
8+
// WithdrawDelegatorRewardMsg is translated to a [MsgWithdrawDelegatorReward](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#L42-L50).
9+
// `delegator_address` is automatically filled with the current contract's address.
10+
type WithdrawDelegatorRewardMsg struct {
11+
// Validator contains `validator_address` of a MsgWithdrawDelegatorReward
12+
Validator string `json:"validator"`
13+
}
14+
15+
// FundCommunityPoolMsg is translated to a [MsgFundCommunityPool](https://github.com/cosmos/cosmos-sdk/blob/v0.42.4/proto/cosmos/distribution/v1beta1/tx.proto#LL69C1-L76C2).
16+
// `depositor` is automatically filled with the current contract's address
17+
type FundCommunityPoolMsg struct {
18+
// Amount is the list of coins to be send to the community pool
19+
Amount []Coin `json:"amount"`
20+
}
21+
22+
type DistributionMsg struct {
23+
SetWithdrawAddress *SetWithdrawAddressMsg `json:"set_withdraw_address,omitempty"`
24+
WithdrawDelegatorReward *WithdrawDelegatorRewardMsg `json:"withdraw_delegator_reward,omitempty"`
25+
FundCommunityPool *FundCommunityPoolMsg `json:"fund_community_pool,omitempty"`
26+
}
27+
28+
// Coin is a string representation of the sdk.Coin type (more portable than sdk.Int)
29+
type Coin struct {
30+
Amount string `json:"amount"` // string encoing of decimal value, eg. "12.3456"
31+
Denom string `json:"denom"` // type, eg. "ATOM"
32+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
type TransferMsg struct {
2+
Amount Coin `json:"amount"`
3+
ChannelID string `json:"channel_id"`
4+
Memo string `json:"memo,omitempty"` // this is not yet in wasmvm, but will be soon
5+
Timeout IBCTimeout `json:"timeout"`
6+
ToAddress string `json:"to_address"`
7+
}
8+
type SendPacketMsg struct {
9+
ChannelID string `json:"channel_id"`
10+
Data []byte `json:"data"`
11+
Timeout IBCTimeout `json:"timeout"`
12+
}
13+
type CloseChannelMsg struct {
14+
ChannelID string `json:"channel_id"`
15+
}
16+
17+
type IBCMsg struct {
18+
Transfer *TransferMsg `json:"transfer,omitempty"`
19+
SendPacket *SendPacketMsg `json:"send_packet,omitempty"`
20+
CloseChannel *CloseChannelMsg `json:"close_channel,omitempty"`
21+
}
22+
23+
// Coin is a string representation of the sdk.Coin type (more portable than sdk.Int)
24+
type Coin struct {
25+
Amount string `json:"amount"` // string encoing of decimal value, eg. "12.3456"
26+
Denom string `json:"denom"` // type, eg. "ATOM"
27+
}
28+
29+
// IBCTimeout is the timeout for an IBC packet. At least one of block and timestamp is required.
30+
type IBCTimeout struct {
31+
Block *IBCTimeoutBlock `json:"block,omitempty"` // in wasmvm, this does not have "omitempty"
32+
// Nanoseconds since UNIX epoch
33+
Timestamp *Uint64 `json:"timestamp,omitempty"`
34+
}
35+
36+
// IBCTimeoutBlock Height is a monotonically increasing data type
37+
// that can be compared against another Height for the purposes of updating and
38+
// freezing clients.
39+
// Ordering is (revision_number, timeout_height)
40+
type IBCTimeoutBlock struct {
41+
// block height after which the packet times out.
42+
// the height within the given revision
43+
Height uint64 `json:"height"`
44+
// the version that the client is currently on
45+
// (eg. after reseting the chain this could increment 1 as height drops to 0)
46+
Revision uint64 `json:"revision"`
47+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
type DelegateMsg struct {
2+
Amount Coin `json:"amount"`
3+
Validator string `json:"validator"`
4+
}
5+
type UndelegateMsg struct {
6+
Amount Coin `json:"amount"`
7+
Validator string `json:"validator"`
8+
}
9+
type RedelegateMsg struct {
10+
Amount Coin `json:"amount"`
11+
DstValidator string `json:"dst_validator"`
12+
SrcValidator string `json:"src_validator"`
13+
}
14+
15+
type StakingMsg struct {
16+
Delegate *DelegateMsg `json:"delegate,omitempty"`
17+
Undelegate *UndelegateMsg `json:"undelegate,omitempty"`
18+
Redelegate *RedelegateMsg `json:"redelegate,omitempty"`
19+
}
20+
21+
// Coin is a string representation of the sdk.Coin type (more portable than sdk.Int)
22+
type Coin struct {
23+
Amount string `json:"amount"` // string encoing of decimal value, eg. "12.3456"
24+
Denom string `json:"denom"` // type, eg. "ATOM"
25+
}

0 commit comments

Comments
 (0)