Skip to content

Commit

Permalink
Merge pull request #154 from Concordium/enable-initializing-new-smart…
Browse files Browse the repository at this point in the history
…-contract-from-the-existing-module-reference

Add option to `deriveFromChain` given a module reference when initializing a contract instance
  • Loading branch information
DOBEN authored Feb 20, 2024
2 parents bbae075 + 637665f commit 6daa288
Show file tree
Hide file tree
Showing 11 changed files with 510 additions and 331 deletions.
4 changes: 4 additions & 0 deletions front-end-tools/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 3.1.0

- Add option to `deriveFromChain` given a module reference in Step 2.

## 3.0.2

- Fix error message when specifying input parameter without uploading schema.
Expand Down
12 changes: 9 additions & 3 deletions front-end-tools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@
The front end contains useful functionalities for smart contract developers:

- Upload and deploy a smart contract module to chain.
- Initialize a smart contract module on chain.
- Initialize a smart contract instance on chain.
- Invoke a smart contract on chain (reading from chain).
- Update a smart contract on chain (writing to chain).

Only the browser wallet is supported in the first version (no support for mobile wallets).

## Hosted front end

[Hosted front end link](https://sctools.mainnet.concordium.software/)

## Prerequisites

- Browser wallet extension must be installed in a Chromium-based browser.
Expand All @@ -30,13 +36,13 @@ To start the front end locally, do the following:

- Run `yarn build` in this folder.
- Run `yarn start` in this folder.
- Open URL logged in console (typically http://127.0.0.1:8080).
- Open URL logged in console (typically http://127.0.0.1:5173).

To have hot-reload (useful for development), do the following instead:

- Run `yarn watch` in this folder in a terminal.
- Run `yarn start` in this folder in another terminal.
- Open URL logged in console (typically http://127.0.0.1:8080).
- Open URL logged in console (typically http://127.0.0.1:5173).

## Using yarn (on Unix/macOS systems)

Expand Down
2 changes: 1 addition & 1 deletion front-end-tools/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "front-end-tools",
"packageManager": "yarn@4.0.2",
"version": "3.0.2",
"version": "3.1.0",
"license": "Apache-2.0",
"engines": {
"node": ">=16.x"
Expand Down
14 changes: 4 additions & 10 deletions front-end-tools/src/Main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
MAINNET,
useWalletConnectorSelector,
} from '@concordium/react-components';
import { ModuleReference } from '@concordium/web-sdk';

import { Alert } from 'react-bootstrap';
import DeployComponent from './components/DeployComponent';
Expand Down Expand Up @@ -48,10 +49,9 @@ export default function Main(props: ConnectionProps) {
const [accountBalance, setAccountBalance] = useState<string | undefined>(undefined);

// Shared state between deploy step and init step
const [moduleReferenceCalculated, setModuleReferenceCalculated] = useState<string | undefined>(undefined);
const [moduleReferenceDeployed, setModuleReferenceDeployed] = useState<string | undefined>(undefined);
const [contracts, setContracts] = useState<string[]>([]);
const [embeddedModuleSchemaBase64Init, setEmbeddedModuleSchemaBase64Init] = useState<string | undefined>(undefined);
const [moduleReferenceCalculated, setModuleReferenceCalculated] = useState<ModuleReference.Type | undefined>(
undefined
);

// Refresh accountInfo periodically.
// eslint-disable-next-line consistent-return
Expand Down Expand Up @@ -135,22 +135,16 @@ export default function Main(props: ConnectionProps) {
connection={connection}
account={account}
client={client}
setContracts={setContracts}
moduleReferenceCalculated={moduleReferenceCalculated}
setModuleReferenceDeployed={setModuleReferenceDeployed}
setModuleReferenceCalculated={setModuleReferenceCalculated}
setEmbeddedModuleSchemaBase64Init={setEmbeddedModuleSchemaBase64Init}
/>

<InitComponent
isTestnet={isTestnet}
connection={connection}
account={account}
client={client}
contracts={contracts}
moduleReferenceDeployed={moduleReferenceDeployed}
moduleReferenceCalculated={moduleReferenceCalculated}
embeddedModuleSchemaBase64={embeddedModuleSchemaBase64Init}
/>

<ReadComponent connection={connection} account={account} client={client} />
Expand Down
57 changes: 6 additions & 51 deletions front-end-tools/src/components/DeployComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React, { useEffect, useState } from 'react';
import { useForm } from 'react-hook-form';
import { Alert, Button, Form } from 'react-bootstrap';
import { Buffer } from 'buffer';

import { WalletConnection } from '@concordium/react-components';
import {
Expand All @@ -25,29 +24,16 @@ interface ConnectionProps {
connection: WalletConnection;
client: ConcordiumGRPCClient | undefined;
isTestnet: boolean;
setContracts: (contracts: string[]) => void;
setEmbeddedModuleSchemaBase64Init: (embeddedModuleSchemaBase64Init: string) => void;
setModuleReferenceDeployed: (moduleReferenceDeployed: string | undefined) => void;
setModuleReferenceCalculated: (moduleReferenceCalculated: string) => void;
moduleReferenceCalculated: string | undefined;
setModuleReferenceCalculated: (moduleReferenceCalculated: ModuleReference.Type) => void;
moduleReferenceCalculated: ModuleReference.Type | undefined;
}

/**
* A component that manages the input fields and corresponding state to deploy a new smart contract wasm module on chain.
* This components creates a `DeployModule` transaction.
*/
export default function DeployComponenet(props: ConnectionProps) {
const {
isTestnet,
client,
connection,
account,
setContracts,
setModuleReferenceDeployed,
setModuleReferenceCalculated,
moduleReferenceCalculated,
setEmbeddedModuleSchemaBase64Init,
} = props;
const { isTestnet, client, connection, account, setModuleReferenceCalculated, moduleReferenceCalculated } = props;

type FormType = {
file: FileList | undefined;
Expand Down Expand Up @@ -76,7 +62,6 @@ export default function DeployComponenet(props: ConnectionProps) {
report.outcome.summary.transactionType === TransactionKindString.DeployModule
) {
setTransactionOutcome('Success');
setModuleReferenceDeployed(report.outcome.summary.moduleDeployed.contents);
clearInterval(interval);
} else {
setTransactionOutcome('Fail');
Expand All @@ -85,7 +70,6 @@ export default function DeployComponenet(props: ConnectionProps) {
}
})
.catch((e) => {
setModuleReferenceDeployed(undefined);
setTransactionOutcome(`Fail; Error: ${(e as Error).message}`);
clearInterval(interval);
});
Expand All @@ -97,7 +81,7 @@ export default function DeployComponenet(props: ConnectionProps) {
useEffect(() => {
if (connection && client && moduleReferenceCalculated) {
client
.getModuleSource(ModuleReference.fromHexString(moduleReferenceCalculated))
.getModuleSource(moduleReferenceCalculated)
.then((value) => {
if (value === undefined) {
setIsModuleReferenceAlreadyDeployedStep1(false);
Expand All @@ -120,7 +104,6 @@ export default function DeployComponenet(props: ConnectionProps) {

const tx = deploy(connection, AccountAddress.fromBase58(account), base64Module);
tx.then((txHash) => {
setModuleReferenceDeployed(undefined);
setTxHashDeploy(txHash);
}).catch((err: Error) => setTransactionErrorDeploy((err as Error).message));
}
Expand All @@ -140,7 +123,6 @@ export default function DeployComponenet(props: ConnectionProps) {
register.onChange(e);

setUploadError(undefined);
setModuleReferenceDeployed(undefined);
setTransactionErrorDeploy(undefined);
setTxHashDeploy(undefined);

Expand All @@ -160,7 +142,7 @@ export default function DeployComponenet(props: ConnectionProps) {

setBase64Module(module);
setModuleReferenceCalculated(
Buffer.from(sha256([new Uint8Array(arrayBuffer)])).toString('hex')
ModuleReference.fromBuffer(sha256([new Uint8Array(arrayBuffer)]))
);

// Concordium's tooling create versioned modules e.g. `.wasm.v1` now.
Expand Down Expand Up @@ -195,33 +177,6 @@ export default function DeployComponenet(props: ConnectionProps) {
}

if (wasmModule) {
const moduleFunctions = WebAssembly.Module.exports(wasmModule);

const contractNames = [];
for (let i = 0; i < moduleFunctions.length; i += 1) {
if (moduleFunctions[i].name.startsWith('init_')) {
contractNames.push(moduleFunctions[i].name.slice(5));
}
}
setContracts(contractNames);

const customSection = WebAssembly.Module.customSections(
wasmModule,
'concordium-schema'
);

const schema = new Uint8Array(customSection[0]);

// Use `reduce` to be able to convert large schema.
const moduleSchemaBase64Embedded = btoa(
new Uint8Array(schema).reduce(
(data, byte) => data + String.fromCharCode(byte),
''
)
);

setEmbeddedModuleSchemaBase64Init(moduleSchemaBase64Embedded);

// Check if the module was built as a reproducible build.
const buildInfoSection = WebAssembly.Module.customSections(
wasmModule,
Expand Down Expand Up @@ -250,7 +205,7 @@ export default function DeployComponenet(props: ConnectionProps) {
<>
<div className="actionResultBox">
Calculated module reference:
<div>{moduleReferenceCalculated}</div>
<div>{moduleReferenceCalculated.moduleRef}</div>
</div>
<div className="actionResultBox">
Module in base64:
Expand Down
Loading

0 comments on commit 6daa288

Please sign in to comment.