Skip to content

Commit 498692a

Browse files
committed
add smart contract interactions
1 parent 4648074 commit 498692a

5 files changed

+168
-15
lines changed

README.md

+7
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ git checkout <tag_name>
4949
- **Article**: [Mastering smart contract deployment with MultiversX JavaScript SDK](https://www.julian.io/articles/multiversx-js-sdk-sc-deployment.html)
5050
- **Video**: [Mastering smart contract deployment with MultiversX JavaScript SDK](https://www.youtube.com/watch?v=Rk-vHqd2avs)
5151

52+
### Example 4: Smart contract interactions
53+
54+
- **Tag**: `smart-contract-interactions`
55+
- **Description**: This example demonstrates how to interact with a smart contract using the MultiversX JavaScript SDK on the devnet.
56+
- **Article**: [Step-by-step guide to MultiversX smart contract interactions with JavaScript SDK](https://www.julian.io/articles/multiversx-js-sdk-sc-interactions.html)
57+
- **Video**: [Step-by-step guide to MultiversX smart contract interactions with JavaScript SDK](https://www.youtube.com/watch?v=TMDC5yxT4_c)
58+
5259
## Security and Wallet Information
5360

5461
The examples use a demo wallet with a hardcoded password. All interactions occur on the **devnet** (development network of MultiversX), ensuring that it is safe to expose the wallet credentials. The devnet is designed for testing and development, involving no real assets. Don't do this on the mainnet.

deploy-smart-contract.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
SmartContractTransactionsFactory,
66
Code,
77
Address,
8+
AbiRegistry,
89
TransactionWatcher,
910
SmartContractTransactionsOutcomeParser,
1011
TransactionsConverter,
@@ -29,12 +30,13 @@ const deploySmartContract = async () => {
2930
// Load ABI file (not required for now, but will be useful when interacting with the SC)
3031
// Although it would be helpful if we had initial arguments to pass
3132
const abiFile = await promises.readFile("./piggybank.abi.json", "UTF-8");
33+
const abiObj = JSON.parse(abiFile);
3234

3335
// Prepare transfer transactions factory
3436
const factoryConfig = new TransactionsFactoryConfig({ chainID: "D" });
3537
let scFactory = new SmartContractTransactionsFactory({
3638
config: factoryConfig,
37-
abi: abiFile,
39+
abi: AbiRegistry.create(abiObj),
3840
});
3941

4042
// Prepare deploy transaction
@@ -82,8 +84,6 @@ const deploySmartContract = async () => {
8284
converter.transactionOnNetworkToOutcome(transactionOnNetwork);
8385
const parsedOutcome = parser.parseDeploy({ transactionOutcome });
8486

85-
console.log(parsedOutcome);
86-
8787
console.log(
8888
`Smart Contract deployed. Here it is:\nhttps://devnet-explorer.multiversx.com/accounts/${parsedOutcome.contracts[0].address}\n\nCheck the transaction in the Explorer:\nhttps://devnet-explorer.multiversx.com/transactions/${txHash}`
8989
);

package-lock.json

+8-8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
"test": "echo \"Error: no test specified\" && exit 1"
99
},
1010
"author": "",
11-
"license": "ISC",
11+
"license": "MIT",
1212
"dependencies": {
13-
"@multiversx/sdk-core": "^13.1.0",
13+
"@multiversx/sdk-core": "^13.2.1",
1414
"@multiversx/sdk-network-providers": "^2.4.3",
15-
"@multiversx/sdk-wallet": "^4.4.0"
15+
"@multiversx/sdk-wallet": "^4.5.0"
1616
}
17-
}
17+
}

smart-contract-interactions.js

+146
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
import { promises } from "node:fs";
2+
import {
3+
Address,
4+
SmartContractTransactionsFactory,
5+
TransactionsFactoryConfig,
6+
TransactionComputer,
7+
AbiRegistry,
8+
QueryRunnerAdapter,
9+
SmartContractQueriesController,
10+
} from "@multiversx/sdk-core";
11+
import {
12+
syncAndGetAccount,
13+
senderAddress,
14+
getSigner,
15+
apiNetworkProvider,
16+
} from "./setup.js";
17+
18+
/**
19+
* Replace with your own deployed piggy bank smart contract
20+
* check deploy-smart-contract.js on how to deploy one
21+
*/
22+
const PIGGYBANK_CONTRACT_ADDRESS =
23+
"erd1qqqqqqqqqqqqqpgqtrajzw4vq0zxccdt9u66cvgg6vz8c6cwnegqkfqkpq";
24+
25+
/**
26+
* Load ABI file
27+
*/
28+
const getAbi = async () => {
29+
const abiFile = await promises.readFile("./piggybank.abi.json", "UTF-8");
30+
return JSON.parse(abiFile);
31+
};
32+
33+
const scTransaction = async ({ functionName, args, amount }) => {
34+
const user = await syncAndGetAccount();
35+
const computer = new TransactionComputer();
36+
const signer = await getSigner();
37+
38+
const abiObj = await getAbi();
39+
40+
const factoryConfig = new TransactionsFactoryConfig({ chainID: "D" });
41+
const factory = new SmartContractTransactionsFactory({
42+
config: factoryConfig,
43+
abi: AbiRegistry.create(abiObj),
44+
});
45+
46+
const transaction = factory.createTransactionForExecute({
47+
sender: new Address(senderAddress),
48+
contract: Address.fromBech32(PIGGYBANK_CONTRACT_ADDRESS),
49+
function: functionName,
50+
gasLimit: 5000000,
51+
arguments: args || [],
52+
nativeTransferAmount: amount,
53+
});
54+
55+
// Increase the nonce
56+
transaction.nonce = user.getNonceThenIncrement();
57+
58+
// Serialize the transaction for signing
59+
const serializedTransaction = computer.computeBytesForSigning(transaction);
60+
61+
// Sign the transaction with our signer
62+
transaction.signature = await signer.sign(serializedTransaction);
63+
64+
// Broadcast the transaction
65+
const txHash = await apiNetworkProvider.sendTransaction(transaction);
66+
67+
console.log(
68+
"Check in the Explorer: ",
69+
`https://devnet-explorer.multiversx.com/transactions/${txHash}`
70+
);
71+
};
72+
73+
/**
74+
* Call the createPiggy endpoint on the PiggyBank smart contract
75+
* https://github.com/xdevguild/piggy-bank-sc/blob/master/src/lib.rs#L25
76+
* We pass the unix timestamp in the future
77+
*/
78+
const createPiggy = async () => {
79+
await scTransaction({
80+
functionName: "createPiggy",
81+
args: [1750686756],
82+
});
83+
};
84+
85+
/**
86+
* Call the addAmount endpoint on the PiggyBank smart contract
87+
* https://github.com/xdevguild/piggy-bank-sc/blob/master/src/lib.rs#L42
88+
*/
89+
const addAmount = async () => {
90+
await scTransaction({
91+
functionName: "addAmount",
92+
amount: 1000000000000000n,
93+
});
94+
};
95+
96+
/**
97+
* Query the getLockedAmount endpoint on the PiggyBank smart contract
98+
* https://github.com/xdevguild/piggy-bank-sc/blob/master/src/lib.rs#L92
99+
*/
100+
const getLockedAmount = async () => {
101+
const abiObj = await getAbi();
102+
103+
const queryRunner = new QueryRunnerAdapter({
104+
networkProvider: apiNetworkProvider,
105+
});
106+
107+
const controller = new SmartContractQueriesController({
108+
queryRunner: queryRunner,
109+
abi: AbiRegistry.create(abiObj),
110+
});
111+
112+
const query = controller.createQuery({
113+
contract: PIGGYBANK_CONTRACT_ADDRESS,
114+
function: "getLockedAmount",
115+
arguments: [senderAddress],
116+
});
117+
118+
const response = await controller.runQuery(query);
119+
120+
const [amount] = controller.parseQueryResponse(response);
121+
122+
// The returned amount is a BigNumber
123+
console.log("Locked amount is: ", amount.valueOf());
124+
};
125+
126+
/**
127+
* Here we will manage which function to call
128+
*/
129+
const smartContractInteractions = () => {
130+
const args = process.argv.slice(2);
131+
const functionName = args[0];
132+
133+
const functions = {
134+
createPiggy,
135+
addAmount,
136+
getLockedAmount,
137+
};
138+
139+
if (functionName in functions) {
140+
functions[functionName]();
141+
} else {
142+
console.log("Function not found!");
143+
}
144+
};
145+
146+
smartContractInteractions();

0 commit comments

Comments
 (0)