Skip to content

Commit f771d9c

Browse files
authored
Merge pull request #47 from balancednetwork/feature/add-Multicall-contract
New multicall contract
2 parents 9959736 + bc17b4f commit f771d9c

6 files changed

Lines changed: 291 additions & 3 deletions

File tree

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ buildscript {
1919
mavenCentral()
2020
}
2121
dependencies {
22-
classpath 'foundation.icon:gradle-javaee-plugin:0.7.8'
22+
classpath 'foundation.icon:gradle-javaee-plugin:0.8.0'
2323
}
2424
}
2525

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
2+
/*
3+
* Copyright (c) 2022-2022 Balanced.network.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
version = '0.1.0'
19+
20+
repositories {
21+
// Use Maven Central for resolving dependencies.
22+
mavenCentral()
23+
}
24+
25+
dependencies {
26+
compileOnly 'foundation.icon:javaee-api:0.9.1'
27+
implementation 'foundation.icon:javaee-scorex:0.5.2'
28+
29+
testImplementation 'foundation.icon:javaee-unittest:0.9.2'
30+
// Use JUnit Jupiter for testing.
31+
testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1'
32+
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
33+
testImplementation 'org.mockito:mockito-core:4.1.0'
34+
}
35+
36+
optimizedJar {
37+
mainClassName = 'network.balanced.score.core.multicall.Multicall'
38+
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
39+
from {
40+
configurations.runtimeClasspath.collect{it.isDirectory() ? it : zipTree(it)}
41+
}
42+
enableDebug = false
43+
}
44+
45+
deployJar {
46+
endpoints {
47+
sejong {
48+
uri = 'https://sejong.net.solidwallet.io/api/v3'
49+
nid = 0x53
50+
to = "cx75256fadf232ad1124d9c6cd70c9b1ec122a0f47"
51+
}
52+
local {
53+
uri = 'http://localhost:9082/api/v3'
54+
nid = 0x3
55+
}
56+
mainnet {
57+
uri = 'https://ctz.solidwallet.io/api/v3'
58+
nid = 0x1
59+
}
60+
}
61+
keystore = rootProject.hasProperty('keystoreName') ? "$keystoreName" : ''
62+
password = rootProject.hasProperty('keystorePass') ? "$keystorePass" : ''
63+
parameters {}
64+
}
65+
66+
tasks.named('test') {
67+
// Use JUnit Platform for unit tests.
68+
useJUnitPlatform()
69+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright (c) 2022-2022 Balanced.network.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package network.balanced.score.core.multicall;
18+
19+
import score.Address;
20+
import score.Context;
21+
import score.VarDB;
22+
import score.annotation.External;
23+
24+
import java.math.BigInteger;
25+
import java.util.Map;
26+
27+
import scorex.util.HashMap;
28+
29+
public class Multicall {
30+
31+
private final Address defaultAddress = new Address(new byte[Address.LENGTH]);
32+
public final VarDB<Address> dexAddress = Context.newVarDB("dexAddress", Address.class);
33+
public static final String TAG = "Multicall";
34+
35+
public Multicall() {
36+
}
37+
38+
private void onlyOwner() {
39+
Address caller = Context.getCaller();
40+
Address owner = Context.getOwner();
41+
Context.require(caller.equals(owner), TAG + ": Caller is not the owner");
42+
}
43+
44+
@External(readonly = true)
45+
public String name() {
46+
return "Balanced Multicall";
47+
}
48+
49+
@External(readonly = true)
50+
public Address getDexAddress() {
51+
return dexAddress.get();
52+
}
53+
54+
@External
55+
public void setDexAddress(Address dex) {
56+
onlyOwner();
57+
Context.require(dex.isContract(), TAG + ": Dex parameter is not contract address");
58+
this.dexAddress.set(dex);
59+
}
60+
61+
@External(readonly = true)
62+
public Map<String, Object> getPoolStatsForPair(Address _base, Address _quote) {
63+
BigInteger poolId = (BigInteger) Context.call(dexAddress.getOrDefault(defaultAddress), "getPoolId", _base,
64+
_quote);
65+
66+
@SuppressWarnings("unchecked")
67+
Map<String, Object> poolStats = (Map<String, Object>) Context.call(dexAddress.getOrDefault(defaultAddress),
68+
"getPoolStats", poolId);
69+
70+
Map<String, Object> poolStatsWithId = new HashMap<>();
71+
poolStatsWithId.put("id", poolId);
72+
poolStatsWithId.putAll(poolStats);
73+
74+
return poolStatsWithId;
75+
}
76+
77+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright (c) 2022-2022 Balanced.network.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package network.balanced.score.core.multicall;
18+
19+
import score.Address;
20+
import score.annotation.External;
21+
22+
import java.math.BigInteger;
23+
import java.util.Map;
24+
25+
public class DexMock {
26+
27+
@External(readonly = true)
28+
public BigInteger getPoolId(Address _token1Address, Address _token2Address) {
29+
return BigInteger.ONE;
30+
}
31+
32+
@External(readonly = true)
33+
public Map<String, ?> getPoolStats(BigInteger _id) {
34+
return Map.of("base_token", "cx0000000000000000000000000000000000000032",
35+
"quote_token", "None",
36+
"base", 0,
37+
"quote", BigInteger.valueOf(1000L),
38+
"total_supply", BigInteger.valueOf(10000000000000L),
39+
"price", BigInteger.TEN,
40+
"name", "sICX/ICX",
41+
"base_decimals", 18,
42+
"quote_decimals", 18,
43+
"min_quote", BigInteger.TEN);
44+
}
45+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright (c) 2022-2022 Balanced.network.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package network.balanced.score.core.multicall;
18+
19+
import com.iconloop.score.test.Account;
20+
import com.iconloop.score.test.Score;
21+
import com.iconloop.score.test.ServiceManager;
22+
import com.iconloop.score.test.TestBase;
23+
import org.junit.jupiter.api.Assertions;
24+
import org.junit.jupiter.api.BeforeEach;
25+
import org.junit.jupiter.api.Test;
26+
import org.junit.jupiter.api.function.Executable;
27+
import score.Address;
28+
29+
30+
import java.math.BigInteger;
31+
import java.util.Map;
32+
33+
import static org.junit.jupiter.api.Assertions.assertEquals;
34+
import static org.mockito.Mockito.*;
35+
36+
37+
public class MulticallTest extends TestBase {
38+
39+
public static final ServiceManager sm = getServiceManager();
40+
public static final Account owner = sm.createAccount();
41+
42+
private Score multicallScore;
43+
private Score dexMock;
44+
45+
private DexMock dexSpy;
46+
47+
private void expectErrorMessage(Executable contractCall, String expectedErrorMessage) {
48+
AssertionError e = Assertions.assertThrows(AssertionError.class, contractCall);
49+
assertEquals(expectedErrorMessage, e.getMessage());
50+
}
51+
52+
@BeforeEach
53+
public void setup() throws Exception {
54+
multicallScore = sm.deploy(owner, Multicall.class);
55+
assert (multicallScore.getAddress().isContract());
56+
57+
dexMock = sm.deploy(owner, DexMock.class);
58+
assert (dexMock.getAddress().isContract());
59+
60+
dexSpy = (DexMock) spy(dexMock.getInstance());
61+
dexMock.setInstance(dexSpy);
62+
}
63+
64+
65+
@Test
66+
void name() {
67+
String contractName = "Balanced Multicall";
68+
assertEquals(contractName, multicallScore.call("name"));
69+
}
70+
71+
@Test
72+
void setAndGetDex() {
73+
Executable setDexNotFromOwner = () -> multicallScore.invoke(sm.createAccount(), "setDexAddress",
74+
dexMock.getAddress());
75+
String expectedErrorMessage = "Multicall: Caller is not the owner";
76+
expectErrorMessage(setDexNotFromOwner, expectedErrorMessage);
77+
78+
multicallScore.invoke(owner, "setDexAddress", dexMock.getAddress());
79+
Address actualDex = (Address) multicallScore.call("getDexAddress");
80+
assertEquals(dexMock.getAddress(), actualDex);
81+
}
82+
83+
@Test
84+
void getPoolStatsForPairTest() {
85+
setAndGetDex();
86+
Address baseToken = Account.newScoreAccount(51).getAddress();
87+
Address quoteToken = Account.newScoreAccount(52).getAddress();
88+
89+
@SuppressWarnings("unchecked")
90+
Map<String, Object> poolStats = (Map<String, Object>) multicallScore.call("getPoolStatsForPair", baseToken,
91+
quoteToken);
92+
verify(dexSpy).getPoolId(baseToken, quoteToken);
93+
verify(dexSpy).getPoolStats(BigInteger.ONE);
94+
reset();
95+
}
96+
97+
}

settings.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2022 Balanced.network.
2+
* Copyright (c) 2022-2022 Balanced.network.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -25,5 +25,5 @@
2525
*/
2626

2727
rootProject.name = 'balanced-java-contracts'
28-
include(':core-contracts',
28+
include(':core-contracts:Multicall',
2929
':token-contracts')

0 commit comments

Comments
 (0)