powerdlz23 1.1.4 → 1.1.6

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 (38) hide show
  1. package/laundry/main.py +35 -0
  2. package/package.json +1 -1
  3. package/polymer/polymer-template/.env.example +27 -0
  4. package/polymer/polymer-template/.gitmodules +6 -0
  5. package/polymer/polymer-template/.gitpod.yml +10 -0
  6. package/polymer/polymer-template/Justfile +97 -0
  7. package/polymer/polymer-template/README.md +312 -0
  8. package/polymer/polymer-template/config/alt-config.json +42 -0
  9. package/polymer/polymer-template/config.json +42 -0
  10. package/polymer/polymer-template/contracts/XCounter.sol +89 -0
  11. package/polymer/polymer-template/contracts/XCounterUC.sol +100 -0
  12. package/polymer/polymer-template/contracts/arguments.js +7 -0
  13. package/polymer/polymer-template/contracts/base/CustomChanIbcApp.sol +205 -0
  14. package/polymer/polymer-template/contracts/base/GeneralMiddleware.sol +200 -0
  15. package/polymer/polymer-template/contracts/base/UniversalChanIbcApp.sol +93 -0
  16. package/polymer/polymer-template/foundry.toml +6 -0
  17. package/polymer/polymer-template/hardhat.config.js +66 -0
  18. package/polymer/polymer-template/ibc.json +26 -0
  19. package/polymer/polymer-template/img/gh_template.png +0 -0
  20. package/polymer/polymer-template/package-lock.json +7672 -0
  21. package/polymer/polymer-template/package.json +34 -0
  22. package/polymer/polymer-template/remappings.txt +5 -0
  23. package/polymer/polymer-template/scripts/deploy.js +51 -0
  24. package/polymer/polymer-template/scripts/private/_create-channel-config.js +62 -0
  25. package/polymer/polymer-template/scripts/private/_create-channel.js +96 -0
  26. package/polymer/polymer-template/scripts/private/_deploy-config.js +62 -0
  27. package/polymer/polymer-template/scripts/private/_events.js +241 -0
  28. package/polymer/polymer-template/scripts/private/_helpers.js +113 -0
  29. package/polymer/polymer-template/scripts/private/_sanity-check-custom.js +69 -0
  30. package/polymer/polymer-template/scripts/private/_sanity-check-universal.js +120 -0
  31. package/polymer/polymer-template/scripts/private/_sanity-check.js +21 -0
  32. package/polymer/polymer-template/scripts/private/_send-packet-config.js +53 -0
  33. package/polymer/polymer-template/scripts/private/_set-contracts-config.js +50 -0
  34. package/polymer/polymer-template/scripts/private/_switch-clients.js +90 -0
  35. package/polymer/polymer-template/scripts/private/_update-vibc-address.js +52 -0
  36. package/polymer/polymer-template/scripts/private/_vibc-helpers.js +118 -0
  37. package/polymer/polymer-template/scripts/send-packet.js +38 -0
  38. package/polymer/polymer-template/scripts/send-universal-packet.js +44 -0
