diff --git a/.gitignore b/.gitignore index e4d77b966..81967d29c 100644 --- a/.gitignore +++ b/.gitignore @@ -82,4 +82,4 @@ fabric.properties # Ignore Gradle build output directory build .DS_Store -.vscode \ No newline at end of file +.vscode diff --git a/core-contracts/BatchDisbursement/build.gradle b/core-contracts/BatchDisbursement/build.gradle new file mode 100644 index 000000000..3917ae5b2 --- /dev/null +++ b/core-contracts/BatchDisbursement/build.gradle @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2022-2022 Balanced.network. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +version = '0.1.0' + +repositories { + // Use Maven Central for resolving dependencies. + mavenCentral() +} + +dependencies { + compileOnly 'foundation.icon:javaee-api:0.9.1' + implementation 'foundation.icon:javaee-scorex:0.5.2' + + testImplementation 'com.github.sink772:javaee-tokens:0.6.1' + testImplementation 'foundation.icon:javaee-unittest:0.9.2' + // Use JUnit Jupiter for testing. + testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' + testImplementation 'org.mockito:mockito-core:4.1.0' +} + +optimizedJar { + mainClassName = 'network.balanced.score.core.batchDisbursement.BatchDisbursement' + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + from { + configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } + } + enableDebug = false +} + +deployJar { + endpoints { + sejong { + uri = 'https://sejong.net.solidwallet.io/api/v3' + nid = 0x53 + to = "cx3ddc7e3599d270cfa65cc933e1a3487f11f6b6f6" + } + local { + uri = 'http://localhost:9082/api/v3' + nid = 0x3 + } + mainnet { + uri = 'https://ctz.solidwallet.io/api/v3' + nid = 0x1 + } + } + keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : '' + password = rootProject.hasProperty('keystorePass') ? "$keystorePass" : '' + parameters { arg('_governance', "cxdeeabbbdd77a3f648cf4ce4a5f3d4bdd1e3833b3") } +} + +tasks.named('test') { + // Use JUnit Platform for unit tests. + useJUnitPlatform() +} diff --git a/core-contracts/BatchDisbursement/src/main/java/network/balanced/score/core/batchDisbursement/BatchDisbursement.java b/core-contracts/BatchDisbursement/src/main/java/network/balanced/score/core/batchDisbursement/BatchDisbursement.java new file mode 100644 index 000000000..8588025eb --- /dev/null +++ b/core-contracts/BatchDisbursement/src/main/java/network/balanced/score/core/batchDisbursement/BatchDisbursement.java @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2022-2022 Balanced.network. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package network.balanced.score.core.batchDisbursement; + +import score.*; +import score.annotation.EventLog; +import score.annotation.External; +import scorex.util.HashMap; + +import java.math.BigInteger; +import java.util.Map; + +import static network.balanced.score.core.batchDisbursement.Checks.onlyGovernance; +import static network.balanced.score.core.batchDisbursement.Checks.onlyOwner; + +public class BatchDisbursement { + + public static final VarDB
governance = Context.newVarDB("governance", Address.class); + public final BranchDB> userClaimableTokens = Context.newBranchDB( + "user_claimable_tokens", BigInteger.class); + public final VarDB
daofund = Context.newVarDB("daofund", Address.class); + public final VarDB
reserveFund = Context.newVarDB("reserve_fund", Address.class); + public final EnumerableSetDB
allowedTokenAddress = new EnumerableSetDB<>("allowed_token_address", + Address.class); + + public static final String TAG = "BatchDisbursement"; + + public BatchDisbursement(Address _governance) { + Context.require(_governance.isContract(), TAG + ": Governance address should be a contract"); + governance.set(_governance); + } + + public static class Disbursement { + public Address tokenAddress; + public BigInteger tokenAmount; + } + + public static class DisbursementRecipient { + public Address recipient; + public Disbursement[] disbursement; + } + + /* + * Event Logs + */ + + @EventLog(indexed = 1) + public void Claim(Address user, Address tokenAddress, BigInteger amount) { + } + + @EventLog(indexed = 1) + protected void TokenTransfer(Address recipient, BigInteger amount, String note) { + } + + /* + * Setters and getters + */ + @External(readonly = true) + public String name() { + return "Balanced Batch Disbursement"; + } + + @External + public void setGovernance(Address _address) { + onlyOwner(); + Context.require(_address.isContract(), TAG + ": Address provided is an EOA Address. Contract address required"); + governance.set(_address); + } + + @External(readonly = true) + public Address getGovernance() { + return governance.get(); + } + + @External + public void setDaofund(Address _address) { + onlyOwner(); + Context.require(_address.isContract(), TAG + ": Address provided is an EOA Address. Contract address required"); + daofund.set(_address); + } + + @External(readonly = true) + public Address getDaofund() { + return daofund.get(); + } + + @External + public void setReserveFund(Address _address) { + onlyOwner(); + Context.require(_address.isContract(), TAG + ": Address provided is an EOA Address. Contract address required"); + reserveFund.set(_address); + } + + @External(readonly = true) + public Address getReserveFund() { + return reserveFund.get(); + } + + @External(readonly = true) + public Map getTokenBalances() { + Map balances = new HashMap<>(); + for (int arrayIndex = 0; arrayIndex < allowedTokenAddress.length(); arrayIndex++) { + Address tokenAddress = allowedTokenAddress.at(arrayIndex); + BigInteger balance = (BigInteger) Context.call(tokenAddress, "balanceOf", Context.getAddress()); + balances.put(tokenAddress.toString(), balance); + } + return balances; + } + + @External + public void uploadDisbursementData(DisbursementRecipient[] disbursementRecipients) { + onlyOwner(); + + for (DisbursementRecipient disbursementRecipient : disbursementRecipients) { + Address user = disbursementRecipient.recipient; + DictDB userTokens = userClaimableTokens.at(user); + for (Disbursement disbursement : disbursementRecipient.disbursement) { + Address token = disbursement.tokenAddress; + BigInteger currentAmount = userTokens.getOrDefault(token, BigInteger.ZERO); + userTokens.set(disbursement.tokenAddress, currentAmount.add(disbursement.tokenAmount)); + } + } + } + + @External(readonly = true) + public Map getDisbursementDetail(Address _user) { + + Map userClaimableTokens = new HashMap<>(); + DictDB userTokens = this.userClaimableTokens.at(_user); + + for (int arrayIndex = 0; arrayIndex < allowedTokenAddress.length(); arrayIndex++) { + Address token = allowedTokenAddress.at(arrayIndex); + BigInteger tokenAmount = userTokens.getOrDefault(token, BigInteger.ZERO); + userClaimableTokens.put(token.toString(), tokenAmount); + } + return Map.of("user", _user, "claimableTokens", userClaimableTokens); + } + + @External + public void claim() { + Address sender = Context.getCaller(); + DictDB userTokens = userClaimableTokens.at(sender); + + for (int arrayIndex = 0; arrayIndex < allowedTokenAddress.length(); arrayIndex++) { + Address token = allowedTokenAddress.at(arrayIndex); + BigInteger tokenAmount = userTokens.getOrDefault(token, BigInteger.ZERO); + if (tokenAmount != null && tokenAmount.signum() > 0) { + userTokens.set(token, BigInteger.ZERO); + sendToken(token, sender, tokenAmount, TAG + ": tokens claimed"); + Claim(sender, token, tokenAmount); + } + } + } + + @External + public void batchDisburse(Address _source) { + onlyGovernance(); + Context.call(_source, "claim"); + } + + @External + public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { + Address tokenContract = Context.getCaller(); + + Context.require(_from.equals(getDaofund()) || _from.equals(getReserveFund()), TAG+ ": Only receivable from " + + "daofund or reserve contract"); + if (!allowedTokenAddress.contains(tokenContract)) { + allowedTokenAddress.add(tokenContract); + } + } + + private void sendToken(Address tokenAddress, Address to, BigInteger amount, String message) { + try { + Context.call(tokenAddress, "transfer", to, amount, new byte[0]); + TokenTransfer(to, amount, message + ": " + amount + "" + tokenAddress + " tokens sent to " + to); + } catch (Exception e) { + Context.println(e.getMessage()); + Context.revert(TAG + ": Error in sending tokens to user- " + to); + } + } + +} diff --git a/core-contracts/BatchDisbursement/src/main/java/network/balanced/score/core/batchDisbursement/Checks.java b/core-contracts/BatchDisbursement/src/main/java/network/balanced/score/core/batchDisbursement/Checks.java new file mode 100644 index 000000000..9ccb6d421 --- /dev/null +++ b/core-contracts/BatchDisbursement/src/main/java/network/balanced/score/core/batchDisbursement/Checks.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022-2022 Balanced.network. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package network.balanced.score.core.batchDisbursement; + +import score.Address; +import score.Context; + +public class Checks { + public static Address defaultAddress = new Address(new byte[Address.LENGTH]); + + public static void onlyOwner() { + Address caller = Context.getCaller(); + Address owner = Context.getOwner(); + Context.require(caller.equals(owner), "SenderNotScoreOwner: Sender=" + caller + "Owner=" + owner); + } + + public static void onlyGovernance() { + Address sender = Context.getCaller(); + Address governance = BatchDisbursement.governance.getOrDefault(defaultAddress); + Context.require(!governance.equals(defaultAddress), BatchDisbursement.TAG + ": Governance address not set"); + Context.require(sender.equals(governance), BatchDisbursement.TAG + ": Sender not governance contract"); + } +} diff --git a/core-contracts/BatchDisbursement/src/main/java/network/balanced/score/core/batchDisbursement/EnumerableSetDB.java b/core-contracts/BatchDisbursement/src/main/java/network/balanced/score/core/batchDisbursement/EnumerableSetDB.java new file mode 100644 index 000000000..fb612e250 --- /dev/null +++ b/core-contracts/BatchDisbursement/src/main/java/network/balanced/score/core/batchDisbursement/EnumerableSetDB.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2022-2022 Balanced.network. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package network.balanced.score.core.batchDisbursement; + +import score.ArrayDB; +import score.Context; +import score.DictDB; + +public class EnumerableSetDB { + private final ArrayDB entries; + private final DictDB indexes; + + public EnumerableSetDB(String varKey, Class valueClass) { + // array of valueClass + this.entries = Context.newArrayDB(varKey + "_es_entries", valueClass); + // value => array index + this.indexes = Context.newDictDB(varKey + "_es_index", Integer.class); + } + + public int length() { + return entries.size(); + } + + public V at(int index) { + return entries.get(index); + } + + public boolean contains(V value) { + return indexes.get(value) != null; + } + + public Integer indexOf(V value) { + // returns null if value doesn't exist + Integer result = indexes.get(value); + if (result != null) { + return result - 1; + } + return null; + } + + public void add(V value) { + if (!contains(value)) { + //add new value + entries.add(value); + indexes.set(value, entries.size()); + } + } + + public V remove(V value) { + Integer valueIndex = indexOf(value); + + if (valueIndex != null) { + int lastIndex = entries.size(); + V lastValue = entries.pop(); + indexes.set(value, null); + if (lastIndex != valueIndex) { + entries.set(valueIndex - 1, lastValue); + indexes.set(lastValue, valueIndex); + return lastValue; + } + } + return null; + } +} \ No newline at end of file diff --git a/core-contracts/BatchDisbursement/src/test/java/network/balanced/score/core/batchDisbursement/BatchDisbursementTest.java b/core-contracts/BatchDisbursement/src/test/java/network/balanced/score/core/batchDisbursement/BatchDisbursementTest.java new file mode 100644 index 000000000..3219f8fed --- /dev/null +++ b/core-contracts/BatchDisbursement/src/test/java/network/balanced/score/core/batchDisbursement/BatchDisbursementTest.java @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2022-2022 Balanced.network. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package network.balanced.score.core.batchDisbursement; + +import com.iconloop.score.test.Account; +import com.iconloop.score.test.Score; +import com.iconloop.score.test.ServiceManager; +import com.iconloop.score.test.TestBase; +import com.iconloop.score.token.irc2.IRC2Mintable; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.function.Executable; +import score.Address; + +import java.lang.reflect.InvocationTargetException; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class BatchDisbursementTest extends TestBase { + + public static final ServiceManager sm = getServiceManager(); + public static final Account owner = sm.createAccount(); + public static final Account governanceScore = Account.newScoreAccount(1); + + private Score batchDisbursement; + private Score balnTokenScore; + private Score daofundScore; + private Score reserveFundScore; + + List recipients = new ArrayList<>(); + + public static class BalnToken extends IRC2Mintable { + public BalnToken(String _name, String _symbol, int _decimals) { + super(_name, _symbol, _decimals); + } + } + + private void expectErrorMessage(Executable contractCall, String expectedErrorMessage) { + AssertionError e = Assertions.assertThrows(AssertionError.class, contractCall); + assertEquals(expectedErrorMessage, e.getMessage()); + } + + @BeforeEach + void setUp() throws Exception { + batchDisbursement = sm.deploy(owner, BatchDisbursement.class, governanceScore.getAddress()); + assert (batchDisbursement.getAddress().isContract()); + + balnTokenScore = sm.deploy(owner, BalnToken.class, "Balanced Token", "BALN", 18); + assert (balnTokenScore.getAddress().isContract()); + + daofundScore = sm.deploy(owner, MockDaofund.class, balnTokenScore.getAddress()); + assert (daofundScore.getAddress().isContract()); + + reserveFundScore = sm.deploy(owner, MockReserve.class, balnTokenScore.getAddress()); + assert (reserveFundScore.getAddress().isContract()); + + balnTokenScore.invoke(owner, "mintTo", daofundScore.getAddress(), BigInteger.TEN.pow(23)); + balnTokenScore.invoke(owner, "mintTo", reserveFundScore.getAddress(), BigInteger.TEN.pow(23)); + + for (int i = 0; i < 10; i++) { + recipients.add(sm.createAccount()); + } + } + + @Test + @DisplayName("Deployment with non contract address") + void testDeploy() { + Account notContract = sm.createAccount(); + Executable deploymentWithNonContract = () -> sm.deploy(owner, BatchDisbursement.class, + notContract.getAddress()); + + String expectedErrorMessage = "BatchDisbursement: Governance address should be a contract"; + InvocationTargetException e = Assertions.assertThrows(InvocationTargetException.class, + deploymentWithNonContract); + assertEquals(expectedErrorMessage, e.getCause().getMessage()); + } + + @Test + void name() { + String contractName = "Balanced Batch Disbursement"; + assertEquals(contractName, batchDisbursement.call("name")); + } + + @Test + void setAndGetGovernance() { + assertEquals(governanceScore.getAddress(), batchDisbursement.call("getGovernance")); + Address newGovernance = Account.newScoreAccount(2).getAddress(); + batchDisbursement.invoke(owner, "setGovernance", newGovernance); + assertEquals(newGovernance, batchDisbursement.call("getGovernance")); + } + + @Test + void setAndGetDaofund() { + Account nonOwner = sm.createAccount(); + + Executable nonOwnerCall = () -> batchDisbursement.invoke(nonOwner, "setDaofund", daofundScore.getAddress()); + String expectedErrorMessage = + "SenderNotScoreOwner: Sender=" + nonOwner.getAddress() + "Owner=" + owner.getAddress(); + expectErrorMessage(nonOwnerCall, expectedErrorMessage); + + batchDisbursement.invoke(owner, "setDaofund", daofundScore.getAddress()); + assertEquals(daofundScore.getAddress(), batchDisbursement.call("getDaofund")); + } + + @Test + void setAndGetReserveFund() { + batchDisbursement.invoke(owner, "setReserveFund", reserveFundScore.getAddress()); + assertEquals(reserveFundScore.getAddress(), batchDisbursement.call("getReserveFund")); + } + + @Test + void getTokenBalances() { + assertEquals(Map.of(), batchDisbursement.call("getTokenBalances")); + + setAndGetDaofund(); + setAndGetReserveFund(); + + batchDisbursement.invoke(governanceScore, "batchDisburse", daofundScore.getAddress()); + assertEquals(Map.of(balnTokenScore.getAddress().toString(), BigInteger.TEN.pow(22)), batchDisbursement.call( + "getTokenBalances")); + + batchDisbursement.invoke(governanceScore, "batchDisburse", reserveFundScore.getAddress()); + assertEquals(Map.of(balnTokenScore.getAddress().toString(), BigInteger.TEN.pow(22).multiply(BigInteger.TWO)), + batchDisbursement.call("getTokenBalances")); + } + + @Test + void uploadDisbursementData() { + getTokenBalances(); + + BatchDisbursement.DisbursementRecipient[] batchRecipients = new BatchDisbursement.DisbursementRecipient[10]; + BatchDisbursement.Disbursement disbursement = new BatchDisbursement.Disbursement(); + disbursement.tokenAddress = balnTokenScore.getAddress(); + disbursement.tokenAmount = BigInteger.valueOf(500L); + + for (int j = 0; j < 10; j++) { + batchRecipients[j] = new BatchDisbursement.DisbursementRecipient(); + batchRecipients[j].recipient = recipients.get(j).getAddress(); + batchRecipients[j].disbursement = new BatchDisbursement.Disbursement[]{disbursement}; + } + + batchDisbursement.invoke(owner, "uploadDisbursementData", (Object) batchRecipients); + for (int i = 0; i < 10; i++) { + Address expectedRecipient = batchRecipients[i].recipient; + BigInteger expectedAmount = batchRecipients[i].disbursement[0].tokenAmount; + Address expectedTokenAddress = batchRecipients[i].disbursement[0].tokenAddress; + + Map disbursementDetail = (Map) batchDisbursement.call( + "getDisbursementDetail", expectedRecipient); + Address actualRecipient = (Address) disbursementDetail.get("user"); + Map claimableTokens = (Map) disbursementDetail.get( + "claimableTokens"); + BigInteger actualAmount = claimableTokens.get(expectedTokenAddress.toString()); + + assertEquals(expectedRecipient, actualRecipient); + assertEquals(expectedAmount, actualAmount); + } + } + + @Test + void claim() { + uploadDisbursementData(); + + for (int i = 0; i < 10; i++) { + Account user = recipients.get(i); + assertEquals(BigInteger.ZERO, balnTokenScore.call("balanceOf", user.getAddress())); + batchDisbursement.invoke(recipients.get(i), "claim"); + assertEquals(BigInteger.valueOf(500L), balnTokenScore.call("balanceOf", user.getAddress())); + + // Try claiming once more, should not disburse tokens + batchDisbursement.invoke(recipients.get(i), "claim"); + assertEquals(BigInteger.valueOf(500L), balnTokenScore.call("balanceOf", user.getAddress())); + } + } + + @Test + void tokenFallback() { + setAndGetDaofund(); + setAndGetReserveFund(); + + balnTokenScore.invoke(owner, "mint", BigInteger.TEN.pow(25)); + Executable transferFromInvalidAddress = () -> balnTokenScore.invoke(owner, "transfer", + batchDisbursement.getAddress(), BigInteger.TEN.pow(21), new byte[0]); + String expectedErrorMessage = "BatchDisbursement: Only receivable from daofund or reserve contract"; + expectErrorMessage(transferFromInvalidAddress, expectedErrorMessage); + } +} \ No newline at end of file diff --git a/core-contracts/BatchDisbursement/src/test/java/network/balanced/score/core/batchDisbursement/MockDaofund.java b/core-contracts/BatchDisbursement/src/test/java/network/balanced/score/core/batchDisbursement/MockDaofund.java new file mode 100644 index 000000000..7818902c7 --- /dev/null +++ b/core-contracts/BatchDisbursement/src/test/java/network/balanced/score/core/batchDisbursement/MockDaofund.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2022-2022 Balanced.network. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package network.balanced.score.core.batchDisbursement; + +import score.Address; +import score.Context; +import score.VarDB; +import score.annotation.External; + +import java.math.BigInteger; + +public class MockDaofund { + + private VarDB
balnToken = Context.newVarDB("baln_token", Address.class); + + public MockDaofund(Address balnToken) { + this.balnToken.set(balnToken); + } + + @External + public void claim() { + Context.call(balnToken.get(), "transfer", Context.getCaller(), BigInteger.TEN.pow(22), new byte[0]); + } + + @External + public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { + + } +} diff --git a/core-contracts/BatchDisbursement/src/test/java/network/balanced/score/core/batchDisbursement/MockReserve.java b/core-contracts/BatchDisbursement/src/test/java/network/balanced/score/core/batchDisbursement/MockReserve.java new file mode 100644 index 000000000..337c0afdf --- /dev/null +++ b/core-contracts/BatchDisbursement/src/test/java/network/balanced/score/core/batchDisbursement/MockReserve.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2022-2022 Balanced.network. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package network.balanced.score.core.batchDisbursement; + +import score.Address; +import score.Context; +import score.VarDB; +import score.annotation.External; + +import java.math.BigInteger; + +public class MockReserve { + + private VarDB
balnToken = Context.newVarDB("baln_token", Address.class); + + public MockReserve(Address balnToken) { + this.balnToken.set(balnToken); + } + + @External + public void claim() { + Context.call(balnToken.get(), "transfer", Context.getCaller(), BigInteger.TEN.pow(22), new byte[0]); + } + + @External + public void tokenFallback(Address _from, BigInteger _value, byte[] _data) { + + } +} diff --git a/core-contracts/Reserve/src/test/java/network/balanced/score/core/reserve/utils/Loans.java b/core-contracts/Reserve/src/test/java/network/balanced/score/core/reserve/utils/Loans.java index a75bfca81..5c1c93f3c 100644 --- a/core-contracts/Reserve/src/test/java/network/balanced/score/core/reserve/utils/Loans.java +++ b/core-contracts/Reserve/src/test/java/network/balanced/score/core/reserve/utils/Loans.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 Balanced.network. + * Copyright (c) 2022-2022 Balanced.network. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/settings.gradle b/settings.gradle index c6e249a35..33c826004 100644 --- a/settings.gradle +++ b/settings.gradle @@ -26,5 +26,6 @@ rootProject.name = 'balanced-java-contracts' include(':core-contracts:Multicall', + ':core-contracts:BatchDisbursement', ':core-contracts:Reserve', ':token-contracts')