@concordium/node-sdk
Advanced tools
Comparing version
{ | ||
"name": "@concordium/node-sdk", | ||
"version": "1.1.0", | ||
"version": "2.0.0", | ||
"description": "Helpers for interacting with the Concordium node", | ||
@@ -15,8 +15,7 @@ "repository": { | ||
"license": "Apache-2.0", | ||
"private": false, | ||
"engines": { | ||
"node": ">=14.16.0" | ||
}, | ||
"main": "lib/src/index.js", | ||
"types": "lib/src/index.d.ts", | ||
"main": "lib/index.js", | ||
"types": "lib/index.d.ts", | ||
"files": [ | ||
@@ -26,3 +25,3 @@ "/lib/**/*" | ||
"devDependencies": { | ||
"@types/bs58check": "^2.1.0", | ||
"@noble/ed25519": "^1.6.0", | ||
"@types/google-protobuf": "^3.15.3", | ||
@@ -33,2 +32,3 @@ "@types/jest": "^26.0.23", | ||
"babel-jest": "^27.0.6", | ||
"cross-env": "5.0.5", | ||
"eslint": "^7.29.0", | ||
@@ -40,6 +40,4 @@ "eslint-config-prettier": "^8.3.0", | ||
"grpc_tools_node_protoc_ts": "5.3.0", | ||
"husky": "^4.2.5", | ||
"jest": "^27.0.6", | ||
"lint-staged": "^12.0.2", | ||
"noble-ed25519": "^1.2.5", | ||
"prettier": "^2.3.2", | ||
@@ -54,25 +52,15 @@ "ts-jest": "^27.0.3", | ||
"scripts": { | ||
"generate-js": "yarn run grpc_tools_node_protoc --js_out=import_style=commonjs,binary:grpc --grpc_out=grpc_js:grpc --plugin=protoc-gen-grpc=./node_modules/.bin/grpc_tools_node_protoc_plugin -I ./deps/concordium-grpc-api deps/concordium-grpc-api/*.proto", | ||
"generate-ts": "yarn run grpc_tools_node_protoc --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=grpc_js:grpc -I ./deps/concordium-grpc-api deps/concordium-grpc-api/*.proto", | ||
"generate": "mkdir -p grpc && yarn generate-js && yarn generate-ts", | ||
"generate-js": "yarn run grpc_tools_node_protoc --js_out=import_style=commonjs,binary:grpc --grpc_out=grpc_js:grpc --plugin=protoc-gen-grpc=../../node_modules/.bin/grpc_tools_node_protoc_plugin -I ../../deps/concordium-grpc-api ../../deps/concordium-grpc-api/*.proto", | ||
"generate-ts": "yarn run grpc_tools_node_protoc --plugin=protoc-gen-ts=../../node_modules/.bin/protoc-gen-ts --ts_out=grpc_js:grpc -I ../../deps/concordium-grpc-api ../../deps/concordium-grpc-api/*.proto", | ||
"generate": "([ -e \"../../deps/concordium-grpc-api\" ] && mkdir -p grpc && yarn generate-js && yarn generate-ts) || echo 'Please checkout submodules before building'; false", | ||
"lint": "eslint . --cache --ext .ts,.tsx --max-warnings 0", | ||
"lint-fix": "yarn --silent lint --fix; exit 0", | ||
"test": "jest", | ||
"build": "wasm-pack build --target nodejs && tsc && cp -r ./grpc/ ./lib/ && cp -r ./pkg/ ./lib/" | ||
"build": "([ ! -e \"grpc\" ] && yarn generate) || true && tsc && cp -r ./grpc/ ./lib/ " | ||
}, | ||
"dependencies": { | ||
"@concordium/common-sdk": "2.0.0", | ||
"@grpc/grpc-js": "^1.3.4", | ||
"google-protobuf": "^3.20.1", | ||
"bs58check": "^2.1.2", | ||
"buffer": "^6.0.3", | ||
"hash.js": "^1.1.7" | ||
}, | ||
"husky": { | ||
"hooks": { | ||
"pre-commit": "lint-staged" | ||
} | ||
}, | ||
"lint-staged": { | ||
"*.ts": "yarn lint --fix" | ||
"buffer": "^6.0.3" | ||
} | ||
} |
519
README.md
@@ -1,7 +0,40 @@ | ||
# concordium-node-sdk-js | ||
# Concordium Nodejs SDK | ||
[](https://github.com/Concordium/.github/blob/main/.github/CODE_OF_CONDUCT.md) | ||
Wrappers for interacting with the Concordium node. | ||
Wrappers for interacting with the Concordium node, using nodejs. | ||
[Note that this package contains and exports the functions from the common-sdk, check the readme of that package for an overview of those](../common/README.md). | ||
**Table of Contents** | ||
- [ConcordiumNodeClient](#concordiumnodeclient) | ||
- [Creating a client](#creating-a-client) | ||
- [Send Account Transaction](#send-account-transaction) | ||
- [Create a new account](#create-a-new-account) | ||
- [Construct IdentityInput for creating credentials](#construct-identityinput-for-creating-credentials) | ||
- [Construct from user-cli output:](#construct-from-user-cli-output) | ||
- [Construct from mobile wallet export:](#construct-from-mobile-wallet-export) | ||
- [getAccountInfo](#getaccountinfo) | ||
- [getNextAccountNonce](#getnextaccountnonce) | ||
- [getTransactionStatus](#gettransactionstatus) | ||
- [getBlockSummary](#getblocksummary) | ||
- [getBlockInfo](#getblockinfo) | ||
- [getBlocksAtHeight](#getblocksatheight) | ||
- [getConsensusStatus](#getconsensusstatus) | ||
- [getCryptographicParameters](#getcryptographicparameters) | ||
- [getIdentityProviders](#getidentityproviders) | ||
- [getAnonymityRevokers](#getanonymityrevokers) | ||
- [getPeerList](#getpeerlist) | ||
- [getBakerList](#getbakerlist) | ||
- [getPoolStatus](#getpoolstatus) | ||
- [getRewardStatus](#getrewardstatus) | ||
- [Check block for transfers with memo](#check-block-for-transfers-with-memo) | ||
- [getInstances](#getinstances) | ||
- [getInstanceInfo](#getinstanceinfo) | ||
- [Build](#build) | ||
- [Building for a release](#building-for-a-release) | ||
- [Publishing a release](#publishing-a-release) | ||
- [Test](#test) | ||
# ConcordiumNodeClient | ||
@@ -32,198 +65,10 @@ | ||
## Create a simple transfer | ||
The following example demonstrates how a simple transfer can be created. | ||
```js | ||
const header: AccountTransactionHeader = { | ||
expiry: new TransactionExpiry(new Date(Date.now() + 3600000)), | ||
nonce: 1n, // the next nonce for this account, can be found using getNextAccountNonce | ||
sender: new AccountAddress("4ZJBYQbVp3zVZyjCXfZAAYBVkJMyVj8UKUNj9ox5YqTCBdBq2M"), | ||
}; | ||
const simpleTransfer: SimpleTransferPayload = { | ||
amount: new GtuAmount(100n), | ||
toAddress: new AccountAddress("4hXCdgNTxgM7LNm8nFJEfjDhEcyjjqQnPSRyBS9QgmHKQVxKRf"), | ||
}; | ||
const simpleTransferAccountTransaction: AccountTransaction = { | ||
header: header, | ||
payload: simpleTransfer, | ||
type: AccountTransactionType.SimpleTransfer, | ||
}; | ||
``` | ||
## Send Account Transaction | ||
The following example demonstrates how to send any account transaction. | ||
## Create a simple transfer with a memo | ||
The following example demonstrates how a simple transfer with a memo can be created. | ||
```js | ||
const header: AccountTransactionHeader = { | ||
expiry: new TransactionExpiry(new Date(Date.now() + 3600000)), | ||
nonce: 1n, // the next nonce for this account, can be found using getNextAccountNonce | ||
sender: new AccountAddress("4ZJBYQbVp3zVZyjCXfZAAYBVkJMyVj8UKUNj9ox5YqTCBdBq2M"), | ||
}; | ||
const simpleTransferWithMemo: SimpleTransferWithMemoPayload = { | ||
amount: new GtuAmount(100n), | ||
toAddress: new AccountAddress("4hXCdgNTxgM7LNm8nFJEfjDhEcyjjqQnPSRyBS9QgmHKQVxKRf"), | ||
memo: new DataBlob(Buffer.from('6B68656C6C6F20776F726C64', 'hex')), | ||
}; | ||
const simpleTransferWithMemoAccountTransaction: AccountTransaction = { | ||
header: header, | ||
payload: simpleTransferWithMemo, | ||
type: AccountTransactionType.SimpleTransferWithMemo, | ||
}; | ||
``` | ||
## Create a Register data transaction | ||
The following example demonstrates how a register data transaction can be created. | ||
```js | ||
const header: AccountTransactionHeader = { | ||
expiry: new TransactionExpiry(new Date(Date.now() + 3600000)), | ||
nonce: 1n, // the next nonce for this account, can be found using getNextAccountNonce | ||
sender: new AccountAddress("4ZJBYQbVp3zVZyjCXfZAAYBVkJMyVj8UKUNj9ox5YqTCBdBq2M"), | ||
}; | ||
const registerData: RegisterDataPayload = { | ||
data: new DataBlob(Buffer.from('6B68656C6C6F20776F726C64', 'hex')) // Add the bytes you wish to register as a DataBlob | ||
}; | ||
const registerDataAccountTransaction: AccountTransaction = { | ||
header: header, | ||
payload: registerData, | ||
type: AccountTransactionType.RegisterData, | ||
}; | ||
``` | ||
See the Constructing transactions section for the [common package](../common#constructing-transactions) for how to create an account transaction. | ||
See the signing a transaction section for the [common package](../common#sign-an-account-transaction) for how to sign an account transaction. | ||
## Create a configure delegation transaction | ||
The following example demonstrates how a configure delegation transaction can be created. | ||
Note that although all the fields are optional, they are all required, when becoming a delegator. | ||
```js | ||
const header: AccountTransactionHeader = { | ||
expiry: new TransactionExpiry(new Date(Date.now() + 3600000)), | ||
nonce: 1n, // the next nonce for this account, can be found using getNextAccountNonce | ||
sender: new AccountAddress("4ZJBYQbVp3zVZyjCXfZAAYBVkJMyVj8UKUNj9ox5YqTCBdBq2M"), | ||
}; | ||
const configureDelegationPayload: ConfigureDelegationPayload = { | ||
stake: new GtuAmount(1000000000n), | ||
delegationTarget: { | ||
delegateType: DelegationTargetType.Baker, | ||
bakerId: 100n | ||
}, | ||
restakeEarnings: true, | ||
}; | ||
const configureDelegationAccountTransaction: AccountTransaction = { | ||
header: header, | ||
payload: configureDelegationPayload, | ||
type: AccountTransactionType.ConfigureDelegation, | ||
}; | ||
``` | ||
## Create a credential for an existing account | ||
The following example demonstrates how to create a credential for an existing account. This | ||
credential can then be deployed onto the account by the account owner with an update | ||
credentials transaction. See [Create an update credentials transaction](#Create-an-update-credentials-transaction) for how to | ||
create this transaction payload using the output from the example below. | ||
See [Construct IdentityInput](#Construct-identityInput-for-creating-credentials) for how to construct an IdentityInput. | ||
```js | ||
const lastFinalizedBlockHash = (await client.getConsensusStatus()).lastFinalizedBlock; | ||
const cryptographicParameters = await client.getCryptographicParameters(lastFinalizedBlockHash); | ||
if (!cryptographicParameters) { | ||
throw new Error('Cryptographic parameters were not found on a block that has been finalized.'); | ||
} | ||
// The parts of the identity required to create a new credential, parsed from | ||
// e.g. a wallet export. | ||
const identityInput: IdentityInput = ... | ||
// Require just one key on the credential to sign. This can be any number | ||
// up to the number of public keys added to the credential. | ||
const threshold: number = 1; | ||
// The index of the credential that will be created. This index is per identity | ||
// and has to be in sequence, and not already used. Note that index 0 is used | ||
// by the initial credential that was created with the identity. | ||
const credentialIndex: number = 1; | ||
// In this example the credential will have one signing key, but there | ||
// could be multiple. The signatures on the credential must be supplied | ||
// in the same order as the keys are here. | ||
const publicKeys: VerifyKey[] = [ | ||
{ | ||
schemeId: "Ed25519", | ||
verifyKey: "c8cd7623c5a9316d8e2fccb51e1deee615bdb5d324fb4a6d33801848fb5e459e" | ||
} | ||
]; | ||
// The attributes to reveal about the account holder on chain. In the case of an | ||
// empty array no attributes are revealed. | ||
const revealedAttributes: AttributeKey[] = []; | ||
// The next step creates an unsigned credential for an existing account. | ||
// Note that unsignedCredentialForExistingAccount also contains the randomness used, | ||
// which should be saved to later be able to reveal attributes, or prove properties about them. | ||
const existingAccountAddress = new AccountAddress("3sAHwfehRNEnXk28W7A3XB3GzyBiuQkXLNRmDwDGPUe8JsoAcU"); | ||
const unsignedCredentialForExistingAccount = createUnsignedCredentialForExistingAccount( | ||
identityInput, | ||
cryptographicParameters.value, | ||
threshold, | ||
publicKeys, | ||
credentialIndex, | ||
revealedAttributes, | ||
existingAccountAddress | ||
); | ||
// Sign the credential information. | ||
const credentialDigestToSign = getCredentialForExistingAccountSignDigest(unsignedCredentialForExistingAccount.unsignedCdi, existingAccountAddress); | ||
const credentialSigningKey = 'acab9ec5dfecfe5a6e13283f7ca79a6f6f5c685f036cd044557969e4dbe9d781'; | ||
const credentialSignature = Buffer.from(await ed.sign(credentialDigestToSign, credentialSigningKey)).toString('hex'); | ||
// Combine the credential and the signatures so that the object is ready | ||
// to be submitted as part of an update credentials transaction. This is the | ||
// object that must be provided to the account owner, who can then use it to | ||
// deploy it to their account. | ||
const signedCredentialForExistingAccount: CredentialDeploymentInfo = buildSignedCredentialForExistingAccount(unsignedCredentialForExistingAccount.unsignedCdi, [credentialSignature]); | ||
``` | ||
## Create an update credentials transaction | ||
The following demonstrates how to construct an update credentials transaction, which is | ||
used to deploy additional credentials to an account, remove existing credentials on the account | ||
or to update the credential threshold on the account. Note that the initial credential with | ||
index 0 cannot be removed. | ||
```js | ||
// The signed credential that is to be deployed on the account. Received from the | ||
// credential holder. | ||
const signedCredentialForExistingAccount: CredentialDeploymentInfo = ... | ||
// The credentials that are deployed have to be indexed. Index 0 is used up | ||
// by the initial credential on an account. The indices that have already been | ||
// used can be found in the AccountInfo. | ||
const accountAddress = new AccountAddress("3sAHwfehRNEnXk28W7A3XB3GzyBiuQkXLNRmDwDGPUe8JsoAcU"); | ||
const accountInfo = await client.getAccountInfo(accountAddress, lastFinalizedBlockHash); | ||
const nextAvailableIndex = Math.max(...Object.keys(accountInfo.accountCredentials).map((key) => Number(key))) + 1; | ||
// The current number of credentials on the account is required, as it is used to calculate | ||
// the correct energy cost. | ||
const currentNumberOfCredentials = BigInt(Object.keys(accountInfo.accountCredentials).length); | ||
const newCredential: IndexedCredentialDeploymentInfo = { | ||
cdi: signedCredentialForExistingAccount, | ||
index: nextAvailableIndex | ||
}; | ||
// List the credential id (credId) of any credentials that should be removed from the account. | ||
// The existing credentials (and their credId) can be found in the AccountInfo. | ||
const credentialsToRemove = ["b0f11a9dcdd0758c8eec717956455deed73a0db59995da2cb20d73ee974eb39aec2c79970c640126827a8fbb84217424"]; | ||
// Update the credential threshold to 2, so that transactions require signatures from both | ||
// of the credentials. If left at e.g. 1, then both credentials can create transactions | ||
// by themselves. | ||
const threshold = 2; | ||
const updateCredentialsPayload: UpdateCredentialsPayload = { | ||
newCredentials: [newCredential], | ||
removeCredentialIds: credentialsToRemove, | ||
threshold: threshold, | ||
currentNumberOfCredentials: currentNumberOfCredentials, | ||
}; | ||
``` | ||
## Send Account Transaction | ||
The following example demonstrates how to send any account transaction. | ||
See the previous sections for how to create an account transaction. | ||
```js | ||
import * as ed from "noble-ed25519"; | ||
let accountTransaction: AccountTransaction; | ||
@@ -233,18 +78,6 @@ // Create the transaction | ||
// Sign the transaction, the following is just an example, and any method for signing | ||
// with the key can be employed. | ||
const signingKey = "ce432f6bba0d47caec1f45739331dc354b6d749fdb8ab7c2b7f6cb24db39ca0c"; | ||
const hashToSign = getAccountTransactionSignDigest(accountTransaction); | ||
const signature = Buffer.from(await ed.sign(hashToSign, signingKey)).toString("hex"); | ||
let signatures: AccountTransactionSignature; | ||
// Sign the transaction | ||
// ... | ||
// The signatures used to sign the transaction must be provided in a structured way, | ||
// so that each signature can be mapped to the credential that signed the transaction. | ||
// In this example we assume the key used was from the credential with index 0, and it | ||
// was the key with index 0. | ||
const signatures: AccountTransactionSignature = { | ||
0: { | ||
0: signature | ||
} | ||
}; | ||
// Send the transaction to the node. | ||
@@ -415,26 +248,2 @@ const success = await client.sendAccountTransaction(accountTransaction, signatures); | ||
## Generate account alias | ||
The following shows how to generate an account alias. The alias is an alternative address, which is connected to the same account. | ||
The getAlias function takes a counter (0 <= counter < 2^24) to determine which alias to return. | ||
``` | ||
const accountAddress = new AccountAddress("3sAHwfehRNEnXk28W7A3XB3GzyBiuQkXLNRmDwDGPUe8JsoAcU"); | ||
const aliasCount = 1; | ||
const alias: AccountAddress = getAlias(accountAddress, aliasCount); | ||
``` | ||
## Check for account alias | ||
The following shows how to check if two addresses are aliases. | ||
``` | ||
const accountAddress = new AccountAddress("3sAHwfehRNEnXk28W7A3XB3GzyBiuQkXLNRmDwDGPUe8JsoAcU"); | ||
const anotherAccountAddress = new AccountAddress("3sAHwfehRNEnXk28W7A3XB3GzyBiuQkXLNRmDwDGJhiz8WxC5b"); | ||
if (isAlias(accountAddress, anotherAccountAddress)) { | ||
... // the addresses are aliases | ||
} else { | ||
... // the addresses are not aliases | ||
} | ||
``` | ||
## getAccountInfo | ||
@@ -560,3 +369,3 @@ Retrieves information about an account. The function must be provided an account address or a credential registration id. | ||
There are also type checks for specific fields in the summary, which can be found in [blockSummaryHelpers](src/blockSummaryHelpers.ts). | ||
There are also type checks for specific fields in the summary, which can be found in [blockSummaryHelpers](../common/src/blockSummaryHelpers.ts). | ||
@@ -682,217 +491,2 @@ ## getBlockInfo | ||
## Deploy module | ||
The following example demonstrates how to deploy a smart contract module. | ||
```js | ||
/** | ||
* | ||
* @param filePath for the wasm file moudule | ||
* @returns Buffer of the wasm file | ||
*/ | ||
function getByteArray(filePath: string): Buffer { | ||
const data = fs.readFileSync(filePath); | ||
return Buffer.from(data); | ||
} | ||
//To get the buffer of the wasm file from the previous method | ||
const wasmFileBuffer = getByteArray(wasmFilePath) as Buffer; | ||
const deployModule: DeployModulePayload = { | ||
content: wasmFileBuffer, | ||
version: 0, | ||
}; | ||
const header: AccountTransactionHeader = { | ||
expiry: new TransactionExpiry(new Date(Date.now() + 3600000)), | ||
nonce: nextAccountNonce.nonce, | ||
sender: new AccountAddress(senderAccountAddress), | ||
}; | ||
const deployModuleTransaction: AccountTransaction = { | ||
header: header, | ||
payload: deployModule, | ||
type: AccountTransactionType.DeployModule, | ||
}; | ||
``` | ||
Finally, to actually deploy the module to the chain, send the constructed `deployModuleTransaction` to the chain using `sendAccountTransaction`. (See [Send Account Transaction](#Send-Account-Transaction) for how to do this) | ||
## Init Contract (parameterless smart contract) | ||
The following example demonstrates how to initialize a smart contract from a module, which has already been deployed. | ||
The name of the contract "INDBank". | ||
In this example, the contract does not take any parameters, so we can leave parameters as an empty buffer. | ||
```js | ||
const contractName = 'INDBank'; | ||
const params = Buffer.from([]); | ||
//The amount of energy that can be used for contract execution. | ||
const maxContractExecutionEnergy = 300000n; | ||
``` | ||
Create init contract transaction | ||
```js | ||
const initModule: InitContractPayload = { | ||
amount: new GtuAmount(0n), // Amount to send to the contract. If the smart contract is not payable, set the amount to 0. | ||
moduleRef: new ModuleReference('a225a5aeb0a5cf9bbc59209e15df030e8cc2c17b8dba08c4bf59f80edaedd8b1'), // Module reference | ||
contractName: contractName, | ||
parameter: params, | ||
maxContractExecutionEnergy: maxContractExecutionEnergy | ||
}; | ||
const initContractTransaction: AccountTransaction = { | ||
header: header, | ||
payload: initModule, | ||
type: AccountTransactionType.InitializeSmartContractInstance, | ||
}; | ||
``` | ||
Finally, to actually initialize the contract on the chain, send the constructed `initContractTransaction` to the chain using `sendAccountTransaction`. (See [Send Account Transaction](#Send-Account-Transaction) for how to do this) | ||
## Update Contract (parameterless smart contract) | ||
The following example demonstrates how to update a smart contract. | ||
To update a smart contract we create a 'updateContractTransaction'. | ||
To do this we need to specify the name of the receive function, which should contain the contract name as a prefix (So if the contract has the name "INDBank" and the receive function has the name "insertAmount" then the receiveName should be "INDBank.insertAmount"). | ||
We also need to supply the contract address of the contract instance. This consists of an index and a subindex. | ||
In this example, the contract does not take any parameters, so we can leave the parameters as an empty buffer. | ||
```js | ||
const receiveName = 'INDBank.insertAmount'; | ||
const params = Buffer.from([]); | ||
const contractAddress = { index: BigInt(83), subindex: BigInt(0) } as ContractAddress; | ||
//The amount of energy that can be used for contract execution. | ||
const maxContractExecutionEnergy = 30000n; | ||
``` | ||
Create update contract transaction | ||
```js | ||
const updateModule: UpdateContractPayload = | ||
{ | ||
amount: new GtuAmount(1000n), | ||
contractAddress: contractAddress, | ||
receiveName: receiveName, | ||
parameter: params, | ||
maxContractExecutionEnergy: maxContractExecutionEnergy | ||
}; | ||
const updateContractTransaction: AccountTransaction = { | ||
header: header, | ||
payload: updateModule, | ||
type: AccountTransactionType.UpdateSmartContractInstance, | ||
}; | ||
``` | ||
Finally, to actually update the contract on the chain, send the constructed `updateContractTransaction` to the chain using `sendAccountTransaction`. (See [Send Account Transaction](#Send-Account-Transaction) for how to do this) | ||
## Smart contract with parameters | ||
In the previous sections we have seen how to initialize and update contracts without parameters. In this section we will describe how to initialize and update contracts with parameters. | ||
The user should provide the input in the JSON format specified in [our documentation](https://developer.concordium.software/en/mainnet/smart-contracts/references/schema-json.html). | ||
Let us consider the following example where the contract's initialization parameter is the following structure: | ||
```rust | ||
#[derive(SchemaType, Serialize)] | ||
struct MyStruct { | ||
age: u16, | ||
name: String, | ||
city: String, | ||
} | ||
``` | ||
An example of a valid input would be: | ||
```js | ||
const userInput = { | ||
age: 51, | ||
name: 'Concordium', | ||
city: 'Zug', | ||
}; | ||
``` | ||
An other example could be if the parameter is the following "SomeEnum": | ||
```rust | ||
#[derive(SchemaType, Serialize)] | ||
enum AnotherEnum { | ||
D, | ||
} | ||
#[derive(SchemaType, Serialize)] | ||
enum SomeEnum { | ||
B(AnotherEnum), | ||
} | ||
``` | ||
Then the following would be a valid input: | ||
```js | ||
const userInput = { | ||
B: [ | ||
{ | ||
D: [] | ||
} | ||
] | ||
}; | ||
``` | ||
Then the user needs to provide the schema for the module. Here we use getModuleBuffer to load the schema file: | ||
```js | ||
const modulefileBuffer = getModuleBuffer( | ||
'SCHEMA-FILE-PATH' | ||
); | ||
``` | ||
Then the parameters can be serialized into bytes: | ||
```js | ||
const inputParams = serializeInitContractParameters( | ||
"my-contract-name", | ||
userInput, | ||
modulefileBuffer | ||
); | ||
``` | ||
Then the payload and transaction can be constructed, in the same way as the parameterless example: | ||
```js | ||
const initModule: InitContractPayload = { | ||
amount: new GtuAmount(0n), | ||
moduleRef: new ModuleReference( | ||
'6cabee5b2d9d5013216eef3e5745288dcade77a4b1cd0d7a8951262476d564a0' | ||
), | ||
contractName: contractName, | ||
parameter: inputParams, | ||
maxContractExecutionEnergy: baseEnergy, | ||
}; | ||
const initContractTransaction: AccountTransaction = { | ||
header: header, | ||
payload: initModule, | ||
type: AccountTransactionType.InitializeSmartContractInstance, | ||
}; | ||
``` | ||
Finally, to actually initialize the contract on the chain, send the constructed `initContractTransaction` to the chain using `sendAccountTransaction`. (See [Send Account Transaction](#Send-Account-Transaction) for how to do this) | ||
To update a contract with parameters, consider the example where the input is an i64 value, like -2000000. | ||
```js | ||
const userInput = -2000000; | ||
const contractName = "my-contract-name"; | ||
const receiveFunctionName = "my-receive-function-name"; | ||
const receiveName = contractName + '.' + receiveFunctionName; | ||
``` | ||
Then the user need to provide the schema. Here we use getModuleBuffer to load the schema file: | ||
```js | ||
const modulefileBuffer = getModuleBuffer( | ||
'SCHEMA-PATH' | ||
); | ||
``` | ||
Then the parameters can be serialized into bytes: | ||
```js | ||
const inputParams = serializeUpdateContractParameters( | ||
contractName, | ||
receiveFunctionName, | ||
userInput, | ||
modulefileBuffer | ||
); | ||
``` | ||
Then we will construct the update payload with parameters obtained | ||
```js | ||
const updateModule: UpdateContractPayload = { | ||
amount: new GtuAmount(1000n), | ||
contractAddress: contractAddress, | ||
receiveName: receiveName, | ||
parameter: inputParams, | ||
maxContractExecutionEnergy: baseEnergy, | ||
} as UpdateContractPayload; | ||
const updateContractTransaction: AccountTransaction = { | ||
header: header, | ||
payload: updateModule, | ||
type: AccountTransactionType.UpdateSmartContractInstance, | ||
}; | ||
``` | ||
Finally, to actually update the contract on the chain, send the constructed `updateContractTransaction` to the chain using `sendAccountTransaction`. (See [Send Account Transaction](#Send-Account-Transaction) for how to do this) | ||
## getInstances | ||
@@ -961,21 +555,13 @@ Used to get the full list of contract instances on the chain at a specific block. | ||
## Deserialize contract state | ||
The following example demonstrates how to deserialize a contract's state: | ||
```js | ||
const contractName = "my-contract-name" | ||
const schema = Buffer.from(schemaSource); // Load schema from file | ||
const rawContractState = Buffer.from(stateSource); // Could be getinstanceInfo(...).model (if contract is version 0) | ||
const state = deserializeContractState(contractName, schema, rawContractState); | ||
``` | ||
# Build | ||
## Building for a release | ||
To build the project run | ||
To build the package run | ||
``` | ||
yarn build | ||
``` | ||
Note that you must have [wasm-pack](https://rustwasm.github.io/wasm-pack/) installed to build the project. | ||
Note that the dependent packages must already have been built. To easily do this, build from the package root instead. | ||
## Publishing a release | ||
@@ -985,15 +571,6 @@ Before publishing a new release it is essential that it has been built first. So make sure that | ||
``` | ||
yarn publish | ||
yarn npm publish | ||
``` | ||
and step through the steps precented to you. | ||
and step through the steps presented to you. | ||
## Updating the gRPC files | ||
If the external dependency concordium-grpc-api has been updated (or this is your first time building the project), | ||
then it is required to regenerate the files from the `.proto` file. Do this by running: | ||
``` | ||
yarn generate | ||
``` | ||
This will overwrite the existing files in `src/grpc/`. Remember to check that existing functionality still | ||
works after performing an update. | ||
# Test | ||
@@ -1000,0 +577,0 @@ An automatic test suite is part of this project, and it is run by executing: |
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
3
-40%18
-5.26%0
-100%378824
-81.61%16
-75.38%7438
-39.36%1
Infinity%575
-42.38%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed