-
Notifications
You must be signed in to change notification settings - Fork 59
/
Copy pathcontract-interaction.js
executable file
·116 lines (96 loc) · 4.62 KB
/
contract-interaction.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#!/usr/bin/env node
// # Compile & Deploy a Sophia Smart Contract
//
// ## Introduction
// The whole script is [located in the repository](https://github.com/aeternity/aepp-sdk-js/blob/568c291b92c030011ca9e68169f328be6ff79488/examples/node/contract-interaction.js) and this page explains in detail how to:
//
// - deal with the different phases of compiling Sophia contracts to bytecode
// - deploy the bytecode to get a callable contract address
// - invoke the deployed contract on the æternity blockchain
// ## 1. Specify imports
//
// You need to import `AeSdk`, `Node` and `MemoryAccount` classes from the SDK.
import { AeSdk, Contract, CompilerHttp, Node, MemoryAccount } from '@aeternity/aepp-sdk';
// **Note**:
//
// - You need to have the SDK installed via `npm i @aetenity/aepp-sdk -g` to run that example code.
// ## 2. Define constants
// The following constants are used in the subsequent code snippets.
// typically you read the source code from a separate .aes file
const CONTRACT_SOURCE_CODE = `
contract Multiplier =
record state = { factor: int }
entrypoint init(f : int) : state = { factor = f }
stateful entrypoint setFactor(f : int): int =
put(state{ factor = f })
f * 10
entrypoint multiplyBy(x : int) = x * state.factor
`;
const ACCOUNT_SECRET_KEY = 'sk_2CuofqWZHrABCrM7GY95YSQn8PyFvKQadnvFnpwhjUnDCFAWmf';
const NODE_URL = 'https://testnet.aeternity.io';
const COMPILER_URL = 'https://v8.compiler.aepps.com';
// Note:
//
// - The secret key of the account is pre-funded and only used for demonstration purpose
// - You can replace it with your own
// (see [Create an Account](../../quick-start.md#2-create-a-sender-account))
// - In case the account runs out of funds you can always request AE using the [Faucet](https://faucet.aepps.com/)
// ## 3. Create object instances
const account = new MemoryAccount(ACCOUNT_SECRET_KEY);
const node = new Node(NODE_URL);
const aeSdk = new AeSdk({
nodes: [{ name: 'testnet', instance: node }],
accounts: [account],
onCompiler: new CompilerHttp(COMPILER_URL),
});
// ## 4. Get contract instance
// Knowing the source code allows you to initialize a contract instance and interact with the
// contract in a convenient way.
console.log(CONTRACT_SOURCE_CODE);
const contract = await Contract.initialize({
...aeSdk.getContext(),
sourceCode: CONTRACT_SOURCE_CODE,
});
// ## 5. Compile the contract
// The `$compile` function sends a raw Sophia contract as string
// to the HTTP compiler for bytecode compilation. In the future this will be done
// without talking to the node, but requiring a bytecode compiler
// implementation directly in the SDK.
const bytecode = await contract.$compile();
console.log(`Obtained bytecode ${bytecode}`);
// ## 6. Deploy the contract
// Invoking `$deploy` on the contract instance will result in the `CreateContractTx`
// being created, signed (using the _secretKey_ of the previously defined `MemoryAccount`) and
// broadcasted to the network. It will be picked up by the miners and written to the chain.
const deployInfo = await contract.$deploy([5]);
console.log(`Contract deployed at ${deployInfo.address}`);
// Note:
//
// - Sophia contracts always have an `init` function which needs to be invoked.
// - The SDK generates the required `calldata` for the provided arguments by
// `@aeternity/aepp-calldata` package.
// ## 7. Call a contract function
// Once the `ContractCreateTx` has been successfully mined, you can attempt to invoke
// any public function (aka `entrypoint` in Sophia) defined within it.
await contract.setFactor(6);
// **Note**:
//
// - `setFactor` is a stateful entrypoint that changes to the contract's state so `contract`
// broadcasting the transaction to be mined
// ## 8. Call a contract function via dry-run
// You can use `callStatic` option which performs a `dry-run` of the
// transaction which allows you to get the result without having to mine a transaction.
let call = await contract.setFactor(7, { callStatic: true });
// ## 9. Decode the call result
// The execution result, if successful, will be an FATE-encoded result value.
// The `decodedResult` property will contain the result value decoded using calldata package.
console.log(`setFactor execution result: ${call.decodedResult}`);
// ## 10. Call a contract non-stateful entrypoint via dry-run
call = await contract.multiplyBy(8);
console.log(`multiplyBy execution result: ${call.decodedResult}`);
// **Note**:
//
// - The `contract` automatically chooses to perform a dry-run call as `multiplyBy` is a
// non-stateful entrypoint
// - if `multiplyBy` would be a `stateful entrypoint` the transaction would be broadcasted to
// the network and picked up by miners