@@ -40,59 +40,127 @@ public ICS20Transfer(Address _ibcHandler, byte[] _serializeIrc2) {
40
40
serializedIrc2 = _serializeIrc2 ;
41
41
}
42
42
43
+ /**
44
+ * Set the admin address and ensure only admin can call this function.
45
+ *
46
+ * @param _admin the new admin address
47
+ * @return void
48
+ */
43
49
@ External
44
50
public void setAdmin (Address _admin ) {
45
51
onlyAdmin ();
46
52
admin .set (_admin );
47
53
}
48
54
55
+ /**
56
+ * Retrieves the admin address.
57
+ *
58
+ * @return the admin address
59
+ */
49
60
@ External (readonly = true )
50
61
public Address getAdmin () {
51
62
return admin .get ();
52
63
}
53
64
65
+ /**
66
+ * Retrieves the IBC handler address.
67
+ *
68
+ * @return the IBC handler address
69
+ */
54
70
@ External (readonly = true )
55
71
public Address getIBCAddress () {
56
72
return ibcHandler .get ();
57
73
}
58
74
75
+ /**
76
+ * Retrieves the destination port for the given channel ID.
77
+ *
78
+ * @param channelId the source channel id
79
+ * @return the destination port associated with the channel ID
80
+ */
59
81
@ External (readonly = true )
60
82
public String getDestinationPort (String channelId ) {
61
83
return destinationPort .get (channelId );
62
84
}
63
85
86
+ /**
87
+ * Retrieves the destination channel for the given channel ID.
88
+ *
89
+ * @param channelId the source channel id
90
+ * @return the destination channel associated with the channel ID
91
+ */
64
92
@ External (readonly = true )
65
93
public String getDestinationChannel (String channelId ) {
66
94
return destinationChannel .get (channelId );
67
95
}
68
96
97
+ /**
98
+ * Retrieves the token contract address for the given denom.
99
+ *
100
+ * @param denom the token denom
101
+ * @return the token contract address
102
+ */
69
103
@ External (readonly = true )
70
104
public Address getTokenContractAddress (String denom ) {
71
- System .out .println (denom +"bbbbbbbbbbbbbbb" );
72
- Context .require (tokenContracts .get (denom ) != null , TAG +" : Token not registered" );
105
+ Context .require (tokenContracts .get (denom ) != null , TAG + " : Token not registered" );
73
106
return tokenContracts .get (denom );
74
107
}
75
108
109
+ /**
110
+ * Register a token contract for cosmos chain.
111
+ *
112
+ * @param name
113
+ * @param symbol
114
+ * @param decimals
115
+ */
76
116
@ External
77
117
public void registerCosmosToken (String name , String symbol , int decimals ) {
78
118
onlyAdmin ();
79
119
Address tokenAddress = Context .deploy (serializedIrc2 , name , symbol , decimals );
80
120
tokenContracts .set (name , tokenAddress );
81
121
}
82
122
123
+ /**
124
+ * Register a token contract for icon chain.
125
+ *
126
+ * @param tokenAddress the irc2 token contract address
127
+ */
83
128
@ External
84
129
public void registerIconToken (Address tokenAddress ) {
85
130
onlyAdmin ();
86
131
tokenContracts .set (tokenAddress .toString (), tokenAddress );
87
132
}
88
133
134
+ /**
135
+ * Fallback function for token transfer.
136
+ *
137
+ * @param from Sender address
138
+ * @param value Amount
139
+ * @param _data Data in json bytes in format of
140
+ * {
141
+ * "method": "sendFungibleTokens",
142
+ * "params": {
143
+ * "denomination": "string",
144
+ * "amount": "uint64",
145
+ * "sender": "string",
146
+ * "receiver": "string",
147
+ * "sourcePort": "string",
148
+ * "sourceChannel": "string",
149
+ * "timeoutHeight": {
150
+ * "latestHeight": "uint64",
151
+ * "revisionNumber": "uint64",
152
+ * },
153
+ * "timeoutTimestamp": "uint64",
154
+ * "memo":"string"
155
+ * }
156
+ * }
157
+ *
158
+ */
89
159
@ External
90
160
public void tokenFallback (Address from , BigInteger value , byte [] _data ) {
91
161
String method = "" ;
92
162
JsonValue params = null ;
93
163
94
- // Context.require(registeredTokenContracts.getOrDefault(Context.getCaller(), false), TAG+" : Token not registered");
95
-
96
164
try {
97
165
String data = new String (_data );
98
166
JsonObject json = Json .parse (data ).asObject ();
@@ -119,10 +187,11 @@ public void tokenFallback(Address from, BigInteger value, byte[] _data) {
119
187
height .setRevisionNumber (BigInteger .valueOf (timeoutHeight .getLong ("revisionNumber" , 0 )));
120
188
height .setRevisionHeight (BigInteger .valueOf (timeoutHeight .getLong ("latestHeight" , 0 )));
121
189
122
- Context .require (amount .equals (value ), TAG +" : Mismatched amount" );
123
- Context .require (sender .equals (from .toString ()), TAG +" : Sender address mismatched" );
124
- Context .require (tokenContracts .get (denomination ) == Context .getCaller (), TAG +" : Sender Token Contract not registered" );
125
-
190
+ Context .require (amount .equals (value ), TAG + " : Mismatched amount" );
191
+ Context .require (sender .equals (from .toString ()), TAG + " : Sender address mismatched" );
192
+ Context .require (tokenContracts .get (denomination ) == Context .getCaller (),
193
+ TAG + " : Sender Token Contract not registered" );
194
+
126
195
sendFungibleToken (denomination , amount , sender , receiver , sourcePort , sourceChannel , height ,
127
196
timeoutTimestamp , memo );
128
197
} else {
@@ -131,17 +200,41 @@ public void tokenFallback(Address from, BigInteger value, byte[] _data) {
131
200
132
201
}
133
202
203
+ /**
204
+ * Sends ICX to the specified receiver via the specified channel and port.
205
+ *
206
+ * @param receiver the cross chain address of the receiver
207
+ * @param sourcePort the source port
208
+ * @param sourceChannel the source channel
209
+ * @param timeoutHeight the timeout height
210
+ * @param timeoutTimestamp the timeout timestamp
211
+ * @param memo an optional memo
212
+ */
134
213
@ Payable
135
214
@ External
136
215
public void sendICX (String receiver , String sourcePort , String sourceChannel , Height timeoutHeight ,
137
216
BigInteger timeoutTimestamp , @ Optional String memo ) {
138
- Context .require (Context .getValue ().compareTo (BigInteger .ZERO ) > 0 , TAG +" : ICX amount should be greater than 0" );
217
+ Context .require (Context .getValue ().compareTo (BigInteger .ZERO ) > 0 ,
218
+ TAG + " : ICX amount should be greater than 0" );
139
219
140
220
sendFungibleToken ("icx" , Context .getValue (), Context .getCaller ().toString (), receiver , sourcePort ,
141
221
sourceChannel , timeoutHeight , timeoutTimestamp , memo );
142
222
143
223
}
144
224
225
+ /**
226
+ * Sends a irc2 token from the sender to the receiver.
227
+ *
228
+ * @param denomination the denomination of the token to send
229
+ * @param amount the amount of the token to send
230
+ * @param sender the address of the sender
231
+ * @param receiver the cross chain address of the receiver
232
+ * @param sourcePort the source port
233
+ * @param sourceChannel the source channel
234
+ * @param timeoutHeight the timeout height(latest height and revision number)
235
+ * @param timeoutTimestamp the timeout timestamp
236
+ * @param memo an optional memo for the transaction
237
+ */
145
238
private void sendFungibleToken (String denomination , BigInteger amount , String sender , String receiver ,
146
239
String sourcePort , String sourceChannel , Height timeoutHeight , BigInteger timeoutTimestamp ,
147
240
@ Optional String memo ) {
@@ -158,17 +251,13 @@ private void sendFungibleToken(String denomination, BigInteger amount, String se
158
251
String destPort = destinationPort .get (sourceChannel );
159
252
String destChannel = destinationChannel .get (sourceChannel );
160
253
161
- if (destChannel == null || destPort == null ) {
254
+ if (destChannel == null || destPort == null ) {
162
255
Context .revert (TAG + " : Connection not properly Configured" );
163
256
}
164
257
165
- System .out .println ("destPort: " + destPort + isSource );
166
-
167
258
BigInteger seq = Context .call (BigInteger .class , ibcHandler .get (), "getNextSequenceSend" , sourcePort ,
168
259
sourceChannel );
169
260
170
- System .out .println ("seq: " + seq );
171
-
172
261
Packet newPacket = new Packet ();
173
262
174
263
newPacket .setSequence (seq );
@@ -183,20 +272,28 @@ private void sendFungibleToken(String denomination, BigInteger amount, String se
183
272
Context .call (ibcHandler .get (), "sendPacket" , newPacket .encode ());
184
273
}
185
274
275
+ /**
276
+ * Handles the reception of a packet
277
+ *
278
+ * @param packet the byte array representation of the packet to be processed
279
+ * @param relayer the address of the relayer
280
+ * @return a byte array representing the acknowledgement of the packet
281
+ * processing
282
+ */
186
283
@ External
187
284
public byte [] onRecvPacket (byte [] packet , Address relayer ) {
188
285
onlyIBC ();
189
286
Packet packetDb = Packet .decode (packet );
190
287
ICS20Lib .FungibleTokenPacketData data ;
191
-
288
+
192
289
try {
193
290
data = ICS20Lib .unmarshalFungibleTokenPacketData (packetDb .getData ());
194
291
195
- Context .require (!data .denom .equals ("" ), TAG + " : ICS20: invalid denomination" );
196
- Context .require (!data .receiver .equals ("" ), TAG + " : ICS20: invalid receiver address" );
197
- Context .require (!data .sender .equals ("" ), TAG + " : ICS20: invalid sender address" );
198
- Context .require (data .amount .compareTo (BigInteger .ZERO )> 0 , TAG + " : ICS20: invalid amount" );
199
-
292
+ Context .require (!data .denom .equals ("" ), TAG + " : ICS20: invalid denomination" );
293
+ Context .require (!data .receiver .equals ("" ), TAG + " : ICS20: invalid receiver address" );
294
+ Context .require (!data .sender .equals ("" ), TAG + " : ICS20: invalid sender address" );
295
+ Context .require (data .amount .compareTo (BigInteger .ZERO ) > 0 , TAG + " : ICS20: invalid amount" );
296
+
200
297
} catch (Exception e ) {
201
298
return ICS20Lib .FAILED_ACKNOWLEDGEMENT_JSON ;
202
299
}
@@ -206,44 +303,51 @@ public byte[] onRecvPacket(byte[] packet, Address relayer) {
206
303
207
304
byte [] ack = ICS20Lib .SUCCESSFUL_ACKNOWLEDGEMENT_JSON ;
208
305
209
- if (!checkIfReceiverIsAddress (data .receiver )){
306
+ if (!checkIfReceiverIsAddress (data .receiver )) {
210
307
return ICS20Lib .FAILED_ACKNOWLEDGEMENT_JSON ;
211
308
}
212
309
213
- if (isSource ){
310
+ Address receiverAddr = Address .fromString (data .receiver );
311
+
312
+ if (isSource ) {
214
313
String denomOnly = data .denom .substring (denomPrefix .length ());
215
-
216
- if (isNativeAsset (denomOnly )){
314
+
315
+ if (isNativeAsset (denomOnly )) {
217
316
try {
218
- Context .transfer (Address . fromString ( data . receiver ) , data .amount );
317
+ Context .transfer (receiverAddr , data .amount );
219
318
} catch (Exception e ) {
220
319
ack = ICS20Lib .FAILED_ACKNOWLEDGEMENT_JSON ;
221
320
}
222
- } else {
321
+ } else {
223
322
try {
224
323
Address tokenContractAddress = getTokenContractAddress (denomOnly );
225
- Context .call (tokenContractAddress , "transfer" , data . receiver , data .amount , data .memo .getBytes ());
324
+ Context .call (tokenContractAddress , "transfer" , receiverAddr , data .amount , data .memo .getBytes ());
226
325
} catch (Exception e ) {
227
326
ack = ICS20Lib .FAILED_ACKNOWLEDGEMENT_JSON ;
228
327
}
229
328
}
230
- }else {
329
+ } else {
231
330
denomPrefix = getDenomPrefix (packetDb .getDestinationPort (), packetDb .getDestinationChannel ());
232
331
String prefixedDenom = denomPrefix + data .denom ;
233
332
234
- // try {
333
+ try {
235
334
Address tokenContractAddress = getTokenContractAddress (prefixedDenom );
236
- System .out .println ("ancgea" );
237
- Context .call (tokenContractAddress , "mint" , data .receiver , data .amount );
238
- System .out .println ("ancgea" );
239
- // }catch (Exception e){
240
- // ack = ICS20Lib.FAILED_ACKNOWLEDGEMENT_JSON;
241
- // }
335
+ Context .call (tokenContractAddress , "mint" , receiverAddr , data .amount );
336
+ } catch (Exception e ) {
337
+ ack = ICS20Lib .FAILED_ACKNOWLEDGEMENT_JSON ;
338
+ }
242
339
}
243
340
244
341
return ack ;
245
342
}
246
343
344
+ /**
345
+ * Handles the acknowledgement of a packet.
346
+ *
347
+ * @param packet the packet being acknowledged
348
+ * @param acknowledgement the acknowledgement received
349
+ * @param relayer the relayer of the packet
350
+ */
247
351
@ External
248
352
public void onAcknowledgementPacket (byte [] packet , byte [] acknowledgement , Address relayer ) {
249
353
onlyIBC ();
@@ -253,79 +357,137 @@ public void onAcknowledgementPacket(byte[] packet, byte[] acknowledgement, Addre
253
357
}
254
358
}
255
359
360
+ /**
361
+ * Handles the timeout of a packet by refunding the tokens associated with the
362
+ * packet.
363
+ *
364
+ * @param packet the encoded packet data
365
+ * @param relayer the address of the relayer
366
+ */
256
367
@ External
257
368
public void onTimeoutPacket (byte [] packet , Address relayer ) {
258
369
Packet packetDb = Packet .decode (packet );
259
370
refundTokens (packetDb );
260
371
}
261
372
373
+ /**
374
+ * Initializes the channel opening process.
375
+ *
376
+ * @param order the order of the channel
377
+ * @param connectionHops the connection hops for the channel
378
+ * @param portId the port ID for the channel
379
+ * @param channelId the channel ID
380
+ * @param counterpartyPb the counterparty information
381
+ * @param version the version of the channel
382
+ */
262
383
@ External
263
384
public void onChanOpenInit (int order , String [] connectionHops , String portId , String channelId ,
264
385
byte [] counterpartyPb , String version ) {
265
386
onlyIBC ();
266
- Context .require (order == Channel .Order .ORDER_UNORDERED , TAG + " : must be unordered" );
267
- Context .require (version .equals (ICS20_VERSION ), TAG + " : version should be same with ICS20_VERSION" );
387
+ Context .require (order == Channel .Order .ORDER_UNORDERED , TAG + " : must be unordered" );
388
+ Context .require (version .equals (ICS20_VERSION ), TAG + " : version should be same with ICS20_VERSION" );
268
389
Channel .Counterparty counterparty = Channel .Counterparty .decode (counterpartyPb );
269
390
destinationPort .set (channelId , counterparty .getPortId ());
270
391
}
271
392
393
+ /**
394
+ * Channel Opening Process
395
+ *
396
+ * @param order the order of the channel
397
+ * @param connectionHops an array of connection hops
398
+ * @param portId the port ID
399
+ * @param channelId the channel ID
400
+ * @param counterpartyPb the counterparty in protobuf format
401
+ * @param version the version
402
+ * @param counterPartyVersion the counterparty version
403
+ */
272
404
@ External
273
405
public void onChanOpenTry (int order , String [] connectionHops , String portId , String channelId ,
274
406
byte [] counterpartyPb , String version , String counterPartyVersion ) {
275
407
onlyIBC ();
276
- Context .require (order == Channel .Order .ORDER_UNORDERED , TAG +" : must be unordered" );
277
- Context .require (counterPartyVersion .equals (ICS20_VERSION ), TAG +" : version should be same with ICS20_VERSION" );
408
+ Context .require (order == Channel .Order .ORDER_UNORDERED , TAG + " : must be unordered" );
409
+ Context .require (counterPartyVersion .equals (ICS20_VERSION ),
410
+ TAG + " : version should be same with ICS20_VERSION" );
278
411
Channel .Counterparty counterparty = Channel .Counterparty .decode (counterpartyPb );
279
412
destinationPort .set (channelId , counterparty .getPortId ());
280
413
destinationChannel .set (channelId , counterparty .getChannelId ());
281
414
}
282
415
416
+ /**
417
+ * Handles the acknowledged by the counterparty.
418
+ *
419
+ * @param portId the identifier of the port on this chain
420
+ * @param channelId the identifier of the channel that was opened
421
+ * @param counterpartyChannelId the identifier of the channel on the
422
+ * counterparty chain
423
+ * @param counterPartyVersion the version of the ICS20 protocol used by the
424
+ * counterparty
425
+ */
283
426
@ External
284
427
public void onChanOpenAck (String portId , String channelId , String counterpartyChannelId ,
285
428
String counterPartyVersion ) {
286
429
onlyIBC ();
287
- Context .require (counterPartyVersion .equals (ICS20_VERSION ), TAG +" : version should be same with ICS20_VERSION" );
430
+ Context .require (counterPartyVersion .equals (ICS20_VERSION ),
431
+ TAG + " : version should be same with ICS20_VERSION" );
288
432
destinationChannel .set (channelId , counterpartyChannelId );
289
433
}
290
-
434
+
435
+ /**
436
+ * Handles the confirmation of a channel.
437
+ *
438
+ * @param portId the identifier of the port on this chain
439
+ * @param channelId the identifier of the channel that was opened
440
+ */
291
441
@ External
292
442
public void onChanOpenConfirm (String portId , String channelId ) {
293
443
onlyIBC ();
294
444
}
295
445
296
-
446
+ /**
447
+ * Handles the closure of a channel.
448
+ *
449
+ * @param portId the identifier of the port on this chain
450
+ * @param channelId the identifier of the channel that was opened
451
+ */
297
452
@ External
298
453
public void onChanCloseInit (String portId , String channelId ) {
299
- Context .revert ( TAG + " : Not Allowed" );
454
+ Context .revert (TAG + " : Not Allowed" );
300
455
}
301
456
457
+ /**
458
+ * Handles the closing of a channel.
459
+ *
460
+ * @param portId the identifier of the port on this chain
461
+ * @param channelId the identifier of the channel that was opened
462
+ */
302
463
@ External
303
464
public void onChanCloseConfirm (String portId , String channelId ) {
304
465
onlyIBC ();
305
466
}
306
467
468
+ /**
469
+ * Refunds tokens based on the provided packet.
470
+ *
471
+ * @param packet the packet containing the token data
472
+ */
307
473
private void refundTokens (Packet packet ) {
308
474
ICS20Lib .FungibleTokenPacketData data = ICS20Lib .unmarshalFungibleTokenPacketData (packet .getData ());
309
475
310
476
String denomPrefix = getDenomPrefix (packet .getSourcePort (), packet .getSourceChannel ());
311
477
boolean isSource = !data .denom .startsWith (denomPrefix );
312
- System .out .println ("denomPrefix: " + denomPrefix + " data.denom: " + data .denom + " isSource: " + isSource );
313
478
314
479
Address sender = Address .fromString (data .sender );
315
480
316
- if (isSource ){
317
- if (isNativeAsset (data .denom )){
481
+ if (isSource ) {
482
+ if (isNativeAsset (data .denom )) {
318
483
Context .transfer (sender , data .amount );
319
484
return ;
320
485
}
321
486
322
487
Address tokenContractAddress = getTokenContractAddress (data .denom );
323
- System .out .println ("native asset done" +sender .toString ()+"," +data .amount .toString ()+"," +tokenContractAddress .toString ()+"," + data .memo );
324
488
Context .call (tokenContractAddress , "transfer" , sender , data .amount , data .memo .getBytes ());
325
- }
326
- else {
489
+ } else {
327
490
Address tokenContractAddress = getTokenContractAddress (data .denom );
328
- System .out .println ("native asset done" +sender .toString ()+"," +data .amount .toString ()+"," +tokenContractAddress .toString ());
329
491
Context .call (tokenContractAddress , "mint" , sender , data .amount );
330
492
}
331
493
}
@@ -335,11 +497,11 @@ private static String getDenomPrefix(String port, String channel) {
335
497
}
336
498
337
499
private void onlyAdmin () {
338
- Context .require (Context .getCaller ().equals (admin .get ()), TAG + " : Caller is not admin" );
500
+ Context .require (Context .getCaller ().equals (admin .get ()), TAG + " : Caller is not admin" );
339
501
}
340
502
341
503
private void onlyIBC () {
342
- Context .require (Context .getCaller ().equals (getIBCAddress ()), TAG + " : Caller is not IBC Contract" );
504
+ Context .require (Context .getCaller ().equals (getIBCAddress ()), TAG + " : Caller is not IBC Contract" );
343
505
}
344
506
345
507
private boolean isNativeAsset (String denom ) {
0 commit comments