Skip to content

Commit 07ad1a1

Browse files
Add support for Soroban external calls 🎉 (#1679)
This PR adds support for Soroban external calls. This is the first step to support value transfers from inside Soroban contracts. --------- Signed-off-by: salaheldinsoliman <salaheldin_sameh@aucegypt.edu>
1 parent d13e944 commit 07ad1a1

39 files changed

+1069
-201
lines changed

.github/workflows/test.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,8 @@ jobs:
325325
with:
326326
node-version: '16'
327327
- uses: dtolnay/rust-toolchain@1.81.0
328+
with:
329+
target: wasm32-unknown-unknown
328330
- uses: actions/download-artifact@v4.1.8
329331
with:
330332
name: solang-linux-x86-64
@@ -335,14 +337,17 @@ jobs:
335337
echo "$(pwd)/bin" >> $GITHUB_PATH
336338
337339
- name: Install Soroban
338-
run: cargo install --locked soroban-cli --version 22.0.0
340+
run: cargo install --locked stellar-cli --version 22.0.0
339341
- name: Add cargo install location to PATH
340342
run: echo "$HOME/.cargo/bin" >> $GITHUB_PATH
341343
- run: npm install
342344
working-directory: ./integration/soroban
343345
- name: Build Solang contracts
344346
run: npm run build
345347
working-directory: ./integration/soroban
348+
- name: Build rust contracts
349+
run: soroban contract build --profile release-with-logs
350+
working-directory: ./integration/soroban/rust/contracts
346351
- name: Setup Soroban enivronment
347352
run: npm run setup
348353
working-directory: ./integration/soroban

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,5 @@ Cargo.lock
99

1010
.helix/
1111
.vscode/
12+
13+
/test_snapshots

integration/soroban/.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,8 @@
66
node_modules
77
package-lock.json
88
*.txt
9-
*.toml
9+
*.wasm
10+
*.abi
11+
target/
12+
.stellar
13+

integration/soroban/callee.sol

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
contract callee {
2+
function add (uint64 a, uint64 b, uint64 c) public returns (uint64) {
3+
print("add called in Solidity");
4+
return a + b +c;
5+
}
6+
}

integration/soroban/caller.sol

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
contract caller {
2+
function add (address addr, uint64 a, uint64 b, uint64 c) public returns (uint64) {
3+
bytes payload = abi.encode("add", a, b, c);
4+
(bool suc, bytes returndata) = addr.call(payload);
5+
uint64 result = abi.decode(returndata, (uint64));
6+
return result;
7+
}
8+
}

integration/soroban/counter.spec.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ describe('Counter', () => {
3535
it('get correct initial counter', async () => {
3636
// get the count
3737
let count = await call_contract_function("count", server, keypair, contract);
38-
expect(count.toString()).eq("10");
38+
console.log(count.returnValue().value());
39+
expect(count.returnValue().value().toString()).eq("10");
3940
});
4041

4142
it('increment counter', async () => {
@@ -44,7 +45,7 @@ describe('Counter', () => {
4445

4546
// get the count
4647
let count = await call_contract_function("count", server, keypair, contract);
47-
expect(count.toString()).eq("11");
48+
expect(count.returnValue().value().toString()).eq("11");
4849
});
4950
});
5051

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import * as StellarSdk from '@stellar/stellar-sdk';
2+
import { readFileSync } from 'fs';
3+
import { expect } from 'chai';
4+
import path from 'path';
5+
import { fileURLToPath } from 'url';
6+
import { call_contract_function, extractLogEvent } from './test_helpers.js';
7+
8+
const __filename = fileURLToPath(import.meta.url);
9+
const dirname = path.dirname(__filename);
10+
const server = new StellarSdk.SorobanRpc.Server("https://soroban-testnet.stellar.org:443");
11+
12+
function readContractAddress(filename) {
13+
return readFileSync(path.join(dirname, '.soroban', 'contract-ids', filename), 'utf8').trim();
14+
}
15+
16+
describe('Cross Contract Calls', () => {
17+
let keypair, caller, callee, calleeRust;
18+
19+
before(async () => {
20+
console.log('Setting up cross contract tests...');
21+
22+
keypair = StellarSdk.Keypair.fromSecret(readFileSync('alice.txt', 'utf8').trim());
23+
caller = new StellarSdk.Contract(readContractAddress('caller.txt'));
24+
callee = new StellarSdk.Contract(readContractAddress('callee.txt'));
25+
calleeRust = new StellarSdk.Contract(readContractAddress('hello_world.txt'));
26+
});
27+
28+
it('calls Rust contract', async () => {
29+
let addr = calleeRust.address().toScVal();
30+
let values = [
31+
new StellarSdk.xdr.Uint64(BigInt(1)),
32+
new StellarSdk.xdr.Uint64(BigInt(2)),
33+
new StellarSdk.xdr.Uint64(BigInt(0))
34+
].map(StellarSdk.xdr.ScVal.scvU64);
35+
36+
let res = await call_contract_function("add", server, keypair, caller, addr, ...values);
37+
let returnValue = res.returnValue().value().toString();
38+
39+
console.log(returnValue);
40+
expect(returnValue).to.equal("3");
41+
42+
let logMessages = extractLogEvent(res.diagnosticEvents()).logMessages;
43+
console.log(logMessages);
44+
expect(logMessages[0]).to.contain('Soroban SDK add function called!');
45+
});
46+
47+
it('calls Solidity contract', async () => {
48+
let addr = callee.address().toScVal();
49+
let values = [
50+
new StellarSdk.xdr.Uint64(BigInt(1)),
51+
new StellarSdk.xdr.Uint64(BigInt(2)),
52+
new StellarSdk.xdr.Uint64(BigInt(0))
53+
].map(StellarSdk.xdr.ScVal.scvU64);
54+
55+
let res = await call_contract_function("add", server, keypair, caller, addr, ...values);
56+
let returnValue = res.returnValue().value().toString();
57+
58+
console.log(returnValue);
59+
expect(returnValue).to.equal("3");
60+
61+
let logMessages = extractLogEvent(res.diagnosticEvents()).logMessages;
62+
console.log(logMessages);
63+
expect(logMessages[0]).to.contain('add called in Solidity');
64+
});
65+
});

integration/soroban/runtime_error.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ describe('Runtime Error', () => {
3535
await call_contract_function("decrement", server, keypair, contract);
3636
});
3737

38-
it('get correct initial counter', async () => {
38+
it('prints error', async () => {
3939

4040
// decrement the counter again, resulting in a runtime error
4141
let res = await call_contract_function("decrement", server, keypair, contract);
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[workspace]
2+
resolver = "2"
3+
members = [
4+
"contracts/*",
5+
]
6+
7+
[workspace.dependencies]
8+
soroban-sdk = "22"
9+
10+
[profile.release]
11+
opt-level = "z"
12+
overflow-checks = true
13+
debug = 0
14+
strip = "symbols"
15+
debug-assertions = false
16+
panic = "abort"
17+
codegen-units = 1
18+
lto = true
19+
20+
# For more information about this profile see https://soroban.stellar.org/docs/basic-tutorials/logging#cargotoml-profile
21+
[profile.release-with-logs]
22+
inherits = "release"
23+
debug-assertions = true
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[package]
2+
name = "hello-world"
3+
version = "0.0.0"
4+
edition = "2021"
5+
publish = false
6+
7+
[lib]
8+
crate-type = ["cdylib"]
9+
doctest = false
10+
11+
[dependencies]
12+
soroban-sdk = { workspace = true }
13+
14+
[dev-dependencies]
15+
soroban-sdk = { workspace = true, features = ["testutils"] }

0 commit comments

Comments
 (0)