Skip to content

Commit

Permalink
feat: icon bridge migration
Browse files Browse the repository at this point in the history
  • Loading branch information
izyak committed Apr 18, 2024
1 parent e6dc465 commit 076338f
Show file tree
Hide file tree
Showing 4 changed files with 1,034 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,20 @@ public BigInteger getSn() {
return sn.get();
}

/**
* Transfer ownership of token contract to somewhere else
*
* @param _name Reegistered name of the token
* @param to New owner
*/
@External
public void transferOwnership(String _name, Address to) {
requireOwnerAccess();
Address tokenAddr = coinAddresses.get(_name);
Context.require(tokenAddr != null, "Token not registered");
Context.call(ZERO_SCORE_ADDRESS, "setScoreOwner", tokenAddr, to);
}

/**
* Add users to blacklist on certain networks
* Maintains information of all addresses blacklisted on all chains
Expand Down Expand Up @@ -484,6 +498,12 @@ public void tokenFallback(Address _from, BigInteger _value, byte[] _data) {
checkUintLimit(_value);
String _coinName = coinAddressName.get(Context.getCaller());
if (_coinName != null && !Context.getAddress().equals(_from)) {

// icon bridge migration checks
requireNotEth(_coinName);
Coin coin = coinDb.get(name);
require(coin.getCoinType() == NATIVE_WRAPPED_COIN_TYPE, "Cannnot transfer icon tokens anymore.");

Context.require(coinAddresses.get(_coinName) != null, "CoinNotExists");
Balance _userBalance = getBalance(_coinName, _from);
_userBalance.setUsable(_userBalance.getUsable().add(_value));
Expand Down Expand Up @@ -547,6 +567,10 @@ public void reclaim(String _coinName, BigInteger _value) {
@Payable
@External
public void transferNativeCoin(String _to) {

// icon bridge migration checks
Context.revert("Cannot transfer ICX.");

Context.require(_to.length() < 100, "Length Check");

BigInteger value = Context.getValue();
Expand Down Expand Up @@ -580,6 +604,11 @@ public void transfer(String _coinName, BigInteger _value, String _to) {
require(isRegistered(_coinName), "Not supported Token");
Context.require(_to.length() < 100, "Length Check");

// icon bridge migration checks
requireNotEth(_coinName);
Coin coin = coinDb.get(_coinName);
require(coin.getCoinType() == NATIVE_WRAPPED_COIN_TYPE, "Cannnot transfer icon tokens anymore.");

Address owner = Context.getCaller();
BTPAddress to = BTPAddress.valueOf(_to);
checkRestrictions(_coinName, Context.getCaller().toString(), to, _value);
Expand Down Expand Up @@ -613,6 +642,7 @@ public void transferBatch(String[] _coinNames, BigInteger[] _values, String _to)

int tempLen = len;
if (icxValue != null && icxValue.compareTo(BigInteger.ZERO) > 0) {
Context.revert("Cannot transfer ICX.");
tempLen = tempLen + 1;
checkTokenLimit(name, icxValue);
coinNameList.add(name);
Expand All @@ -629,6 +659,12 @@ public void transferBatch(String[] _coinNames, BigInteger[] _values, String _to)
for (int i = 0; i < len; i++) {
String coinName = _coinNames[i];
BigInteger value = _values[i];

// icon bridge migration checks
requireNotEth(coinName);
Coin coin = coinDb.get(coinName);
require(coin.getCoinType() == NATIVE_WRAPPED_COIN_TYPE, "Cannnot transfer icon tokens anymore.");

require(!name.equals(coinName) && this.coinNames.contains(coinName), "Not supported Token");
require(value != null && value.compareTo(BigInteger.ZERO) > 0, "Invalid amount");
checkUintLimit(value);
Expand All @@ -637,6 +673,8 @@ public void transferBatch(String[] _coinNames, BigInteger[] _values, String _to)
checkTokenLimit(coinName, value);
}

System.out.println("yaha aayo?");

transferFromBatch(owner, Context.getAddress(), _coinNames, _values);

sendRequest(owner, to, coinNameList, values);
Expand Down Expand Up @@ -1501,4 +1539,8 @@ private void checkUintLimit(BigInteger value) {
require(UINT_CAP.compareTo(value) >= 0, "Value cannot exceed uint(256)-1");
}

private void requireNotEth(String name) {
String ethName = "btp-0x38.bsc-eth";
require(!name.equals(ethName), "NotETH");
}
}
198 changes: 198 additions & 0 deletions javascore/bts/src/test/java/foundation/icon/btp/bts/BTSTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.function.Executable;
Expand Down Expand Up @@ -281,6 +282,7 @@ public void operationsOnUnRegisteredToken() {

@Test
@Order(7)
@Disabled
public void operationOnRegisteredTokens() {
register();

Expand All @@ -298,6 +300,7 @@ public void operationOnRegisteredTokens() {

@Test
@Order(8)
@Disabled
public void reclaimDepositedTokens() {
// for IRC2 tokens
register();
Expand Down Expand Up @@ -338,6 +341,7 @@ public void reclaimDepositedTokens() {

@Test
@Order(9)
@Disabled
public void transferNativeCoin() {
sendBTPMessageMock();
String btpAddress = generateBTPAddress(METACHAIN, owner.getAddress().toString());
Expand Down Expand Up @@ -381,6 +385,7 @@ public void transferNativeCoin() {

@Test
@Order(9)
@Disabled
public void transferNativeCoinResponse() {
sendBTPMessageMock();
String btpAddress = generateBTPAddress(METACHAIN, owner.getAddress().toString());
Expand Down Expand Up @@ -451,6 +456,7 @@ public void transferNativeCoinResponse() {

@Test
@Order(10)
@Disabled
public void transfer() {
String btpaddr = generateBTPAddress("harmony", ETH_ADDR);

Expand Down Expand Up @@ -488,6 +494,7 @@ public void transfer() {

@Test
@Order(10)
@Disabled
public void transferResponseBack() {
sendBTPMessageMock();
String btpAddress = generateBTPAddress(METACHAIN, owner.getAddress().toString());
Expand Down Expand Up @@ -559,6 +566,7 @@ public void transferResponseBack() {

@Test
@Order(11)
@Disabled
public void transferBatch() {
String[] coinNames = new String[]{"Token1", "Token2", "Token3", "Token4", PARA};
BigInteger val = BigInteger.valueOf(10);
Expand Down Expand Up @@ -718,6 +726,7 @@ public void handleBTPMessage1() {

@Test
@Order(13)
@Disabled
public void handleBTPMessage2() {

// request plus response
Expand Down Expand Up @@ -1086,6 +1095,7 @@ public void coinDetails() {

@Test
@Order(20)
@Disabled
public void transferBatchNativecoinTokenLimit() {
tokenLimitBTPMessage();
score.invoke(owner, "setTokenLimit", new String[]{ICON}, new BigInteger[]{BigInteger.valueOf(1000)});
Expand Down Expand Up @@ -1121,6 +1131,7 @@ public void transferBatchNativecoinTokenLimit() {

@Test
@Order(20)
@Disabled
public void handleFeeGathering() {
String feeAggregator = generateBTPAddress("icon", "hx0000000000000000000000000000000000000000");

Expand Down Expand Up @@ -1301,4 +1312,191 @@ void setTokenLimitResponse() {
assertEquals( true, score.call("tokenLimitStatus", "icon", ICON));
assertEquals( true, score.call("tokenLimitStatus", "icon", PARA));
}

// ICON BRIDGE MIGRATION TESTS

@Test
public void preventICXTransfer() {
sendBTPMessageMock();
String btpAddress = generateBTPAddress(METACHAIN, owner.getAddress().toString());
// general condition
contextMock.when(sendICX()).thenReturn(BigInteger.valueOf(100));

Executable call = () -> score.invoke(owner, "transferNativeCoin", btpAddress);
expectErrorMessage(call, "Reverted(0): Cannot transfer ICX.");
}

@Test
@Disabled
public void preventIconTokenTransfer() {
sendBTPMessageMock();
String btpaddr = generateBTPAddress(METACHAIN, owner.getAddress().toString());

register();

// should not transfer native-coin
Executable call = () -> score.invoke(nonOwner, "transfer", TEST_TOKEN, BigInteger.TEN, btpaddr);
expectErrorMessage(call, "Cannnot transfer icon tokens anymore.");

}

@Test
public void preventEthTokenTransfer() {
sendBTPMessageMock();
String btpaddr = generateBTPAddress(METACHAIN, owner.getAddress().toString());

String tokenName = "btp-0x38.bsc-eth";

Verification deployWrappedToken = () -> Context.deploy(any(), eq(tokenName),
eq(tokenName),eq(18));
contextMock.when(deployWrappedToken).thenReturn(wrappedIRC2.getAddress());

score.invoke(owner, "register",tokenName, tokenName, 18, BigInteger.ZERO, BigInteger.TWO,
Address.fromString("cx0000000000000000000000000000000000000000"));


// should not transfer native-coin
Executable call = () -> score.invoke(nonOwner, "transfer", tokenName, BigInteger.TEN, btpaddr);
expectErrorMessage(call, "NotETH");

}

@Test
public void migrationRestrictionOnTransferBatch_includeICX() {

String[] coinNames = new String[]{"Token1", "Token2", "Token3", "Token4", PARA};
BigInteger val = BigInteger.valueOf(10);
BigInteger[] values = new BigInteger[]{val, val, val, val, val};
String destination = generateBTPAddress("harmony", ETH_ADDR);

Verification sendMessage = () -> Context.call(eq(bmcMock.getAddress()), eq("sendMessage"), eq("harmony"),
eq("bts"), eq(BigInteger.ONE), any());
contextMock.when(sendMessage).thenReturn(null);


contextMock.when(sendICX()).thenReturn(BigInteger.valueOf(100));

// register tokens
Account token1 = Account.newScoreAccount(10);
Account token2 = Account.newScoreAccount(11);
Account token3 = Account.newScoreAccount(12);
Account token4 = Account.newScoreAccount(13);

// register irc2 token
register(coinNames[0], token1.getAddress());
register(coinNames[1], token2.getAddress());
register(coinNames[2], token3.getAddress());
register(coinNames[3], token4.getAddress());


Executable call = () -> score.invoke(nonOwner, "transferBatch", coinNames, values, destination);
expectErrorMessage(call, "Reverted(0): Cannot transfer ICX.");

}

@Test
public void migrationRestrictionOnTransferBatch_includeETHTokens() {
String tokenName = "btp-0x38.bsc-eth";

String[] coinNames = new String[]{tokenName,"Token1", "Token2", "Token3", "Token4", PARA};
BigInteger val = BigInteger.valueOf(10);
BigInteger[] values = new BigInteger[]{val, val, val, val, val, val};
String destination = generateBTPAddress("harmony", ETH_ADDR);

Verification sendMessage = () -> Context.call(eq(bmcMock.getAddress()), eq("sendMessage"), eq("harmony"),
eq("bts"), eq(BigInteger.ONE), any());
contextMock.when(sendMessage).thenReturn(null);


// register tokens
Account token1 = Account.newScoreAccount(10);
Account token2 = Account.newScoreAccount(11);
Account token3 = Account.newScoreAccount(12);
Account token4 = Account.newScoreAccount(13);

// register irc2 token
register(coinNames[1], token1.getAddress());
register(coinNames[2], token2.getAddress());
register(coinNames[3], token3.getAddress());
register(coinNames[4], token4.getAddress());

Verification deployWrappedToken = () -> Context.deploy(any(), eq(tokenName),
eq(tokenName),eq(18));
contextMock.when(deployWrappedToken).thenReturn(wrappedIRC2.getAddress());

score.invoke(owner, "register",tokenName, tokenName, 18, BigInteger.ZERO, BigInteger.TWO,
Address.fromString("cx0000000000000000000000000000000000000000"));


Executable call = () -> score.invoke(nonOwner, "transferBatch", coinNames, values, destination);
expectErrorMessage(call, "NotETH");
}

@Test
public void migrationRestrictionOnTransferBatch_includeWrappedTokensOnly() {
String tokenName = "META";

String[] coinNames = new String[]{tokenName, PARA};
BigInteger val = BigInteger.valueOf(10);
BigInteger[] values = new BigInteger[]{val, val};
String destination = generateBTPAddress("harmony", ETH_ADDR);

Verification sendMessage = () -> Context.call(eq(bmcMock.getAddress()), eq("sendMessage"), eq("harmony"),
eq("bts"), eq(BigInteger.ONE), any());
contextMock.when(sendMessage).thenReturn(null);

registerWrapped();

Verification deployWrappedToken = () -> Context.deploy(any(), eq(tokenName),
eq(tokenName),eq(18));
contextMock.when(deployWrappedToken).thenReturn(wrappedIRC2.getAddress());

score.invoke(owner, "register",tokenName, tokenName, 18, BigInteger.ZERO, BigInteger.TWO,
Address.fromString("cx0000000000000000000000000000000000000000"));

// PARA and META registered

Verification transferFromMock = () -> Context.call(eq(Boolean.class), any(), eq("transferFrom"),
eq(nonOwner.getAddress()), eq(score.getAddress()), eq(BigInteger.valueOf(10)), any());
contextMock.when(transferFromMock).thenReturn(true);


score.invoke(nonOwner, "transferBatch", coinNames, values, destination);
}

@Test
public void migrationRestrictionOnTransferBatch_includeIconTokens() {

String[] coinNames = new String[]{"Token1", "Token2", "Token3", "Token4", PARA};
BigInteger val = BigInteger.valueOf(10);
BigInteger[] values = new BigInteger[]{val, val, val, val, val};
String destination = generateBTPAddress("harmony", ETH_ADDR);

Verification sendMessage = () -> Context.call(eq(bmcMock.getAddress()), eq("sendMessage"), eq("harmony"),
eq("bts"), eq(BigInteger.ONE), any());
contextMock.when(sendMessage).thenReturn(null);


// register tokens
Account token1 = Account.newScoreAccount(10);
Account token2 = Account.newScoreAccount(11);
Account token3 = Account.newScoreAccount(12);
Account token4 = Account.newScoreAccount(13);

// register irc2 token
register(coinNames[0], token1.getAddress());
register(coinNames[1], token2.getAddress());
register(coinNames[2], token3.getAddress());
register(coinNames[3], token4.getAddress());


Executable call = () -> score.invoke(nonOwner, "transferBatch", coinNames, values, destination);
expectErrorMessage(call, "Cannnot transfer icon tokens anymore.");
}






}
Loading

0 comments on commit 076338f

Please sign in to comment.