@agoric/cosmos 0.34.2-dev-0b5aab8.0 → 0.34.2-dev-bd0b2a9.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.
package/git-revision.txt CHANGED
@@ -1 +1 @@
1
- 0b5aab8
1
+ bd0b2a9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agoric/cosmos",
3
- "version": "0.34.2-dev-0b5aab8.0+0b5aab8",
3
+ "version": "0.34.2-dev-bd0b2a9.0+bd0b2a9",
4
4
  "description": "Connect JS to the Cosmos blockchain SDK",
5
5
  "parsers": {
6
6
  "js": "mjs"
@@ -39,5 +39,5 @@
39
39
  "typeCoverage": {
40
40
  "atLeast": 0
41
41
  },
42
- "gitHead": "0b5aab88c4a921ea18ff123afc8a7aa12cb2ec1e"
42
+ "gitHead": "bd0b2a9f67af973d5bd789894e723251b83a8dff"
43
43
  }
@@ -331,18 +331,19 @@ func (s *IntegrationTestSuite) TestTransferFromAgdToAgd() {
331
331
 
332
332
  s.Run("TransferFromAgdToAgd", func() {
333
333
  // create a transfer packet's data contents
334
+ baseReceiver := s.chainB.SenderAccounts[1].SenderAccount.GetAddress().String()
334
335
  transferData := ibctransfertypes.NewFungibleTokenPacketData(
335
336
  "uosmo",
336
337
  "1000000",
337
338
  s.chainA.SenderAccount.GetAddress().String(),
338
- s.chainB.SenderAccounts[1].SenderAccount.GetAddress().String(),
339
+ baseReceiver+"?what=arbitrary-data&why=to-test-bridge-targets",
339
340
  `"This is a JSON memo"`,
340
341
  )
341
342
 
342
343
  // Register the sender and receiver as bridge targets on their specific
343
344
  // chain.
344
345
  s.RegisterBridgeTarget(s.chainA, transferData.Sender)
345
- s.RegisterBridgeTarget(s.chainB, transferData.Receiver)
346
+ s.RegisterBridgeTarget(s.chainB, baseReceiver)
346
347
 
347
348
  s.mintToAddress(s.chainA, s.chainA.SenderAccount.GetAddress(), transferData.Denom, transferData.Amount)
348
349
 
@@ -384,7 +385,7 @@ func (s *IntegrationTestSuite) TestTransferFromAgdToAgd() {
384
385
  BlockTime: writeAcknowledgementTime,
385
386
  },
386
387
  Event: "writeAcknowledgement",
387
- Target: transferData.Receiver,
388
+ Target: baseReceiver,
388
389
  Packet: packet,
389
390
  Acknowledgement: ack.Acknowledgement(),
390
391
  },
@@ -16,7 +16,7 @@ import (
16
16
  "github.com/Agoric/agoric-sdk/golang/cosmos/vm"
17
17
  "github.com/Agoric/agoric-sdk/golang/cosmos/x/vibc"
18
18
  vibctypes "github.com/Agoric/agoric-sdk/golang/cosmos/x/vibc/types"
19
- transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types"
19
+ "github.com/Agoric/agoric-sdk/golang/cosmos/x/vtransfer/types"
20
20
  channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types"
21
21
  porttypes "github.com/cosmos/ibc-go/v6/modules/core/05-port/types"
22
22
  host "github.com/cosmos/ibc-go/v6/modules/core/24-host"
@@ -106,7 +106,13 @@ func (k Keeper) GetReceiverImpl() vibctypes.ReceiverImpl {
106
106
  // to tell the IBC system that acknowledgment is async (i.e., that WriteAcknowledgement
107
107
  // will be called later, after the VM has dealt with the packet).
108
108
  func (k Keeper) InterceptOnRecvPacket(ctx sdk.Context, ibcModule porttypes.IBCModule, packet channeltypes.Packet, relayer sdk.AccAddress) ibcexported.Acknowledgement {
109
- ack := ibcModule.OnRecvPacket(ctx, packet, relayer)
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)
110
116
 
111
117
  if ack == nil {
112
118
  // Already declared to be an async ack.
@@ -136,17 +142,21 @@ func (k Keeper) InterceptOnAcknowledgementPacket(
136
142
  acknowledgement []byte,
137
143
  relayer sdk.AccAddress,
138
144
  ) error {
139
- // Pass every acknowledgement to the wrapped IBC module.
140
- modErr := ibcModule.OnAcknowledgementPacket(ctx, packet, acknowledgement, relayer)
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)
141
152
 
142
- // If the sender is not a targeted account, we're done.
143
- sender, _, err := k.parseTransfer(ctx, packet)
144
- if err != nil || sender == "" {
153
+ // If the sender is not a watched account, we're done.
154
+ if !k.targetIsWatched(ctx, baseSender) {
145
155
  return modErr
146
156
  }
147
157
 
148
- // Trigger VM, regardless of errors in the ibcModule.
149
- vmErr := k.vibcKeeper.TriggerOnAcknowledgementPacket(ctx, sender, packet, acknowledgement, relayer)
158
+ // Trigger VM with the original packet, regardless of errors in the ibcModule.
159
+ vmErr := k.vibcKeeper.TriggerOnAcknowledgementPacket(ctx, baseSender, packet, acknowledgement, relayer)
150
160
 
151
161
  // Any error from the VM is trumped by one from the wrapped IBC module.
152
162
  if modErr != nil {
@@ -163,17 +173,21 @@ func (k Keeper) InterceptOnTimeoutPacket(
163
173
  packet channeltypes.Packet,
164
174
  relayer sdk.AccAddress,
165
175
  ) error {
166
- // Pass every timeout to the wrapped IBC module.
167
- modErr := ibcModule.OnTimeoutPacket(ctx, packet, relayer)
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)
168
183
 
169
- // If the sender is not a targeted account, we're done.
170
- sender, _, err := k.parseTransfer(ctx, packet)
171
- if err != nil || sender == "" {
184
+ // If the sender is not a watched account, we're done.
185
+ if !k.targetIsWatched(ctx, baseSender) {
172
186
  return modErr
173
187
  }
174
188
 
175
- // Trigger VM, regardless of errors in the app.
176
- vmErr := k.vibcKeeper.TriggerOnTimeoutPacket(ctx, sender, packet, relayer)
189
+ // Trigger VM with the original packet, regardless of errors in the app.
190
+ vmErr := k.vibcKeeper.TriggerOnTimeoutPacket(ctx, baseSender, packet, relayer)
177
191
 
178
192
  // Any error from the VM is trumped by one from the wrapped IBC module.
179
193
  if modErr != nil {
@@ -185,14 +199,15 @@ func (k Keeper) InterceptOnTimeoutPacket(
185
199
  // InterceptWriteAcknowledgement checks to see if the packet's receiver is a
186
200
  // targeted account, and if so, delegates to the VM.
187
201
  func (k Keeper) InterceptWriteAcknowledgement(ctx sdk.Context, chanCap *capabilitytypes.Capability, packet ibcexported.PacketI, ack ibcexported.Acknowledgement) error {
188
- _, receiver, err := k.parseTransfer(ctx, packet)
189
- if err != nil || receiver == "" {
190
- // We can't parse, but that means just to ack directly.
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.
191
206
  return k.WriteAcknowledgement(ctx, chanCap, packet, ack)
192
207
  }
193
208
 
194
- // Trigger VM
195
- if err = k.vibcKeeper.TriggerWriteAcknowledgement(ctx, receiver, packet, ack); err != nil {
209
+ // Trigger VM with the original packet.
210
+ if err = k.vibcKeeper.TriggerWriteAcknowledgement(ctx, baseReceiver, packet, ack); err != nil {
196
211
  errAck := channeltypes.NewErrorAcknowledgement(err)
197
212
  return k.WriteAcknowledgement(ctx, chanCap, packet, errAck)
198
213
  }
@@ -200,27 +215,13 @@ func (k Keeper) InterceptWriteAcknowledgement(ctx sdk.Context, chanCap *capabili
200
215
  return nil
201
216
  }
202
217
 
203
- // parseTransfer checks if a packet's sender and/or receiver are targeted accounts.
204
- func (k Keeper) parseTransfer(ctx sdk.Context, packet ibcexported.PacketI) (string, string, error) {
205
- var transferData transfertypes.FungibleTokenPacketData
206
- err := k.cdc.UnmarshalJSON(packet.GetData(), &transferData)
207
- if err != nil {
208
- return "", "", err
209
- }
210
-
211
- var sender string
212
- var receiver string
218
+ // targetIsWatched checks if a target address has been watched by the VM.
219
+ func (k Keeper) targetIsWatched(ctx sdk.Context, target string) bool {
213
220
  prefixStore := prefix.NewStore(
214
221
  ctx.KVStore(k.key),
215
222
  []byte(watchedAddressStoreKeyPrefix),
216
223
  )
217
- if prefixStore.Has([]byte(transferData.Sender)) {
218
- sender = transferData.Sender
219
- }
220
- if prefixStore.Has([]byte(transferData.Receiver)) {
221
- receiver = transferData.Receiver
222
- }
223
- return sender, receiver, nil
224
+ return prefixStore.Has([]byte(target))
224
225
  }
225
226
 
226
227
  // GetWatchedAdresses returns the watched addresses from the keeper as a slice
@@ -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
+ }
@@ -0,0 +1,167 @@
1
+ package types_test
2
+
3
+ import (
4
+ "testing"
5
+
6
+ "github.com/stretchr/testify/require"
7
+
8
+ codec "github.com/cosmos/cosmos-sdk/codec"
9
+ cdctypes "github.com/cosmos/cosmos-sdk/codec/types"
10
+
11
+ transfertypes "github.com/cosmos/ibc-go/v6/modules/apps/transfer/types"
12
+ clienttypes "github.com/cosmos/ibc-go/v6/modules/core/02-client/types"
13
+ channeltypes "github.com/cosmos/ibc-go/v6/modules/core/04-channel/types"
14
+
15
+ "github.com/Agoric/agoric-sdk/golang/cosmos/x/vtransfer/types"
16
+ )
17
+
18
+ func TestExtractBaseAddress(t *testing.T) {
19
+ bases := []struct {
20
+ name string
21
+ addr string
22
+ }{
23
+ {"agoric address", "agoric1abcdefghiteaneas"},
24
+ {"cosmos address", "cosmos1abcdeffiharceuht"},
25
+ {"hex address", "0xabcdef198189818c93839ibia"},
26
+ }
27
+
28
+ prefixes := []struct {
29
+ prefix string
30
+ baseIsWrong bool
31
+ isErr bool
32
+ }{
33
+ {"", false, false},
34
+ {"/", false, true},
35
+ {"orch:/", false, true},
36
+ {"unexpected", true, false},
37
+ {"norch:/", false, true},
38
+ {"orch:", false, true},
39
+ {"norch:", false, true},
40
+ {"\x01", false, true},
41
+ }
42
+
43
+ suffixes := []struct {
44
+ suffix string
45
+ baseIsWrong bool
46
+ isErr bool
47
+ }{
48
+ {"", false, false},
49
+ {"/", false, false},
50
+ {"/sub/account", false, false},
51
+ {"?query=something&k=v&k2=v2", false, false},
52
+ {"?query=something&k=v&k2=v2#fragment", false, false},
53
+ {"unexpected", true, false},
54
+ {"\x01", false, true},
55
+ }
56
+
57
+ for _, b := range bases {
58
+ b := b
59
+ for _, p := range prefixes {
60
+ p := p
61
+ for _, s := range suffixes {
62
+ s := s
63
+ t.Run(b.name+" "+p.prefix+" "+s.suffix, func(t *testing.T) {
64
+ addr := p.prefix + b.addr + s.suffix
65
+ addr, err := types.ExtractBaseAddress(addr)
66
+ if p.isErr || s.isErr {
67
+ require.Error(t, err)
68
+ } else {
69
+ require.NoError(t, err)
70
+ if p.baseIsWrong || s.baseIsWrong {
71
+ require.NotEqual(t, b.addr, addr)
72
+ } else {
73
+ require.Equal(t, b.addr, addr)
74
+ }
75
+ }
76
+ })
77
+ }
78
+ }
79
+ }
80
+ }
81
+
82
+ func TestExtractBaseAddressFromPacket(t *testing.T) {
83
+ ir := cdctypes.NewInterfaceRegistry()
84
+ cdc := codec.NewProtoCodec(ir)
85
+ transfertypes.RegisterInterfaces(ir)
86
+ channeltypes.RegisterInterfaces(ir)
87
+ clienttypes.RegisterInterfaces(ir)
88
+
89
+ cases := []struct {
90
+ name string
91
+ addrs map[types.AddressRole]struct{ addr, baseAddr string }
92
+ }{
93
+ {"sender has params",
94
+ map[types.AddressRole]struct{ addr, baseAddr string }{
95
+ types.RoleSender: {"cosmos1abcdeffiharceuht?foo=bar&baz=bot#fragment", "cosmos1abcdeffiharceuht"},
96
+ types.RoleReceiver: {"agoric1abcdefghiteaneas", "agoric1abcdefghiteaneas"},
97
+ },
98
+ },
99
+ {"receiver has params",
100
+ map[types.AddressRole]struct{ addr, baseAddr string }{
101
+ types.RoleSender: {"cosmos1abcdeffiharceuht", "cosmos1abcdeffiharceuht"},
102
+ types.RoleReceiver: {"agoric1abcdefghiteaneas?bingo=again", "agoric1abcdefghiteaneas"},
103
+ },
104
+ },
105
+ {"both are base",
106
+ map[types.AddressRole]struct{ addr, baseAddr string }{
107
+ types.RoleSender: {"cosmos1abcdeffiharceuht", "cosmos1abcdeffiharceuht"},
108
+ types.RoleReceiver: {"agoric1abcdefghiteaneas", "agoric1abcdefghiteaneas"},
109
+ },
110
+ },
111
+ {"both have params",
112
+ map[types.AddressRole]struct{ addr, baseAddr string }{
113
+ types.RoleSender: {"agoric1abcdefghiteaneas?bingo=again", "agoric1abcdefghiteaneas"},
114
+ types.RoleReceiver: {"cosmos1abcdeffiharceuht?foo=bar&baz=bot#fragment", "cosmos1abcdeffiharceuht"},
115
+ },
116
+ },
117
+ }
118
+
119
+ for _, tc := range cases {
120
+ tc := tc
121
+ t.Run(tc.name, func(t *testing.T) {
122
+ ftPacketData := transfertypes.NewFungibleTokenPacketData("denom", "100", tc.addrs[types.RoleSender].addr, tc.addrs[types.RoleReceiver].addr, "my-favourite-memo")
123
+ packetBz, err := cdc.MarshalJSON(&ftPacketData)
124
+ require.NoError(t, err)
125
+ packet := channeltypes.NewPacket(packetBz, 1234, "my-port", "my-channel", "their-port", "their-channel", clienttypes.NewHeight(133, 445), 10999)
126
+
127
+ for role, addrs := range tc.addrs {
128
+ addrs := addrs
129
+ role := role
130
+
131
+ t.Run(string(role), func(t *testing.T) {
132
+ baseAddr, err := types.ExtractBaseAddress(addrs.addr)
133
+ require.NoError(t, err)
134
+ require.Equal(t, addrs.baseAddr, baseAddr)
135
+
136
+ packetBaseAddr, err := types.ExtractBaseAddressFromPacket(cdc, packet, role, nil)
137
+ require.NoError(t, err)
138
+ require.Equal(t, addrs.baseAddr, packetBaseAddr)
139
+
140
+ var newPacket channeltypes.Packet
141
+ packetBaseAddr2, err := types.ExtractBaseAddressFromPacket(cdc, packet, role, &newPacket)
142
+ require.NoError(t, err)
143
+ require.Equal(t, addrs.baseAddr, packetBaseAddr2)
144
+
145
+ var basePacketData transfertypes.FungibleTokenPacketData
146
+ err = cdc.UnmarshalJSON(newPacket.GetData(), &basePacketData)
147
+ require.NoError(t, err)
148
+
149
+ // Check that the only difference between the packet data is the baseAddr.
150
+ packetData := basePacketData
151
+ switch role {
152
+ case types.RoleSender:
153
+ require.Equal(t, addrs.baseAddr, basePacketData.Sender)
154
+ packetData.Sender = addrs.addr
155
+ case types.RoleReceiver:
156
+ require.Equal(t, addrs.baseAddr, basePacketData.Receiver)
157
+ packetData.Receiver = addrs.addr
158
+ default:
159
+ t.Fatal("unexpected role", role)
160
+ }
161
+
162
+ require.Equal(t, ftPacketData, packetData)
163
+ })
164
+ }
165
+ })
166
+ }
167
+ }