@agoric/cosmos 0.34.2-orchestration-dev-096c4e8.0 → 0.34.2-other-dev-3eb1a1d.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/MAINTAINERS.md +3 -0
  2. package/Makefile +38 -34
  3. package/ante/ante.go +1 -4
  4. package/ante/inbound_test.go +2 -2
  5. package/app/app.go +198 -137
  6. package/app/upgrade.go +248 -0
  7. package/cmd/agd/agvm.go +3 -3
  8. package/cmd/agd/find_binary.go +2 -2
  9. package/cmd/agd/main.go +9 -10
  10. package/cmd/libdaemon/main.go +13 -13
  11. package/daemon/cmd/root.go +235 -92
  12. package/daemon/cmd/root_test.go +189 -1
  13. package/daemon/main.go +3 -2
  14. package/git-revision.txt +1 -1
  15. package/go.mod +14 -11
  16. package/go.sum +20 -19
  17. package/index.cjs +1 -1
  18. package/package.json +4 -3
  19. package/proto/agoric/swingset/genesis.proto +4 -0
  20. package/proto/agoric/swingset/swingset.proto +26 -1
  21. package/proto/agoric/vbank/vbank.proto +7 -0
  22. package/proto/agoric/vtransfer/genesis.proto +18 -0
  23. package/scripts/protocgen.sh +7 -8
  24. package/types/kv_entry_helpers.go +42 -0
  25. package/upgradegaia.sh +8 -8
  26. package/util/util.go +21 -0
  27. package/vm/action.go +1 -1
  28. package/vm/client.go +15 -13
  29. package/vm/client_test.go +34 -36
  30. package/vm/controller.go +3 -38
  31. package/vm/core_proposals.go +22 -2
  32. package/vm/proto_json.go +38 -0
  33. package/vm/proto_json_test.go +103 -0
  34. package/vm/server.go +106 -5
  35. package/x/swingset/alias.go +2 -0
  36. package/x/swingset/config.go +234 -0
  37. package/x/swingset/genesis.go +178 -40
  38. package/x/swingset/keeper/extension_snapshotter.go +2 -2
  39. package/x/swingset/keeper/keeper.go +24 -27
  40. package/x/swingset/keeper/swing_store_exports_handler.go +14 -3
  41. package/x/swingset/keeper/test_utils.go +16 -0
  42. package/x/swingset/module.go +24 -9
  43. package/x/swingset/testing/queue.go +17 -0
  44. package/x/swingset/types/default-params.go +31 -5
  45. package/x/swingset/types/expected_keepers.go +2 -2
  46. package/x/swingset/types/genesis.pb.go +78 -25
  47. package/x/swingset/types/msgs.go +53 -12
  48. package/x/swingset/types/params.go +53 -43
  49. package/x/swingset/types/params_test.go +75 -9
  50. package/x/swingset/types/swingset.pb.go +387 -57
  51. package/x/vbank/README.md +6 -1
  52. package/x/vbank/genesis.go +0 -2
  53. package/x/vbank/keeper/keeper.go +4 -9
  54. package/x/vbank/keeper/migrations.go +30 -0
  55. package/x/vbank/module.go +8 -7
  56. package/x/vbank/types/key.go +3 -3
  57. package/x/vbank/types/msgs.go +0 -12
  58. package/x/vbank/types/params.go +43 -2
  59. package/x/vbank/types/vbank.pb.go +105 -36
  60. package/x/vbank/vbank.go +8 -13
  61. package/x/vbank/vbank_test.go +14 -9
  62. package/x/vibc/alias.go +1 -1
  63. package/x/vibc/module.go +2 -7
  64. package/x/vibc/types/ibc_module.go +9 -3
  65. package/x/vibc/types/receiver.go +17 -7
  66. package/x/vlocalchain/handler.go +2 -1
  67. package/x/vlocalchain/keeper/keeper.go +24 -8
  68. package/x/vlocalchain/keeper/keeper_test.go +65 -1
  69. package/x/vlocalchain/types/expected_keepers.go +12 -0
  70. package/x/vlocalchain/vlocalchain.go +27 -22
  71. package/x/vlocalchain/vlocalchain_test.go +163 -8
  72. package/x/vstorage/keeper/grpc_query.go +0 -1
  73. package/x/vstorage/keeper/keeper.go +9 -17
  74. package/x/vstorage/module.go +0 -5
  75. package/x/vstorage/testing/queue.go +28 -0
  76. package/x/vtransfer/alias.go +13 -0
  77. package/x/vtransfer/genesis.go +39 -0
  78. package/x/vtransfer/genesis_test.go +12 -0
  79. package/x/vtransfer/handler.go +20 -0
  80. package/x/vtransfer/ibc_middleware.go +186 -0
  81. package/x/vtransfer/ibc_middleware_test.go +449 -0
  82. package/x/vtransfer/keeper/keeper.go +282 -0
  83. package/x/vtransfer/module.go +124 -0
  84. package/x/vtransfer/types/baseaddr.go +156 -0
  85. package/x/vtransfer/types/baseaddr_test.go +167 -0
  86. package/x/vtransfer/types/expected_keepers.go +38 -0
  87. package/x/vtransfer/types/genesis.pb.go +328 -0
  88. package/x/vtransfer/types/key.go +9 -0
  89. package/x/vtransfer/types/msgs.go +9 -0
  90. package/ante/fee.go +0 -97
