diff --git a/docs/guides/address-length.md b/docs/guides/address-length.md index 5413b40d69..a2c3f53e5c 100644 --- a/docs/guides/address-length.md +++ b/docs/guides/address-length.md @@ -81,5 +81,5 @@ Running the above code you would get output like Therefore the minimum address length is 41 chars. All these addresses valid, for example `ak_11111111111111111111111111111111273Yts` [used] to collect AENS name fees. -[isAddressValid]: https://docs.aeternity.com/aepp-sdk-js/v13.1.0/api/functions/isAddressValid.html +[isAddressValid]: https://docs.aeternity.com/aepp-sdk-js/v13.2.1/api/functions/isAddressValid.html [used]: https://mainnet.aeternity.io/v3/accounts/ak_11111111111111111111111111111111273Yts diff --git a/docs/guides/contracts.md b/docs/guides/contracts.md index c024b42536..436a349385 100644 --- a/docs/guides/contracts.md +++ b/docs/guides/contracts.md @@ -5,24 +5,33 @@ The smart contract language of the æternity blockchain is [Sophia](https://docs Before interacting with contracts using the SDK you should get familiar with Sophia itself first. Have a look into [aepp-sophia-examples](https://github.com/aeternity/aepp-sophia-examples) and start rapid prototyping using [AEstudio](https://studio.aepps.com). -The SDK needs to interact with following components in order to enable smart contract interactions on the æternity blockchain: - -- [æternity](https://github.com/aeternity/aeternity) (host your own one or use the public testnet node at `https://testnet.aeternity.io`) -- [aesophia_http](https://github.com/aeternity/aesophia_http) (host your own one or use the public compiler at `https://v7.compiler.aepps.com`) - -Note: - -- For production deployments you should ***always*** host these services by yourself. - ## 1. Specify imports ```js // node.js import -const { AeSdk, MemoryAccount, Node, CompilerHttp } = require('@aeternity/aepp-sdk') +const { AeSdk, MemoryAccount, Node } = require('@aeternity/aepp-sdk') // ES import -import { AeSdk, MemoryAccount, Node, CompilerHttp } from '@aeternity/aepp-sdk' +import { AeSdk, MemoryAccount, Node } from '@aeternity/aepp-sdk' +// additionally you may need to import CompilerCli or CompilerHttp +``` + +## 2. Setup compiler +Compiler primarily used to generate bytecode to deploy a contract. +Skip this step if you have a contract bytecode or need to interact with an already deployed contract. +Out-of-the-box SDK supports [aesophia_cli](https://github.com/aeternity/aesophia_cli) and [aesophia_http](https://github.com/aeternity/aesophia_http) implemented in [CompilerCli](https://docs.aeternity.com/aepp-sdk-js/v13.2.1/api/classes/CompilerCli.html) and [CompilerHttp](https://docs.aeternity.com/aepp-sdk-js/v13.2.1/api/classes/CompilerHttp.html) respectively. + +CompilerCli is available only in Node.js and requires Erlang installed (`escript` available in `$PATH`), Windows is supported. +```js +const compiler = new CompilerCli() ``` -## 2. Create an instance of the SDK +CompilerHttp requires a hosted compiler service. Preferable to host your own compiler service since [compiler.aepps.com](https://v7.compiler.aepps.com/api) is planned to be decommissioned. An example of how to run it using [docker-compose](https://github.com/aeternity/aepp-sdk-js/blob/cd8dd7f76a6323383349b48400af0d69c2cfd88e/docker-compose.yml#L11-L14). +```js +const compiler = new CompilerHttp('https://v7.compiler.aepps.com') // host your own compiler +``` + +Both compiler classes implement the [same interface](https://docs.aeternity.com/aepp-sdk-js/v13.2.1/api/classes/CompilerBase.html) that can be used to generate bytecode and ACI without a Contract instance. + +## 3. Create an instance of the SDK When creating an instance of the SDK you need to provide an account which will be used to sign transactions like `ContractCreateTx` and `ContractCallTx` that will be broadcasted to the network. ```js @@ -32,7 +41,7 @@ const account = new MemoryAccount(SECRET_KEY) const aeSdk = new AeSdk({ nodes: [{ name: 'testnet', instance: node }], accounts: [account], - onCompiler: new CompilerHttp('https://v7.compiler.aepps.com'), // ideally host your own compiler + onCompiler: compiler, // remove if step #2 skipped }) ``` @@ -42,7 +51,7 @@ Note: - For each transaction you can choose a specific account to use for signing (by default the first account will be used), see [transaction options](../transaction-options.md). - This is specifically important and useful for writing tests. -## 3. Initialize the contract instance +## 4. Initialize the contract instance ### By source code @@ -59,6 +68,13 @@ Note: const contract = await aeSdk.initializeContract({ sourceCode, fileSystem }) ``` +### By path to source code (available only in Node.js) +It can be used with both CompilerCli and CompilerHttp. This way contract imports would be handled automatically, with no need to provide `fileSystem` option. +```js +const sourceCodePath = './example.aes' +const contract = await aeSdk.initializeContract({ sourceCodePath }) +``` + ### By ACI and bytecode If you pre-compiled the contracts you can also initialize a contract instance by providing ACI and bytecode: @@ -80,7 +96,7 @@ const contract = await aeSdk.initializeContract({ aci, address }) ### Options - Following attributes can be provided via `options` to `initializeContract`: - - `aci` (default: obtained via http compiler) + - `aci` (default: obtained via `onCompiler`) - The Contract ACI. - `address` - The address where the contract is located at. @@ -94,7 +110,11 @@ const contract = await aeSdk.initializeContract({ aci, address }) - You wouldn't want to provide an `amount` to each transaction or use the same `nonce` which would result in invalid transactions. - For options like `ttl` or `gasPrice` it does absolutely make sense to set this on contract instance level. -## 4. Deploy the contract +### Keep bytecode and ACI for future use +After the contract is initialized you can persist values of `contract._aci` and `contract.$options.bytecode`. +They can be provided for subsequent contract initializations to don't depend on a compiler. + +## 5. Deploy the contract If you have a Sophia contract source code that looks like this: ```sophia @@ -131,7 +151,7 @@ Note: - In Sophia all `public functions` are called `entrypoints` and need to be declared as `stateful` if they should produce changes to the state of the smart contract, see `increment(value: int)`. -## 5. Call contract entrypoints +## 6. Call contract entrypoints ### a) Stateful entrypoints According to the example above you can call the `stateful` entrypoint `increment` by using one of the following lines: @@ -187,21 +207,13 @@ const tx = await contract.$call('fund_project', [1], { amount: 50 }) As already stated various times in the guide it is possible to provide [transaction options](../transaction-options.md) as object to a function of the SDK that builds and potentially broadcasts a transaction. This object can be passed as additional param to each of these functions and overrides the default settings. ## Sophia datatype cheatsheet -Sometimes you might wonder how to pass params to the JavaScript method that calls an entrypoint of your Sophia smart contract. The following table may help you out. - -| Type | Sophia entrypoint definition | JavaScript method call | -|-----------|-----------------------------------|--------------------------------------------------| -| int | `add_two(one: int, two: int)` | `add_two(1 , 2)` | -| address | `set_owner(owner: address)` | `set_owner('ak_1337...')` | -| bool | `is_it_true(answer: bool)` | `is_it_true(true)` | -| bits | `give_me_bits(input: bits)` | `give_me_bits(0b10110n)` | -| bytes | `get_bytes(test: bytes(3))` | `get_bytes(new Uint8Array([0x1, 0x1f, 0x10]))` | -| string | `hello_world(say_hello: string)` | `hello_world('Hello!')` | -| list | `have_a_few(candy: list(string))` | `have_a_few(['Skittles', 'M&Ms', 'JellyBelly'])` | -| tuple | `a_few_things(things: (string * int * map(address, bool)))` | `a_few_things(['hola', 3, new Map([['ak_1337...', true]])])` | -| record | `record user = {`
        `firstname: string,`
        `lastname: string`
