Skip to content

Commit 76b0807

Browse files
authored
feat(warp): allow authority to create native synthetic tokens (#135)
1 parent 7310d9d commit 76b0807

5 files changed

Lines changed: 436 additions & 80 deletions

File tree

proto/buf.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,5 @@ lint:
1717
- SERVICE_SUFFIX
1818
- PACKAGE_VERSION_SUFFIX
1919
- RPC_REQUEST_STANDARD_NAME
20+
- RPC_REQUEST_RESPONSE_UNIQUE
21+
- RPC_RESPONSE_STANDARD_NAME

proto/hyperlane/warp/v1/tx.proto

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ service Msg {
2121
// CreateSyntheticToken ...
2222
rpc CreateSyntheticToken(MsgCreateSyntheticToken)
2323
returns (MsgCreateSyntheticTokenResponse);
24+
// CreateNativeSyntheticToken ...
25+
rpc CreateNativeSyntheticToken(MsgCreateNativeSyntheticToken)
26+
returns (MsgCreateSyntheticTokenResponse);
2427

2528
// SetToken ...
2629
rpc SetToken(MsgSetToken) returns (MsgSetTokenResponse);
@@ -77,6 +80,22 @@ message MsgCreateSyntheticToken {
7780
];
7881
}
7982

83+
// MsgCreateNativeSyntheticToken ...
84+
message MsgCreateNativeSyntheticToken {
85+
option (cosmos.msg.v1.signer) = "owner";
86+
option (amino.name) = "hyperlane/warp/v1/MsgCreateNativeSyntheticToken";
87+
88+
string owner = 1 [ (cosmos_proto.scalar) = "cosmos.AddressString" ];
89+
90+
string origin_mailbox = 2 [
91+
(gogoproto.customtype) =
92+
"github.com/bcp-innovations/hyperlane-cosmos/util.HexAddress",
93+
(gogoproto.nullable) = false
94+
];
95+
96+
string origin_denom = 3;
97+
}
98+
8099
// MsgCreateSyntheticTokenResponse ...
81100
message MsgCreateSyntheticTokenResponse {
82101
string id = 1 [

x/warp/keeper/msg_server.go

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,29 +19,54 @@ type msgServer struct {
1919

2020
// CreateSyntheticToken ...
2121
func (ms msgServer) CreateSyntheticToken(ctx context.Context, msg *types.MsgCreateSyntheticToken) (*types.MsgCreateSyntheticTokenResponse, error) {
22+
return ms.internalCreateSyntheticToken(ctx, msg.Owner, msg.OriginMailbox, "")
23+
}
24+
25+
// CreateNativeSyntheticToken is an authority gated version of
26+
// CreateSyntheticToken that allows the module authority to specify a native
27+
// (custom) origin denom for the synthetic token.
28+
func (ms msgServer) CreateNativeSyntheticToken(ctx context.Context, msg *types.MsgCreateNativeSyntheticToken) (*types.MsgCreateSyntheticTokenResponse, error) {
29+
if msg.Owner != ms.k.authority {
30+
return nil, fmt.Errorf("invalid authority: expected %s, got %s", ms.k.authority, msg.Owner)
31+
}
32+
33+
if ms.k.bankKeeper.HasSupply(ctx, msg.OriginDenom) {
34+
return nil, fmt.Errorf("denom %s already exists", msg.OriginDenom)
35+
}
36+
37+
return ms.internalCreateSyntheticToken(ctx, msg.Owner, msg.OriginMailbox, msg.OriginDenom)
38+
}
39+
40+
// internalCreateSyntheticToken handles the internal logic for creating a synthetic token.
41+
func (ms msgServer) internalCreateSyntheticToken(ctx context.Context, owner string, originMailbox util.HexAddress, originDenom string) (*types.MsgCreateSyntheticTokenResponse, error) {
2242
if !slices.Contains(ms.k.enabledTokens, int32(types.HYP_TOKEN_TYPE_SYNTHETIC)) {
2343
return nil, fmt.Errorf("module disabled synthetic tokens")
2444
}
2545

26-
has, err := ms.k.coreKeeper.MailboxIdExists(ctx, msg.OriginMailbox)
46+
has, err := ms.k.coreKeeper.MailboxIdExists(ctx, originMailbox)
2747
if err != nil {
2848
return nil, err
2949
}
3050
if !has {
31-
return nil, fmt.Errorf("failed to find mailbox with id: %s", msg.OriginMailbox.String())
51+
return nil, fmt.Errorf("failed to find mailbox with id: %s", originMailbox.String())
3252
}
3353

3454
tokenId, err := ms.k.coreKeeper.AppRouter().GetNextSequence(ctx, uint8(types.HYP_TOKEN_TYPE_SYNTHETIC))
3555
if err != nil {
3656
return nil, err
3757
}
3858

59+
// If the originDenom is left empty, we populate it as a non-native denom.
60+
if originDenom == "" {
61+
originDenom = fmt.Sprintf("hyperlane/%s", tokenId.String())
62+
}
63+
3964
newToken := types.HypToken{
4065
Id: tokenId,
41-
Owner: msg.Owner,
66+
Owner: owner,
4267
TokenType: types.HYP_TOKEN_TYPE_SYNTHETIC,
43-
OriginMailbox: msg.OriginMailbox,
44-
OriginDenom: fmt.Sprintf("hyperlane/%s", tokenId.String()),
68+
OriginMailbox: originMailbox,
69+
OriginDenom: originDenom,
4570
}
4671

4772
if err = ms.k.HypTokens.Set(ctx, tokenId.GetInternalId(), newToken); err != nil {

x/warp/types/expected_keepers.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ type BankKeeper interface {
1414
BurnCoins(ctx context.Context, moduleName string, amt sdk.Coins) error
1515
MintCoins(ctx context.Context, moduleName string, amt sdk.Coins) error
1616
GetSupply(ctx context.Context, denom string) sdk.Coin
17+
HasSupply(ctx context.Context, denom string) bool
1718
}
1819

1920
type CoreKeeper interface {

0 commit comments

Comments
 (0)