Skip to content

Commit

Permalink
Merge branch 'main' into delegation
Browse files Browse the repository at this point in the history
  • Loading branch information
soerenbf committed Mar 9, 2022
2 parents 0bbb678 + 0984d20 commit a373deb
Show file tree
Hide file tree
Showing 74 changed files with 5,253 additions and 146 deletions.
129 changes: 121 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,7 @@ const header: AccountTransactionHeader = {

const deployModuleTransaction: AccountTransaction = {
header: header,
payload: deployModule as AccountTransactionPayload,
payload: deployModule,
type: AccountTransactionType.DeployModule,
};
```
Expand All @@ -623,14 +623,13 @@ Finally, to actually deploy the module to the chain, send the constructed `deplo
## 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 params as an empty Buffer.
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 = {
Expand All @@ -640,7 +639,6 @@ const initModule: InitContractPayload = {
parameter: params,
maxContractExecutionEnergy: maxContractExecutionEnergy
};

const initContractTransaction: AccountTransaction = {
header: header,
payload: initModule,
Expand All @@ -650,15 +648,15 @@ const initContractTransaction: AccountTransaction = {

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)
## 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").
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 list.
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([]);
Expand All @@ -676,7 +674,6 @@ const updateModule: UpdateContractPayload =
parameter: params,
maxContractExecutionEnergy: maxContractExecutionEnergy
};

const updateContractTransaction: AccountTransaction = {
header: header,
payload: updateModule,
Expand All @@ -686,6 +683,122 @@ const updateContractTransaction: AccountTransaction = {

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)

## Deserialize contract state
The following example demonstrates how to deserialize a contract's state:

Expand Down
9 changes: 5 additions & 4 deletions src/accountTransactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,9 @@ export class InitContractHandler
);
const serializedInitName = packBufferWithWord16Length(initNameBuffer);
const serializedModuleRef = payload.moduleRef.decodedModuleRef;
const serializedParameters = packBufferWithWord16Length(
Buffer.from(payload.parameter)
);
const parameterBuffer = payload.parameter;
const serializedParameters =
packBufferWithWord16Length(parameterBuffer);
return Buffer.concat([
serializedAmount,
serializedModuleRef,
Expand Down Expand Up @@ -120,8 +120,9 @@ export class UpdateContractHandler
const receiveNameBuffer = Buffer.from(payload.receiveName, 'utf8');
const serializedReceiveName =
packBufferWithWord16Length(receiveNameBuffer);
const parameterBuffer = payload.parameter;
const serializedParameters = packBufferWithWord16Length(
Buffer.from(payload.parameter)
Buffer.from(parameterBuffer)
);
return Buffer.concat([
serializedAmount,
Expand Down
20 changes: 20 additions & 0 deletions src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
Empty,
GetAddressInfoRequest,
GetPoolStatusRequest,
GetModuleSourceRequest,
PeerListResponse,
PeersRequest,
SendTransactionRequest,
Expand Down Expand Up @@ -758,6 +759,25 @@ export default class ConcordiumNodeClient {
);
}

async getModuleSource(
blockHash: string,
moduleReference: ModuleReference
): Promise<Uint8Array> {
if (!isValidHash(blockHash)) {
throw new Error('The input was not a valid hash: ' + blockHash);
}
const requestObject = new GetModuleSourceRequest();
requestObject.setBlockHash(blockHash);
requestObject.setModuleRef(moduleReference.moduleRef);

const response = await this.sendRequest(
this.client.getModuleSource,
requestObject
);

return response;
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types
sendRequest<T>(command: any, input: T): Promise<Uint8Array> {
const deadline = new Date(Date.now() + this.timeout);
Expand Down
Loading

0 comments on commit a373deb

Please sign in to comment.