@@ -0,0 +1,282 @@
1
+ package keeper
2
+
3
+ import (
4
+ "context"
5
+ "encoding/json"
6
+
7
+ "github.com/cosmos/cosmos-sdk/codec"
8
+ "github.com/cosmos/cosmos-sdk/store/prefix"
9
+ storetypes "github.com/cosmos/cosmos-sdk/store/types"
10
+ sdk "github.com/cosmos/cosmos-sdk/types"
11
+ sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
12
+
13
+ capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper"
14
+ capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
15
+
16
+ "github.com/Agoric/agoric-sdk/golang/cosmos/vm"
17
+ "github.com/Agoric/agoric-sdk/golang/cosmos/x/vibc"
18
+ vibctypes "github.com/Agoric/agoric-sdk/golang/cosmos/x/vibc/types"
19
+ "github.com/Agoric/agoric-sdk/golang/cosmos/x/vtransfer/types"
20
+ channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types"
21
+ porttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types"
22
+ host "github.com/cosmos/ibc-go/v6/modules/core/24-host"
23
+ ibcexported "github.com/cosmos/ibc-go/v6/modules/core/exported"
24
+ )
25
+
26
+ var _ porttypes.ICS4Wrapper = (*Keeper)(nil)
27
+ var _ vibctypes.ReceiverImpl = (*Keeper)(nil)
28
+ var _ vm.PortHandler = (*Keeper)(nil)
29
+
30
+ // "watched addresses" is logically a set and physically a collection of
31
+ // KVStore entries in which each key is a concatenation of a fixed prefix and
32
+ // the address, and its corresponding value is a non-empty but otherwise irrelevant
33
+ // sentinel.
34
+ const (
35
+ watchedAddressStoreKeyPrefix = "watchedAddress/"
36
+ watchedAddressSentinel = "y"
37
+ )
38
+
39
+ // Keeper handles the interceptions from the vtransfer IBC middleware, passing
40
+ // them to the embedded vibc keeper if they involve a targeted address (which is
41
+ // an address associated with a VM listener). The embedded vibc keeper is used
42
+ // to bridge calls to swingset, but with a special wrapper on the bridge
43
+ // controller to use distinct action types. The keeper keeps a store of
44
+ // "targeted addresses", managed from Swingset by bridge messages.
45
+ type Keeper struct {
46
+ porttypes.ICS4Wrapper
47
+ vibctypes.ReceiverImpl
48
+
49
+ vibcKeeper vibc.Keeper
50
+
51
+ key storetypes.StoreKey
52
+ cdc codec.Codec
53
+
54
+ vibcModule porttypes.IBCModule
55
+ }
56
+
57
+ // NewKeeper creates a new vtransfer Keeper instance
58
+ func NewKeeper(
59
+ cdc codec.Codec,
60
+ key storetypes.StoreKey,
61
+ prototypeVibcKeeper vibc.Keeper,
62
+ scopedTransferKeeper capabilitykeeper.ScopedKeeper,
63
+ pushAction vm.ActionPusher,
64
+ ) Keeper {
65
+ wrappedPushAction := wrapActionPusher(pushAction)
66
+
67
+ // This vibcKeeper is used to send notifications from the vtransfer middleware
68
+ // to the VM.
69
+ vibcKeeper := prototypeVibcKeeper.WithScope(nil, scopedTransferKeeper, wrappedPushAction)
70
+ return Keeper{
71
+ ICS4Wrapper: vibcKeeper,
72
+ ReceiverImpl: vibcKeeper,
73
+
74
+ vibcKeeper: vibcKeeper,
75
+ key: key,
76
+ vibcModule: vibc.NewIBCModule(vibcKeeper),
77
+ cdc: cdc,
78
+ }
79
+ }
80
+
81
+ // wrapActionPusher wraps an ActionPusher to prefix the action type with
82
+ // "VTRANSFER_".
83
+ func wrapActionPusher(pusher vm.ActionPusher) vm.ActionPusher {
84
+ return func(ctx sdk.Context, action vm.Action) error {
85
+ action = vm.PopulateAction(ctx, action)
86
+
87
+ // Prefix the action type.
88
+ ah := action.GetActionHeader()
89
+ ah.Type = "VTRANSFER_" + ah.Type
90
+
91
+ // fmt.Println("@@@ vtransfer action", action)
92
+ return pusher(ctx, action)
93
+ }
94
+ }
95
+
96
+ func (k Keeper) GetICS4Wrapper() porttypes.ICS4Wrapper {
97
+ return k
98
+ }
99
+
100
+ func (k Keeper) GetReceiverImpl() vibctypes.ReceiverImpl {
101
+ return k
102
+ }
103
+
104
+ // InterceptOnRecvPacket runs the ibcModule and eventually acknowledges a packet.
105
+ // Many error acknowledgments are sent synchronously, but most cases instead return nil
106
+ // to tell the IBC system that acknowledgment is async (i.e., that WriteAcknowledgement
107
+ // will be called later, after the VM has dealt with the packet).
108
+ func (k Keeper) InterceptOnRecvPacket(ctx sdk.Context, ibcModule porttypes.IBCModule, packet channeltypes.Packet, relayer sdk.AccAddress) ibcexported.Acknowledgement {
109
+ // Pass every (stripped-receiver) inbound packet to the wrapped IBC module.
110
+ var strippedPacket channeltypes.Packet
111
+ _, err := types.ExtractBaseAddressFromPacket(k.cdc, packet, types.RoleReceiver, &strippedPacket)
112
+ if err != nil {
113
+ return channeltypes.NewErrorAcknowledgement(err)
114
+ }
115
+ ack := ibcModule.OnRecvPacket(ctx, strippedPacket, relayer)
116
+
117
+ if ack == nil {
118
+ // Already declared to be an async ack.
119
+ return nil
120
+ }
121
+ portID := packet.GetDestPort()
122
+ channelID := packet.GetDestChannel()
123
+ capName := host.ChannelCapabilityPath(portID, channelID)
124
+ chanCap, ok := k.vibcKeeper.GetCapability(ctx, capName)
125
+ if !ok {
126
+ err := sdkerrors.Wrapf(channeltypes.ErrChannelCapabilityNotFound, "could not retrieve channel capability at: %s", capName)
127
+ return channeltypes.NewErrorAcknowledgement(err)
128
+ }
129
+ // Give the VM a chance to write (or override) the ack.
130
+ if err := k.InterceptWriteAcknowledgement(ctx, chanCap, packet, ack); err != nil {
131
+ return channeltypes.NewErrorAcknowledgement(err)
132
+ }
133
+ return nil
134
+ }
135
+
136
+ // InterceptOnAcknowledgementPacket checks to see if the packet sender is a
137
+ // targeted account, and if so, delegates to the VM.
138
+ func (k Keeper) InterceptOnAcknowledgementPacket(
139
+ ctx sdk.Context,
140
+ ibcModule porttypes.IBCModule,
141
+ packet channeltypes.Packet,
142
+ acknowledgement []byte,
143
+ relayer sdk.AccAddress,
144
+ ) error {
145
+ // Pass every (stripped-sender) acknowledgement to the wrapped IBC module.
146
+ var strippedPacket channeltypes.Packet
147
+ baseSender, err := types.ExtractBaseAddressFromPacket(k.cdc, packet, types.RoleSender, &strippedPacket)
148
+ if err != nil {
149
+ return err
150
+ }
151
+ modErr := ibcModule.OnAcknowledgementPacket(ctx, strippedPacket, acknowledgement, relayer)
152
+
153
+ // If the sender is not a watched account, we're done.
154
+ if !k.targetIsWatched(ctx, baseSender) {
155
+ return modErr
156
+ }
157
+
158
+ // Trigger VM with the original packet, regardless of errors in the ibcModule.
159
+ vmErr := k.vibcKeeper.TriggerOnAcknowledgementPacket(ctx, baseSender, packet, acknowledgement, relayer)
160
+
161
+ // Any error from the VM is trumped by one from the wrapped IBC module.
162
+ if modErr != nil {
163
+ return modErr
164
+ }
165
+ return vmErr
166
+ }
167
+
168
+ // InterceptOnTimeoutPacket checks to see if the packet sender is a targeted
169
+ // account, and if so, delegates to the VM.
170
+ func (k Keeper) InterceptOnTimeoutPacket(
171
+ ctx sdk.Context,
172
+ ibcModule porttypes.IBCModule,
173
+ packet channeltypes.Packet,
174
+ relayer sdk.AccAddress,
175
+ ) error {
176
+ // Pass every (stripped-sender) timeout to the wrapped IBC module.
177
+ var strippedPacket channeltypes.Packet
178
+ baseSender, err := types.ExtractBaseAddressFromPacket(k.cdc, packet, types.RoleSender, &strippedPacket)
179
+ if err != nil {
180
+ return err
181
+ }
182
+ modErr := ibcModule.OnTimeoutPacket(ctx, strippedPacket, relayer)
183
+
184
+ // If the sender is not a watched account, we're done.
185
+ if !k.targetIsWatched(ctx, baseSender) {
186
+ return modErr
187
+ }
188
+
189
+ // Trigger VM with the original packet, regardless of errors in the app.
190
+ vmErr := k.vibcKeeper.TriggerOnTimeoutPacket(ctx, baseSender, packet, relayer)
191
+
192
+ // Any error from the VM is trumped by one from the wrapped IBC module.
193
+ if modErr != nil {
194
+ return modErr
195
+ }
196
+ return vmErr
197
+ }
198
+
199
+ // InterceptWriteAcknowledgement checks to see if the packet's receiver is a
200
+ // targeted account, and if so, delegates to the VM.
201
+ func (k Keeper) InterceptWriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet ibcexported.PacketI, ack ibcexported.Acknowledgement) error {
202
+ // Get the base baseReceiver from the packet, without computing a stripped packet.
203
+ baseReceiver, err := types.ExtractBaseAddressFromPacket(k.cdc, packet, types.RoleReceiver, nil)
204
+ if err != nil || !k.targetIsWatched(ctx, baseReceiver) {
205
+ // We can't parse, or not watching, but that means just to ack directly.
206
+ return k.WriteAcknowledgement(ctx, chanCap, packet, ack)
207
+ }
208
+
209
+ // Trigger VM with the original packet.
210
+ if err = k.vibcKeeper.TriggerWriteAcknowledgement(ctx, baseReceiver, packet, ack); err != nil {
211
+ errAck := channeltypes.NewErrorAcknowledgement(err)
212
+ return k.WriteAcknowledgement(ctx, chanCap, packet, errAck)
213
+ }
214
+
215
+ return nil
216
+ }
217
+
218
+ // targetIsWatched checks if a target address has been watched by the VM.
219
+ func (k Keeper) targetIsWatched(ctx sdk.Context, target string) bool {
220
+ prefixStore := prefix.NewStore(
221
+ ctx.KVStore(k.key),
222
+ []byte(watchedAddressStoreKeyPrefix),
223
+ )
224
+ return prefixStore.Has([]byte(target))
225
+ }
226
+
227
+ // GetWatchedAdresses returns the watched addresses from the keeper as a slice
228
+ // of account addresses.
229
+ func (k Keeper) GetWatchedAddresses(ctx sdk.Context) ([]sdk.AccAddress, error) {
230
+ addresses := make([]sdk.AccAddress, 0)
231
+ prefixStore := prefix.NewStore(ctx.KVStore(k.key), []byte(watchedAddressStoreKeyPrefix))
232
+ iterator := sdk.KVStorePrefixIterator(prefixStore, []byte{})
233
+ defer iterator.Close()
234
+ for ; iterator.Valid(); iterator.Next() {
235
+ addr, err := sdk.AccAddressFromBech32(string(iterator.Key()))
236
+ if err != nil {
237
+ return nil, err
238
+ }
239
+ addresses = append(addresses, addr)
240
+ }
241
+ return addresses, nil
242
+ }
243
+
244
+ // SetWatchedAddresses sets the watched addresses in the keeper from a slice of
245
+ // SDK account addresses.
246
+ func (k Keeper) SetWatchedAddresses(ctx sdk.Context, addresses []sdk.AccAddress) {
247
+ prefixStore := prefix.NewStore(
248
+ ctx.KVStore(k.key),
249
+ []byte(watchedAddressStoreKeyPrefix),
250
+ )
251
+ for _, addr := range addresses {
252
+ prefixStore.Set([]byte(addr.String()), []byte(watchedAddressSentinel))
253
+ }
254
+ }
255
+
256
+ type registrationAction struct {
257
+ Type string `json:"type"` // BRIDGE_TARGET_REGISTER or BRIDGE_TARGET_UNREGISTER
258
+ Target string `json:"target"`
259
+ }
260
+
261
+ // Receive implements the vm.PortHandler interface.
262
+ func (k Keeper) Receive(cctx context.Context, jsonRequest string) (jsonReply string, err error) {
263
+ ctx := sdk.UnwrapSDKContext(cctx)
264
+ var msg registrationAction
265
+ if err := json.Unmarshal([]byte(jsonRequest), &msg); err != nil {
266
+ return "", err
267
+ }
268
+
269
+ prefixStore := prefix.NewStore(
270
+ ctx.KVStore(k.key),
271
+ []byte(watchedAddressStoreKeyPrefix),
272
+ )
273
+ switch msg.Type {
274
+ case "BRIDGE_TARGET_REGISTER":
275
+ prefixStore.Set([]byte(msg.Target), []byte(watchedAddressSentinel))
276
+ case "BRIDGE_TARGET_UNREGISTER":
277
+ prefixStore.Delete([]byte(msg.Target))
278
+ default:
279
+ return "", sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown action type: %s", msg.Type)
280
+ }
281
+ return "true", nil
282
+ }
@@ -0,0 +1,124 @@
1
+ package vtransfer
2
+
3
+ import (
4
+ "encoding/json"
5
+
6
+ "github.com/grpc-ecosystem/grpc-gateway/runtime"
7
+ "github.com/spf13/cobra"
8
+
9
+ "github.com/Agoric/agoric-sdk/golang/cosmos/x/vtransfer/types"
10
+ "github.com/cosmos/cosmos-sdk/client"
11
+ "github.com/cosmos/cosmos-sdk/codec"
12
+ cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
13
+ "github.com/cosmos/cosmos-sdk/types/module"
14
+
15
+ sdk "github.com/cosmos/cosmos-sdk/types"
16
+ abci "github.com/tendermint/tendermint/abci/types"
17
+ )
18
+
19
+ // type check to ensure the interface is properly implemented
20
+ var (
21
+ _ module.AppModule = AppModule{}
22
+ _ module.AppModuleBasic = AppModuleBasic{}
23
+ )
24
+
25
+ // app module Basics object
26
+ type AppModuleBasic struct {
27
+ }
28
+
29
+ func (AppModuleBasic) Name() string {
30
+ return ModuleName
31
+ }
32
+
33
+ func (AppModuleBasic) RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
34
+ }
35
+
36
+ // RegisterInterfaces registers the module's interface types
37
+ func (b AppModuleBasic) RegisterInterfaces(registry cdctypes.InterfaceRegistry) {
38
+ }
39
+
40
+ // DefaultGenesis returns default genesis state as raw bytes for the deployment
41
+ func (AppModuleBasic) DefaultGenesis(cdc codec.JSONCodec) json.RawMessage {
42
+ return cdc.MustMarshalJSON(DefaultGenesisState())
43
+ }
44
+
45
+ // Validation check of the Genesis
46
+ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config client.TxEncodingConfig, bz json.RawMessage) error {
47
+ var data types.GenesisState
48
+ err := cdc.UnmarshalJSON(bz, &data)
49
+ if err != nil {
50
+ return err
51
+ }
52
+ // Once json successfully marshalled, passes along to genesis.go
53
+ return ValidateGenesis(&data)
54
+ }
55
+
56
+ func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *runtime.ServeMux) {
57
+ }
58
+
59
+ // Get the root query command of this module
60
+ func (AppModuleBasic) GetQueryCmd() *cobra.Command {
61
+ return nil
62
+ }
63
+
64
+ // Get the root tx command of this module
65
+ func (AppModuleBasic) GetTxCmd() *cobra.Command {
66
+ return nil
67
+ }
68
+
69
+ type AppModule struct {
70
+ AppModuleBasic
71
+ keeper Keeper
72
+ }
73
+
74
+ // NewAppModule creates a new AppModule Object
75
+ func NewAppModule(k Keeper) AppModule {
76
+ am := AppModule{
77
+ AppModuleBasic: AppModuleBasic{},
78
+ keeper: k,
79
+ }
80
+ return am
81
+ }
82
+
83
+ func (AppModule) Name() string {
84
+ return ModuleName
85
+ }
86
+
87
+ func (am AppModule) RegisterInvariants(ir sdk.InvariantRegistry) {}
88
+
89
+ func (am AppModule) Route() sdk.Route {
90
+ return sdk.NewRoute(types.RouterKey, NewHandler(am.keeper))
91
+ }
92
+
93
+ func (am AppModule) QuerierRoute() string {
94
+ return ModuleName
95
+ }
96
+
97
+ // LegacyQuerierHandler returns the sdk.Querier for module
98
+ func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sdk.Querier {
99
+ return nil
100
+ }
101
+
102
+ func (am AppModule) RegisterServices(cfg module.Configurator) {
103
+ }
104
+
105
+ func (AppModule) ConsensusVersion() uint64 { return 1 }
106
+
107
+ func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) {
108
+ }
109
+
110
+ func (am AppModule) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) []abci.ValidatorUpdate {
111
+ // Prevent Cosmos SDK internal errors.
112
+ return []abci.ValidatorUpdate{}
113
+ }
114
+
115
+ func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONCodec, data json.RawMessage) []abci.ValidatorUpdate {
116
+ var genesisState types.GenesisState
117
+ cdc.MustUnmarshalJSON(data, &genesisState)
118
+ return InitGenesis(ctx, am.keeper, &genesisState)
119
+ }
120
+
121
+ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.RawMessage {
122
+ gs := ExportGenesis(ctx, am.keeper)
123
+ return cdc.MustMarshalJSON(gs)
124
+ }
@@ -0,0 +1,156 @@
1
+ package types
2
+
3
+ import (
4
+ "fmt"
5
+ "net/url"
6
+ "strings"
7
+
8
+ "github.com/cosmos/cosmos-sdk/codec"
9
+
10
+ transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types"
11
+ clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types"
12
+ channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types"
13
+ ibcexported "github.com/cosmos/ibc-go/v6/modules/core/exported"
14
+ )
15
+
16
+ type AddressRole string
17
+
18
+ const (
19
+ RoleSender AddressRole = "Sender"
20
+ RoleReceiver AddressRole = "Receiver"
21
+ )
22
+
23
+ func trimSlashPrefix(s string) string {
24
+ return strings.TrimPrefix(s, "/")
25
+ }
26
+
27
+ // ExtractBaseAddress extracts the base address from a parameterized address.
28
+ // It removes all subpath and query components from addr.
29
+ func ExtractBaseAddress(addr string) (string, error) {
30
+ parsed, err := url.Parse(addr)
31
+ if err != nil {
32
+ return "", err
33
+ }
34
+
35
+ // Specify the fields and values we expect. Unspecified fields will only
36
+ // match if they are zero values in order to be robust against extensions to
37
+ // the url.URL struct.
38
+ //
39
+ // Remove leading slashes from the path fields so that only parsed relative
40
+ // paths match the expected test.
41
+ expected := url.URL{
42
+ Path: trimSlashPrefix(parsed.Path),
43
+ RawPath: trimSlashPrefix(parsed.RawPath),
44
+ RawQuery: parsed.RawQuery,
45
+ Fragment: parsed.Fragment,
46
+ RawFragment: parsed.RawFragment,
47
+
48
+ // Skip over parsing control flags.
49
+ ForceQuery: parsed.ForceQuery,
50
+ OmitHost: parsed.OmitHost,
51
+ }
52
+
53
+ if *parsed != expected {
54
+ return "", fmt.Errorf("address must be relative path with optional query and fragment, got %s", addr)
55
+ }
56
+
57
+ baseAddr, _, _ := strings.Cut(expected.Path, "/")
58
+ if baseAddr == "" {
59
+ return "", fmt.Errorf("base address cannot be empty")
60
+ }
61
+
62
+ return baseAddr, nil
63
+ }
64
+
65
+ // extractBaseTransferData returns the base address from the transferData.Sender
66
+ // (if RoleSender) or transferData.Receiver (if RoleReceiver). Errors in
67
+ // determining the base address are ignored... we then assume the base address
68
+ // is exactly the original address. If newTransferData is not nil, it will be
69
+ // populated with a new FungibleTokenPacketData consisting of the role replaced
70
+ // with its base address.
71
+ func extractBaseTransferData(transferData transfertypes.FungibleTokenPacketData, role AddressRole, newTransferData *transfertypes.FungibleTokenPacketData) (string, error) {
72
+ var target string
73
+ sender := transferData.Sender
74
+ receiver := transferData.Receiver
75
+
76
+ switch role {
77
+ case RoleSender:
78
+ baseSender, err := ExtractBaseAddress(sender)
79
+ if err == nil {
80
+ sender = baseSender
81
+ }
82
+ target = sender
83
+
84
+ case RoleReceiver:
85
+ baseReceiver, err := ExtractBaseAddress(receiver)
86
+ if err == nil {
87
+ receiver = baseReceiver
88
+ }
89
+ target = receiver
90
+
91
+ default:
92
+ err := fmt.Errorf("invalid address role: %s", role)
93
+ return target, err
94
+ }
95
+
96
+ if newTransferData == nil {
97
+ return target, nil
98
+ }
99
+
100
+ // Create the new transfer data.
101
+ *newTransferData = transfertypes.NewFungibleTokenPacketData(
102
+ transferData.Denom,
103
+ transferData.Amount,
104
+ sender, receiver,
105
+ transferData.Memo,
106
+ )
107
+
108
+ return target, nil
109
+ }
110
+
111
+ // ExtractBaseAddressFromPacket returns the base address from a transfer
112
+ // packet's data, either Sender (if role is RoleSender) or Receiver (if role is
113
+ // RoleReceiver).
114
+ // Errors in determining the base address are ignored... we then assume the base
115
+ // address is exactly the original address.
116
+ // If newPacket is not nil, it is populated with a new transfer packet whose
117
+ // corresponding Sender or Receiver is replaced with the extracted base address.
118
+ func ExtractBaseAddressFromPacket(cdc codec.Codec, packet ibcexported.PacketI, role AddressRole, newPacket *channeltypes.Packet) (string, error) {
119
+ transferData := transfertypes.FungibleTokenPacketData{}
120
+ if err := cdc.UnmarshalJSON(packet.GetData(), &transferData); err != nil {
121
+ return "", err
122
+ }
123
+
124
+ var newTransferData *transfertypes.FungibleTokenPacketData
125
+ if newPacket != nil {
126
+ // Capture the transfer data for the new packet.
127
+ newTransferData = &transfertypes.FungibleTokenPacketData{}
128
+ }
129
+ target, err := extractBaseTransferData(transferData, role, newTransferData)
130
+ if err != nil {
131
+ return target, err
132
+ }
133
+
134
+ if newPacket == nil {
135
+ return target, nil
136
+ }
137
+
138
+ // Create a new packet with the new transfer packet data.
139
+ // Re-serialize the packet data with the base addresses.
140
+ newData, err := cdc.MarshalJSON(newTransferData)
141
+ if err != nil {
142
+ return target, err
143
+ }
144
+
145
+ // Create the new packet.
146
+ th := packet.GetTimeoutHeight()
147
+ *newPacket = channeltypes.NewPacket(
148
+ newData, packet.GetSequence(),
149
+ packet.GetSourcePort(), packet.GetSourceChannel(),
150
+ packet.GetDestPort(), packet.GetDestChannel(),
151
+ clienttypes.NewHeight(th.GetRevisionNumber(), th.GetRevisionHeight()),
152
+ packet.GetTimeoutTimestamp(),
153
+ )
154
+
155
+ return target, nil
156
+ }