@@ -0,0 +1,100 @@
1
+ //SPDX-License-Identifier: UNLICENSED
2
+
3
+ pragma solidity ^0.8.9;
4
+
5
+ import "./base/UniversalChanIbcApp.sol";
6
+
7
+ contract XCounterUC is UniversalChanIbcApp {
8
+ // application specific state
9
+ uint64 public counter;
10
+ mapping(uint64 => address) public counterMap;
11
+
12
+ constructor(address _middleware) UniversalChanIbcApp(_middleware) {}
13
+
14
+ // application specific logic
15
+ function resetCounter() internal {
16
+ counter = 0;
17
+ }
18
+
19
+ function increment() internal {
20
+ counter++;
21
+ }
22
+
23
+ // IBC logic
24
+
25
+ /**
26
+ * @dev Sends a packet with the caller's address over the universal channel.
27
+ * @param destPortAddr The address of the destination application.
28
+ * @param channelId The ID of the channel to send the packet to.
29
+ * @param timeoutSeconds The timeout in seconds (relative).
30
+ */
31
+ function sendUniversalPacket(address destPortAddr, bytes32 channelId, uint64 timeoutSeconds) external {
32
+ increment();
33
+ bytes memory payload = abi.encode(msg.sender, counter);
34
+
35
+ uint64 timeoutTimestamp = uint64((block.timestamp + timeoutSeconds) * 1000000000);
36
+
37
+ IbcUniversalPacketSender(mw).sendUniversalPacket(
38
+ channelId, IbcUtils.toBytes32(destPortAddr), payload, timeoutTimestamp
39
+ );
40
+ }
41
+
42
+ /**
43
+ * @dev Packet lifecycle callback that implements packet receipt logic and returns and acknowledgement packet.
44
+ * MUST be overriden by the inheriting contract.
45
+ *
46
+ * @param channelId the ID of the channel (locally) the packet was received on.
47
+ * @param packet the Universal packet encoded by the source and relayed by the relayer.
48
+ */
49
+ function onRecvUniversalPacket(bytes32 channelId, UniversalPacket calldata packet)
50
+ external
51
+ override
52
+ onlyIbcMw
53
+ returns (AckPacket memory ackPacket)
54
+ {
55
+ recvedPackets.push(UcPacketWithChannel(channelId, packet));
56
+
57
+ (address payload, uint64 c) = abi.decode(packet.appData, (address, uint64));
58
+ counterMap[c] = payload;
59
+
60
+ increment();
61
+
62
+ return AckPacket(true, abi.encode(counter));
63
+ }
64
+
65
+ /**
66
+ * @dev Packet lifecycle callback that implements packet acknowledgment logic.
67
+ * MUST be overriden by the inheriting contract.
68
+ *
69
+ * @param channelId the ID of the channel (locally) the ack was received on.
70
+ * @param packet the Universal packet encoded by the source and relayed by the relayer.
71
+ * @param ack the acknowledgment packet encoded by the destination and relayed by the relayer.
72
+ */
73
+ function onUniversalAcknowledgement(bytes32 channelId, UniversalPacket memory packet, AckPacket calldata ack)
74
+ external
75
+ override
76
+ onlyIbcMw
77
+ {
78
+ ackPackets.push(UcAckWithChannel(channelId, packet, ack));
79
+
80
+ // decode the counter from the ack packet
81
+ (uint64 _counter) = abi.decode(ack.data, (uint64));
82
+
83
+ if (_counter != counter) {
84
+ resetCounter();
85
+ }
86
+ }
87
+
88
+ /**
89
+ * @dev Packet lifecycle callback that implements packet receipt logic and return and acknowledgement packet.
90
+ * MUST be overriden by the inheriting contract.
91
+ * NOT SUPPORTED YET
92
+ *
93
+ * @param channelId the ID of the channel (locally) the timeout was submitted on.
94
+ * @param packet the Universal packet encoded by the counterparty and relayed by the relayer
95
+ */
96
+ function onTimeoutUniversalPacket(bytes32 channelId, UniversalPacket calldata packet) external override onlyIbcMw {
97
+ timeoutPackets.push(UcPacketWithChannel(channelId, packet));
98
+ // do logic
99
+ }
100
+ }
@@ -0,0 +1,7 @@
1
+ module.exports = {
2
+ "XCounter": [],
3
+ "XCounterUC": [],
4
+ // Add your contract types here, along with the list of custom constructor arguments
5
+ // DO NOT ADD THE DISPATCHER OR UNIVERSAL CHANNEL HANDLER ADDRESSES HERE!!!
6
+ // These will be added in the deploy script at $ROOT/scripts/deploy.js
7
+ };
@@ -0,0 +1,205 @@
1
+ //SPDX-License-Identifier: UNLICENSED
2
+
3
+ pragma solidity ^0.8.9;
4
+
5
+ import '@open-ibc/vibc-core-smart-contracts/contracts/libs/Ibc.sol';
6
+ import '@open-ibc/vibc-core-smart-contracts/contracts/interfaces/IbcReceiver.sol';
7
+ import '@open-ibc/vibc-core-smart-contracts/contracts/interfaces/IbcDispatcher.sol';
8
+ import '@open-ibc/vibc-core-smart-contracts/contracts/interfaces/ProofVerifier.sol';
9
+
10
+ // CustomChanIbcApp is a contract that can be used as a base contract
11
+ // for IBC-enabled contracts that send packets over a custom IBC channel.
12
+ contract CustomChanIbcApp is IbcReceiverBase, IbcReceiver {
13
+ // received packet as chain B
14
+ IbcPacket[] public recvedPackets;
15
+ // received ack packet as chain A
16
+ AckPacket[] public ackPackets;
17
+ // received timeout packet as chain A
18
+ IbcPacket[] public timeoutPackets;
19
+
20
+ struct ChannelMapping {
21
+ bytes32 channelId;
22
+ bytes32 cpChannelId;
23
+ }
24
+
25
+ // ChannelMapping array with the channel IDs of the connected channels
26
+ ChannelMapping[] public connectedChannels;
27
+
28
+ // add supported versions (format to be negotiated between apps)
29
+ string[] supportedVersions = ['1.0'];
30
+
31
+ constructor(IbcDispatcher _dispatcher) IbcReceiverBase(_dispatcher) {}
32
+
33
+ function updateDispatcher(IbcDispatcher _dispatcher) external onlyOwner {
34
+ dispatcher = _dispatcher;
35
+ }
36
+
37
+ function getConnectedChannels() external view returns (ChannelMapping[] memory) {
38
+ return connectedChannels;
39
+ }
40
+
41
+ function updateSupportedVersions(string[] memory _supportedVersions) external onlyOwner {
42
+ supportedVersions = _supportedVersions;
43
+ }
44
+
45
+ /**
46
+ * @dev Implement a function to send a packet that calls the dispatcher.sendPacket function
47
+ * It has the following function handle:
48
+ * function sendPacket(bytes32 channelId, bytes calldata payload, uint64 timeoutTimestamp) external;
49
+ */
50
+
51
+ /**
52
+ * @dev Packet lifecycle callback that implements packet receipt logic and returns and acknowledgement packet.
53
+ * MUST be overriden by the inheriting contract.
54
+ *
55
+ * @param packet the IBC packet encoded by the source and relayed by the relayer.
56
+ */
57
+ function onRecvPacket(IbcPacket memory packet) external virtual onlyIbcDispatcher returns (AckPacket memory ackPacket) {
58
+ recvedPackets.push(packet);
59
+ // do logic
60
+ return AckPacket(true, abi.encodePacked('{ "account": "account", "reply": "got the message" }'));
61
+ }
62
+
63
+ /**
64
+ * @dev Packet lifecycle callback that implements packet acknowledgment logic.
65
+ * MUST be overriden by the inheriting contract.
66
+ *
67
+ * @param packet the IBC packet encoded by the source and relayed by the relayer.
68
+ * @param ack the acknowledgment packet encoded by the destination and relayed by the relayer.
69
+ */
70
+ function onAcknowledgementPacket(IbcPacket calldata packet, AckPacket calldata ack) external virtual onlyIbcDispatcher {
71
+ ackPackets.push(ack);
72
+ // do logic
73
+ }
74
+
75
+ /**
76
+ * @dev Packet lifecycle callback that implements packet receipt logic and return and acknowledgement packet.
77
+ * MUST be overriden by the inheriting contract.
78
+ * NOT SUPPORTED YET
79
+ *
80
+ * @param packet the IBC packet encoded by the counterparty and relayed by the relayer
81
+ */
82
+ function onTimeoutPacket(IbcPacket calldata packet) external virtual onlyIbcDispatcher {
83
+ timeoutPackets.push(packet);
84
+ // do logic
85
+ }
86
+
87
+ /**
88
+ * @dev Create a custom channel between two IbcReceiver contracts
89
+ * @param local a CounterParty struct with the local chain's portId and version (channelId can be empty)
90
+ * @param ordering the channel ordering (NONE, UNORDERED, ORDERED) equivalent to (0, 1, 2)
91
+ * @param feeEnabled in production, you'll want to enable this to avoid spamming create channel calls (costly for relayers)
92
+ * @param connectionHops 2 connection hops to connect to the destination via Polymer
93
+ * @param counterparty the address of the destination chain contract you want to connect to
94
+ * @param proof ICS23 proof struct with dummy data (only needed on ChanOpenTry)
95
+ */
96
+ function createChannel(
97
+ CounterParty calldata local,
98
+ uint8 ordering,
99
+ bool feeEnabled,
100
+ string[] calldata connectionHops,
101
+ CounterParty calldata counterparty,
102
+ Ics23Proof calldata proof
103
+ ) external virtual onlyOwner{
104
+
105
+ dispatcher.openIbcChannel(
106
+ IbcChannelReceiver(address(this)),
107
+ local,
108
+ ChannelOrder(ordering),
109
+ feeEnabled,
110
+ connectionHops,
111
+ counterparty,
112
+ proof
113
+ );
114
+ }
115
+
116
+ function onOpenIbcChannel(
117
+ string calldata version,
118
+ ChannelOrder,
119
+ bool,
120
+ string[] calldata,
121
+ CounterParty calldata counterparty
122
+ ) external view virtual onlyIbcDispatcher returns (string memory selectedVersion) {
123
+ if (bytes(counterparty.portId).length <= 8) {
124
+ revert invalidCounterPartyPortId();
125
+ }
126
+ /**
127
+ * Version selection is determined by if the callback is invoked on behalf of ChanOpenInit or ChanOpenTry.
128
+ * ChanOpenInit: self version should be provided whereas the counterparty version is empty.
129
+ * ChanOpenTry: counterparty version should be provided whereas the self version is empty.
130
+ * In both cases, the selected version should be in the supported versions list.
131
+ */
132
+ bool foundVersion = false;
133
+ selectedVersion = keccak256(abi.encodePacked(version)) == keccak256(abi.encodePacked(''))
134
+ ? counterparty.version
135
+ : version;
136
+ for (uint256 i = 0; i < supportedVersions.length; i++) {
137
+ if (keccak256(abi.encodePacked(selectedVersion)) == keccak256(abi.encodePacked(supportedVersions[i]))) {
138
+ foundVersion = true;
139
+ break;
140
+ }
141
+ }
142
+ require(foundVersion, 'Unsupported version');
143
+ // if counterpartyVersion is not empty, then it must be the same foundVersion
144
+ if (keccak256(abi.encodePacked(counterparty.version)) != keccak256(abi.encodePacked(''))) {
145
+ require(
146
+ keccak256(abi.encodePacked(counterparty.version)) == keccak256(abi.encodePacked(selectedVersion)),
147
+ 'Version mismatch'
148
+ );
149
+ }
150
+
151
+ // do logic
152
+
153
+ return selectedVersion;
154
+ }
155
+
156
+ function onConnectIbcChannel(
157
+ bytes32 channelId,
158
+ bytes32 counterpartyChannelId,
159
+ string calldata counterpartyVersion
160
+ ) external virtual onlyIbcDispatcher {
161
+ // ensure negotiated version is supported
162
+ bool foundVersion = false;
163
+ for (uint256 i = 0; i < supportedVersions.length; i++) {
164
+ if (keccak256(abi.encodePacked(counterpartyVersion)) == keccak256(abi.encodePacked(supportedVersions[i]))) {
165
+ foundVersion = true;
166
+ break;
167
+ }
168
+ }
169
+ require(foundVersion, 'Unsupported version');
170
+
171
+ // do logic
172
+
173
+ ChannelMapping memory channelMapping = ChannelMapping({
174
+ channelId: channelId,
175
+ cpChannelId: counterpartyChannelId
176
+ });
177
+ connectedChannels.push(channelMapping);
178
+ }
179
+
180
+ function onCloseIbcChannel(bytes32 channelId, string calldata, bytes32) external virtual onlyIbcDispatcher {
181
+ // logic to determin if the channel should be closed
182
+ bool channelFound = false;
183
+ for (uint256 i = 0; i < connectedChannels.length; i++) {
184
+ if (connectedChannels[i].channelId == channelId) {
185
+ for (uint256 j = i; j < connectedChannels.length - 1; j++) {
186
+ connectedChannels[j] = connectedChannels[j + 1];
187
+ }
188
+ connectedChannels.pop();
189
+ channelFound = true;
190
+ break;
191
+ }
192
+ }
193
+ require(channelFound, 'Channel not found');
194
+
195
+ // do logic
196
+ }
197
+
198
+ /**
199
+ * This func triggers channel closure from the dApp.
200
+ * Func args can be arbitary, as long as dispatcher.closeIbcChannel is invoked propperly.
201
+ */
202
+ function triggerChannelClose(bytes32 channelId) external virtual onlyOwner {
203
+ dispatcher.closeIbcChannel(channelId);
204
+ }
205
+ }
@@ -0,0 +1,200 @@
1
+ //SPDX-License-Identifier: UNLICENSED
2
+
3
+ pragma solidity ^0.8.9;
4
+
5
+ import '@open-ibc/vibc-core-smart-contracts/contracts/libs/Ibc.sol';
6
+ import '@open-ibc/vibc-core-smart-contracts/contracts/interfaces/IbcReceiver.sol';
7
+ import '@open-ibc/vibc-core-smart-contracts/contracts/interfaces/IbcDispatcher.sol';
8
+ import '@open-ibc/vibc-core-smart-contracts/contracts/interfaces/IbcMiddleware.sol';
9
+
10
+ contract GeneralMiddleware is IbcMwUser, IbcMiddleware, IbcMwEventsEmitter {
11
+ /**
12
+ * @dev MW_ID is the ID of MW contract on all supported virtual chains.
13
+ * MW_ID must:
14
+ * - be globally unique, ie. no two MWs should have the same MW_ID registered on Polymer chain.
15
+ * - be identical on all supported virtual chains.
16
+ * - be identical on one virtual chain across multiple deployed MW instances. Each MW instance belong exclusively to one MW stack.
17
+ * - be 1 << N, where N is a non-negative integer, and not in conflict with other MWs.
18
+ */
19
+ uint256 public MW_ID;
20
+
21
+ /**
22
+ * @param _middleware The middleware contract address this contract sends packets to and receives packets from.
23
+ */
24
+
25
+ constructor(uint256 mwId, address _middleware) IbcMwUser(_middleware) {
26
+ MW_ID = mwId;
27
+ }
28
+
29
+ function sendUniversalPacket(
30
+ bytes32 channelId,
31
+ bytes32 destPortAddr,
32
+ bytes calldata appData,
33
+ uint64 timeoutTimestamp
34
+ ) external override {
35
+ _sendPacket(channelId, IbcUtils.toBytes32(msg.sender), destPortAddr, 0, appData, timeoutTimestamp);
36
+ }
37
+
38
+ function sendMWPacket(
39
+ bytes32 channelId,
40
+ bytes32 srcPortAddr,
41
+ bytes32 destPortAddr,
42
+ uint256 srcMwIds,
43
+ bytes calldata appData,
44
+ uint64 timeoutTimestamp
45
+ ) external override {
46
+ _sendPacket(channelId, srcPortAddr, destPortAddr, srcMwIds, appData, timeoutTimestamp);
47
+ }
48
+
49
+ function onRecvMWPacket(
50
+ bytes32 channelId,
51
+ UniversalPacket calldata ucPacket,
52
+ // address srcPortAddr,
53
+ // address destPortAddr,
54
+ // 0-based receiver middleware index in the MW stack.
55
+ // 0 for the first MW directly called by UniversalChannel MW.
56
+ // `mwIndex-1` is the last MW that delivers the packet to the non-MW dApp.
57
+ // Each mw in the stack must increment mwIndex by 1 before calling the next MW.
58
+ uint256 mwIndex,
59
+ // bytes calldata appData,
60
+ address[] calldata mwAddrs
61
+ ) external onlyIbcMw returns (AckPacket memory ackPacket) {
62
+ // extra MW custom logic here to process packet, eg. emit MW events, mutate state, etc.
63
+ // implementer can emit custom data fields suitable for their use cases.
64
+ // Here we use MW_ID as the custom MW data field.
65
+ emit RecvMWPacket(
66
+ channelId,
67
+ ucPacket.srcPortAddr,
68
+ ucPacket.destPortAddr,
69
+ MW_ID,
70
+ ucPacket.appData,
71
+ abi.encodePacked(MW_ID)
72
+ );
73
+
74
+ if (mwIndex == mwAddrs.length - 1) {
75
+ // last MW in the stack, deliver packet to dApp
76
+ return
77
+ IbcUniversalPacketReceiver(IbcUtils.toAddress(ucPacket.destPortAddr)).onRecvUniversalPacket(
78
+ channelId,
79
+ ucPacket
80
+ );
81
+ } else {
82
+ // send packet to next MW
83
+ return IbcMwPacketReceiver(mwAddrs[mwIndex + 1]).onRecvMWPacket(channelId, ucPacket, mwIndex + 1, mwAddrs);
84
+ }
85
+ }
86
+
87
+ function onRecvMWAck(
88
+ bytes32 channelId,
89
+ UniversalPacket calldata ucPacket,
90
+ // 0-based receiver middleware index in the MW stack.
91
+ // 0 for the first MW directly called by UniversalChannel MW.
92
+ // `mwIndex-1` is the last MW that delivers the packet to the non-MW dApp.
93
+ // Each mw in the stack must increment mwIndex by 1 before calling the next MW.
94
+ uint256 mwIndex,
95
+ address[] calldata mwAddrs,
96
+ AckPacket calldata ack
97
+ ) external override onlyIbcMw {
98
+ // extra MW custom logic here to process packet, eg. emit MW events, mutate state, etc.
99
+ // implementer can emit custom data fields suitable for their use cases.
100
+ // Here we use MW_ID as the custom MW data field.
101
+ emit RecvMWAck(
102
+ channelId,
103
+ ucPacket.srcPortAddr,
104
+ ucPacket.destPortAddr,
105
+ MW_ID,
106
+ ucPacket.appData,
107
+ abi.encodePacked(MW_ID),
108
+ ack
109
+ );
110
+
111
+ if (mwIndex == mwAddrs.length - 1) {
112
+ // last MW in the stack, deliver ack to dApp
113
+ IbcUniversalPacketReceiver(IbcUtils.toAddress(ucPacket.srcPortAddr)).onUniversalAcknowledgement(
114
+ channelId,
115
+ ucPacket,
116
+ ack
117
+ );
118
+ } else {
119
+ // send ack to next MW
120
+ IbcMwPacketReceiver(mwAddrs[mwIndex + 1]).onRecvMWAck(channelId, ucPacket, mwIndex + 1, mwAddrs, ack);
121
+ }
122
+ }
123
+
124
+ function onRecvMWTimeout(
125
+ bytes32 channelId,
126
+ UniversalPacket calldata ucPacket,
127
+ uint256 mwIndex,
128
+ address[] calldata mwAddrs
129
+ ) external override onlyIbcMw {
130
+ // extra MW custom logic here to process packet, eg. emit MW events, mutate state, etc.
131
+ // implementer can emit custom data fields suitable for their use cases.
132
+ // Here we use MW_ID as the custom MW data field.
133
+ emit RecvMWTimeout(
134
+ channelId,
135
+ ucPacket.srcPortAddr,
136
+ ucPacket.destPortAddr,
137
+ MW_ID,
138
+ ucPacket.appData,
139
+ abi.encodePacked(MW_ID)
140
+ );
141
+
142
+ if (mwIndex == mwAddrs.length - 1) {
143
+ // last MW in the stack, deliver timeout to dApp
144
+ IbcUniversalPacketReceiver(IbcUtils.toAddress(ucPacket.srcPortAddr)).onTimeoutUniversalPacket(
145
+ channelId,
146
+ ucPacket
147
+ );
148
+ } else {
149
+ // send timeout to next MW
150
+ IbcMwPacketReceiver(mwAddrs[mwIndex + 1]).onRecvMWTimeout(channelId, ucPacket, mwIndex + 1, mwAddrs);
151
+ }
152
+ }
153
+
154
+ function onRecvUniversalPacket(
155
+ bytes32 channelId,
156
+ UniversalPacket calldata ucPacket
157
+ ) external override onlyIbcMw returns (AckPacket memory ackPacket) {}
158
+
159
+ function onUniversalAcknowledgement(
160
+ bytes32 channelId,
161
+ UniversalPacket memory packet,
162
+ AckPacket calldata ack
163
+ ) external override onlyIbcMw {}
164
+
165
+ function onTimeoutUniversalPacket(bytes32 channelId, UniversalPacket calldata packet) external override onlyIbcMw {}
166
+
167
+ // internal function to send packet to next MW with MW Ids bit flipped
168
+ // param srcMwIds: MW ID bitmap excluding this MW's ID
169
+ function _sendPacket(
170
+ bytes32 channelId,
171
+ bytes32 srcPortAddr,
172
+ bytes32 destPortAddr,
173
+ uint256 srcMwIds,
174
+ bytes calldata appData,
175
+ uint64 timeoutTimestamp
176
+ ) internal virtual {
177
+ // extra MW custom logic here to process packet, eg. emit MW events, mutate state, etc.
178
+ // implementer can emit custom data fields suitable for their use cases.
179
+ // Here we use MW_ID as the custom MW data field.
180
+ emit SendMWPacket(
181
+ channelId,
182
+ srcPortAddr,
183
+ destPortAddr,
184
+ MW_ID,
185
+ appData,
186
+ timeoutTimestamp,
187
+ abi.encodePacked(MW_ID)
188
+ );
189
+
190
+ // send packet to next MW
191
+ IbcMwPacketSender(mw).sendMWPacket(
192
+ channelId,
193
+ srcPortAddr,
194
+ destPortAddr,
195
+ srcMwIds | MW_ID,
196
+ appData,
197
+ timeoutTimestamp
198
+ );
199
+ }
200
+ }
@@ -0,0 +1,93 @@
1
+ //SPDX-License-Identifier: UNLICENSED
2
+
3
+ pragma solidity ^0.8.9;
4
+
5
+ import '@open-ibc/vibc-core-smart-contracts/contracts/libs/Ibc.sol';
6
+ import '@open-ibc/vibc-core-smart-contracts/contracts/interfaces/IbcReceiver.sol';
7
+ import '@open-ibc/vibc-core-smart-contracts/contracts/interfaces/IbcDispatcher.sol';
8
+ import '@open-ibc/vibc-core-smart-contracts/contracts/interfaces/IbcMiddleware.sol';
9
+
10
+ // UniversalChanIbcApp is a contract that can be used as a base contract
11
+ // for IBC-enabled contracts that send packets over the universal channel.
12
+ contract UniversalChanIbcApp is IbcMwUser, IbcUniversalPacketReceiver {
13
+ struct UcPacketWithChannel {
14
+ bytes32 channelId;
15
+ UniversalPacket packet;
16
+ }
17
+
18
+ struct UcAckWithChannel {
19
+ bytes32 channelId;
20
+ UniversalPacket packet;
21
+ AckPacket ack;
22
+ }
23
+
24
+ // received packet as chain B
25
+ UcPacketWithChannel[] public recvedPackets;
26
+ // received ack packet as chain A
27
+ UcAckWithChannel[] public ackPackets;
28
+ // received timeout packet as chain A
29
+ UcPacketWithChannel[] public timeoutPackets;
30
+
31
+ constructor(address _middleware) IbcMwUser(_middleware) {}
32
+
33
+ /**
34
+ * @dev Implement a function to send a packet that calls the IbcUniversalPacketSender(mw).sendUniversalPacket function
35
+ * It has the following function handle:
36
+ * function sendUniversalPacket(
37
+ bytes32 channelId,
38
+ bytes32 destPortAddr,
39
+ bytes calldata appData,
40
+ uint64 timeoutTimestamp
41
+ ) external;
42
+ */
43
+
44
+ /**
45
+ * @dev Packet lifecycle callback that implements packet receipt logic and returns and acknowledgement packet.
46
+ * MUST be overriden by the inheriting contract.
47
+ *
48
+ * @param channelId the ID of the channel (locally) the packet was received on.
49
+ * @param packet the Universal packet encoded by the source and relayed by the relayer.
50
+ */
51
+ function onRecvUniversalPacket(
52
+ bytes32 channelId,
53
+ UniversalPacket calldata packet
54
+ ) external virtual onlyIbcMw returns (AckPacket memory ackPacket) {
55
+ recvedPackets.push(UcPacketWithChannel(channelId, packet));
56
+ // 1. decode the packet.data
57
+ // 2. do logic
58
+ // 3. encode the ack packet (encoding format should be agreed between the two applications)
59
+ // below is an example, the actual ackpacket data should be implemented by the contract developer
60
+ return AckPacket(true, abi.encodePacked(address(this), IbcUtils.toAddress(packet.srcPortAddr), 'ack-', packet.appData));
61
+ }
62
+
63
+ /**
64
+ * @dev Packet lifecycle callback that implements packet acknowledgment logic.
65
+ * MUST be overriden by the inheriting contract.
66
+ *
67
+ * @param channelId the ID of the channel (locally) the ack was received on.
68
+ * @param packet the Universal packet encoded by the source and relayed by the relayer.
69
+ * @param ack the acknowledgment packet encoded by the destination and relayed by the relayer.
70
+ */
71
+ function onUniversalAcknowledgement(
72
+ bytes32 channelId,
73
+ UniversalPacket memory packet,
74
+ AckPacket calldata ack
75
+ ) external virtual onlyIbcMw {
76
+ ackPackets.push(UcAckWithChannel(channelId, packet, ack));
77
+ // 1. decode the ack.data
78
+ // 2. do logic
79
+ }
80
+
81
+ /**
82
+ * @dev Packet lifecycle callback that implements packet receipt logic and return and acknowledgement packet.
83
+ * MUST be overriden by the inheriting contract.
84
+ * NOT SUPPORTED YET
85
+ *
86
+ * @param channelId the ID of the channel (locally) the timeout was submitted on.
87
+ * @param packet the Universal packet encoded by the counterparty and relayed by the relayer
88
+ */
89
+ function onTimeoutUniversalPacket(bytes32 channelId, UniversalPacket calldata packet) external virtual onlyIbcMw {
90
+ timeoutPackets.push(UcPacketWithChannel(channelId, packet));
91
+ // do logic
92
+ }
93
+ }
@@ -0,0 +1,6 @@
1
+ [profile.default]
2
+ src = 'contracts'
3
+ out = 'out'
4
+ libs = ['node_modules', 'lib']
5
+ test = 'test'
6
+ cache_path = 'cache_forge'
@@ -0,0 +1,66 @@
1
+ require("@nomicfoundation/hardhat-toolbox");
2
+ require("@nomicfoundation/hardhat-foundry");
3
+
4
+ require('dotenv').config();
5
+
6
+ /** @type import('hardhat/config').HardhatUserConfig */
7
+ module.exports = {
8
+ solidity: {
9
+ version: '0.8.23',
10
+ settings: {
11
+ optimizer: {
12
+ enabled: true,
13
+ runs: 200 // Optimize for a typical number of runs
14
+ }
15
+ }
16
+ },
17
+ networks: {
18
+ // for Base testnet
19
+ 'base': {
20
+ url: 'https://sepolia.base.org',
21
+ accounts: [
22
+ process.env.PRIVATE_KEY_1
23
+ ],
24
+ },
25
+ // for OP testnet
26
+ 'optimism': {
27
+ url: 'https://sepolia.optimism.io',
28
+ accounts: [
29
+ process.env.PRIVATE_KEY_1
30
+ ],
31
+ },
32
+ },
33
+ defaultNetwork: 'optimism',
34
+ paths: {
35
+ sources: './contracts',
36
+ tests: './test',
37
+ cache: './cache',
38
+ artifacts: './artifacts',
39
+ libraries: './lib',
40
+ },
41
+ etherscan: {
42
+ apiKey: {
43
+ optimism: process.env.OP_BLOCKSCOUT_API_KEY,
44
+ base: process.env.BASE_BLOCKSCOUT_API_KEY,
45
+ },
46
+ customChains: [
47
+ {
48
+ network: "base",
49
+ chainId: 84532,
50
+ urls: {
51
+ apiURL: "https://base-sepolia.blockscout.com/api",
52
+ browserURL: "https://base-sepolia.blockscout.com",
53
+ }
54
+ },
55
+ {
56
+ network: "optimism",
57
+ chainId: 11155420,
58
+ urls: {
59
+ apiURL: "https://optimism-sepolia.blockscout.com/api",
60
+ browserURL: "https://optimism-sepolia.blockscout.com",
61
+ }
62
+ }
63
+ ]
64
+ },
65
+ };
66
+