`}`

`get_firstname(input: user): string` | `get_firstname({'firstname': 'Alfred', 'lastname': 'Mustermann'})` | -| map | `balances(values: map(address, int))` | `balances(new Map([['ak_1337...', 123], ['ak_FCKGW...', 321], ['ak_Rm5U...', 999]]))` | -| option() | `number_defined(value: option(int)): bool = `
        `Option.is_some(value)` | `// the datatype in the option()`
`number_defined(1337) // int in this case` | -| hash | `a_gram(of: hash)` | `// 32 bytes signature`
`a_gram('af01...490f')` | -| signature | `one_signature(sig: signature)` | `// 64 bytes signature`
`one_signature('af01...490f')` | -| functions | (Higher order) functions are not allowed in `entrypoint` params | | +Sometimes you might wonder how to pass params to the JavaScript method that calls an entrypoint of your Sophia smart contract. +The conversion between JS and Sophia values is handled by aepp-calldata library. +Refer to [its documentation](https://www.npmjs.com/package/@aeternity/aepp-calldata#data-types) to find the right type to use. + +## Generate file system object in Node.js +To do so you can use [getFileSystem](https://docs.aeternity.com/aepp-sdk-js/v13.2.1/api/functions/getFileSystem.html) function. +In most cases, you don't need to do it explicitly. Prefer to use `sourceCodePath` instead `sourceCode` in +[Contract::initialize](https://docs.aeternity.com/aepp-sdk-js/v13.2.1/api/classes/_internal_.Contract.html#initialize), +and [compile](https://docs.aeternity.com/aepp-sdk-js/v13.2.1/api/classes/CompilerBase.html#compile) +instead [compileBySourceCode](https://docs.aeternity.com/aepp-sdk-js/v13.2.1/api/classes/CompilerBase.html#compileBySourceCode) in CompilerBase. diff --git a/docs/guides/paying-for-tx.md b/docs/guides/paying-for-tx.md index 98eb8e579f..3621ea814d 100644 --- a/docs/guides/paying-for-tx.md +++ b/docs/guides/paying-for-tx.md @@ -13,8 +13,8 @@ You can then collect the signed inner transaction, wrap it into a `PayingForTx` ## Usage examples We provided following two NodeJS examples which you can take a look at: -- [InnerTx: ContractCallTx](https://docs.aeternity.com/aepp-sdk-js/v13.1.0/examples/node/paying-for-contract-call-tx/) -- [InnerTx: SpendTx](https://docs.aeternity.com/aepp-sdk-js/v13.1.0/examples/node/paying-for-spend-tx/) +- [InnerTx: ContractCallTx](https://docs.aeternity.com/aepp-sdk-js/v13.2.1/examples/node/paying-for-contract-call-tx/) +- [InnerTx: SpendTx](https://docs.aeternity.com/aepp-sdk-js/v13.2.1/examples/node/paying-for-spend-tx/) Note: diff --git a/examples/node/transfer-ae.mjs b/examples/node/transfer-ae.mjs index 7a90392de4..c4dcb6d230 100755 --- a/examples/node/transfer-ae.mjs +++ b/examples/node/transfer-ae.mjs @@ -53,7 +53,7 @@ console.log(`Balance of ${recipient} (before): ${balanceBefore} aettos`); // Calling the `spend` function will create, sign and broadcast a `SpendTx` to the network. const tx = await aeSdk.spend(amount, recipient); console.log('Transaction mined', tx); -// Alternatively, you can use [transferFunds](https://docs.aeternity.com/aepp-sdk-js/v13.1.0/api/functions/transferFunds.html) +// Alternatively, you can use [transferFunds](https://docs.aeternity.com/aepp-sdk-js/v13.2.1/api/functions/transferFunds.html) // method to transfer a fraction of your AE to another account. // ## 6. Get AE balance of recipient (after transfer) diff --git a/src/Middleware.ts b/src/Middleware.ts index fafb521234..e6eea637a8 100644 --- a/src/Middleware.ts +++ b/src/Middleware.ts @@ -105,7 +105,7 @@ export default class Middleware /** * @param url - Url for middleware API * @param options - Options - * @param options.ignoreVersion - Don't check node version + * @param options.ignoreVersion - Don't ensure that the middleware is supported * @param options.retryCount - Amount of extra requests to do in case of failure * @param options.retryOverallDelay - Time in ms to wait between all retries */ diff --git a/src/Node.ts b/src/Node.ts index ff22ae8f81..a851a191c0 100644 --- a/src/Node.ts +++ b/src/Node.ts @@ -116,7 +116,7 @@ export default class Node extends (NodeTransformed as unknown as NodeTransformed /** * @param url - Url for node API * @param options - Options - * @param options.ignoreVersion - Don't check node version + * @param options.ignoreVersion - Don't ensure that the node is supported * @param options.retryCount - Amount of extra requests to do in case of failure * @param options.retryOverallDelay - Time in ms to wait between all retries */ diff --git a/src/contract/compiler/Cli.ts b/src/contract/compiler/Cli.ts index 47ee9babc1..149919c4b4 100644 --- a/src/contract/compiler/Cli.ts +++ b/src/contract/compiler/Cli.ts @@ -17,14 +17,19 @@ const getPackagePath = (): string => { }; /** - * A wrapper around aesophia_cli, available only in Node.js - * Assumes that `escript` is available in PATH. + * A wrapper around aesophia_cli, available only in Node.js. + * Requires Erlang installed, assumes that `escript` is available in PATH. */ export default class CompilerCli extends CompilerBase { #path: string; #ensureCompatibleVersion = Promise.resolve(); + /** + * @param compilerPath - A path to aesophia_cli binary, by default uses the integrated one + * @param options - Options + * @param options.ignoreVersion - Don't ensure that the compiler is supported + */ constructor( compilerPath = resolve(getPackagePath(), './bin/aesophia_cli'), { ignoreVersion }: { ignoreVersion?: boolean } = {},