Skip to content

Commit

Permalink
181 address list of websites (#182)
Browse files Browse the repository at this point in the history
* Add DeWeb index base sc

* Add tests for updateWebsite and removeWebsite

* Update DeWeb Index Smart Contract README title

* Refactor website management functions to improve owner validation and add base key indexing

* Update tests following changes

* Move utility functions to a separate file

* Enhance address handling and storage key generation

* Update tests

* Simplify tags

* Update wasm path in deploy script
  • Loading branch information
thomas-senechal authored Dec 13, 2024
1 parent 920bbc7 commit 77056fb
Show file tree
Hide file tree
Showing 20 changed files with 11,081 additions and 0 deletions.
1 change: 1 addition & 0 deletions deweb-index/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
PRIVATE_KEY=
6 changes: 6 additions & 0 deletions deweb-index/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
extends: ['@massalabs'],
rules: {
'no-console': 'off',
},
};
3 changes: 3 additions & 0 deletions deweb-index/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
node_modules
build
.env
60 changes: 60 additions & 0 deletions deweb-index/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# DeWeb Index Smart Contract

## Build

By default this will build all files in `assembly/contracts` directory.

```shell
npm run build
```

## Deploy a smart contract

Prerequisites :

- You must add a `.env` file at the root of the repository with the following keys set to valid values :
- WALLET_SECRET_KEY="wallet_secret_key"
- JSON_RPC_URL_PUBLIC=<https://test.massa.net/api/v2:33035>

These keys will be the ones used by the deployer script to interact with the blockchain.

The following command will build contracts in `assembly/contracts` directory and execute the deployment script
`src/deploy.ts`. This script will deploy on the node specified in the `.env` file.

```shell
npm run deploy
```

You can modify `src/deploy.ts` to change the smart contract being deployed, and to pass arguments to the constructor
function:

- line 31: specify what contract you want to deploy
- line 33: create the `Args` object to pass to the constructor of the contract you want to deploy

When the deployment operation is executed on-chain, the
[constructor](https://github.com/massalabs/massa-sc-toolkit/blob/main/packages/sc-project-initializer/commands/init/assembly/contracts/main.ts#L10)
function of the smart contract being deployed will
be called with the arguments provided in the deployment script.

The deployment script uses [massa-sc-deployer library](https://www.npmjs.com/package/@massalabs/massa-sc-deployer)
to deploy smart contracts.

You can edit this script and use [massa-web3 library](https://www.npmjs.com/package/@massalabs/massa-web3)
to create advanced deployment procedure.

For more information, please visit our ReadTheDocs about
[Massa smart-contract development](https://docs.massa.net/en/latest/web3-dev/smart-contracts.html).

## Unit tests

The test framework documentation is available here: [as-pect docs](https://as-pect.gitbook.io/as-pect)

```shell
npm run test
```

## Format code

```shell
npm run fmt
```
24 changes: 24 additions & 0 deletions deweb-index/as-pect.asconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"targets": {
"coverage": {
"lib": ["./node_modules/@as-covers/assembly/index.ts"],
"transform": ["@as-covers/transform", "@as-pect/transform"]
},
"noCoverage": {
"transform": ["@as-pect/transform"]
}
},
"options": {
"exportMemory": true,
"outFile": "output.wasm",
"textFile": "output.wat",
"bindings": "raw",
"exportStart": "_start",
"exportRuntime": true,
"use": ["RTRACE=1"],
"debug": true,
"exportTable": true
},
"extends": "./asconfig.json",
"entries": ["./node_modules/@as-pect/assembly/assembly/index.ts"]
}
28 changes: 28 additions & 0 deletions deweb-index/as-pect.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import createMockedABI from '@massalabs/massa-as-sdk/vm-mock';

export default {
/**
* A set of globs passed to the glob package that qualify typescript files for testing.
*/
entries: ['assembly/__tests__/**/*.spec.ts'],
/**
* A set of globs passed to the glob package that quality files to be added to each test.
*/
include: ['assembly/__tests__/**/*.include.ts'],
/**
* A set of regexp that will disclude source files from testing.
*/
disclude: [/node_modules/],
/**
* Add your required AssemblyScript imports here.
*/
async instantiate(memory, createImports, instantiate, binary) {
return createMockedABI(memory, createImports, instantiate, binary);
},
/** Enable code coverage. */
// coverage: ["assembly/**/*.ts"],
/**
* Specify if the binary wasm file should be written to the file system.
*/
outputBinary: false,
};
13 changes: 13 additions & 0 deletions deweb-index/asconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"targets": {
"release": {
"sourceMap": true,
"optimizeLevel": 3,
"shrinkLevel": 3,
"converge": true,
"noAssert": false,
"exportRuntime": true,
"bindings": false
}
}
}
1 change: 1 addition & 0 deletions deweb-index/assembly/__tests__/as-pect.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="@as-pect/assembly/types/as-pect" />
13 changes: 13 additions & 0 deletions deweb-index/assembly/__tests__/const.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Address } from '@massalabs/massa-as-sdk';

export const scOwner = new Address(
'AU12Rdc4THDQALpocVBnkPNy7y5CndUJQTLutaVDDFgMJcq5kQiKq',
);
export const websiteOwner = new Address(
'AU12IeSDxoHDAxo1xEcVBnkPNy7y5CndUSLTLatoFCCFgMJcq5kQiEs',
);
export const websiteAddress = new Address(
'AS12UBnqTHDQALpocVCDez2oeoa5CndUJQTLccEscDFgEoPaC3sqVz',
);

export const version = '1';
49 changes: 49 additions & 0 deletions deweb-index/assembly/__tests__/remove_website.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Args, stringToBytes } from '@massalabs/as-types';
import {
resetStorage,
setDeployContext,
setOf,
Storage,
} from '@massalabs/massa-as-sdk';
import { OWNER_KEY } from '@massalabs/sc-standards/assembly/contracts/utils/ownership-internal';

import {
constructor,
DEWEB_VERSION_TAG,
removeWebsite,
updateWebsite,
} from '../contracts/deweb-index';
import { _indexByOwnerBaseKey } from '../contracts/utils';

import { scOwner, version, websiteAddress, websiteOwner } from './const';

describe('removeWebsite tests', () => {
beforeEach(() => {
resetStorage();
setDeployContext(scOwner.toString());
setOf(websiteAddress, OWNER_KEY, websiteOwner.toString());
setOf(websiteAddress, DEWEB_VERSION_TAG, stringToBytes(version));
constructor([]);

const args = new Args().add(websiteAddress).serialize();
updateWebsite(args);
});

test('remove website', () => {
const args = new Args().add(websiteAddress).serialize();
removeWebsite(args);

const key = Storage.getKeys(
_indexByOwnerBaseKey(websiteOwner.toString()).concat(
stringToBytes(websiteAddress.toString()),
),
);
expect(key).toHaveLength(0);
});

throws('if the caller is not the owner', () => {
const args = new Args().add(websiteAddress).serialize();
setDeployContext(websiteOwner.toString());
removeWebsite(args);
});
});
122 changes: 122 additions & 0 deletions deweb-index/assembly/__tests__/update_website.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { Args, stringToBytes } from '@massalabs/as-types';
import {
deleteOf,
resetStorage,
setDeployContext,
setOf,
Storage,
} from '@massalabs/massa-as-sdk';
import { OWNER_KEY } from '@massalabs/sc-standards/assembly/contracts/utils/ownership-internal';

import {
constructor,
DEWEB_VERSION_TAG,
updateWebsite,
} from '../contracts/deweb-index';
import {
_addressToOwnerBaseKey,
_indexByOwnerBaseKey,
} from '../contracts/utils';
import { scOwner, version, websiteAddress, websiteOwner } from './const';

describe('updateWebsite tests', () => {
beforeEach(() => {
resetStorage();
setDeployContext(scOwner.toString());
setOf(websiteAddress, OWNER_KEY, websiteOwner.toString());
setOf(websiteAddress, DEWEB_VERSION_TAG, stringToBytes(version));
constructor([]);
});

test('add website', () => {
const args = new Args().add(websiteAddress).serialize();
updateWebsite(args);

const ownerPrefixKey = _indexByOwnerBaseKey(websiteOwner.toString());

const ownerKeys = Storage.getKeys(ownerPrefixKey);
expect(ownerKeys).toHaveLength(1, 'Expected one key for owner');
expect(ownerKeys[0]).toStrictEqual(
ownerPrefixKey.concat(stringToBytes(websiteAddress.toString())),
'Owner keys',
);

const websitePrefixKey = _addressToOwnerBaseKey(websiteAddress.toString());

const websiteKeys = Storage.getKeys(websitePrefixKey);

expect(websiteKeys).toHaveLength(1, 'Expected one key for website');
expect(websiteKeys[0]).toStrictEqual(
websitePrefixKey.concat(stringToBytes(websiteOwner.toString())),
'Website keys',
);
});

test('add website without owner', () => {
deleteOf(websiteAddress, OWNER_KEY);

const args = new Args().add(websiteAddress).serialize();
updateWebsite(args);

const websitePrefixKey = _addressToOwnerBaseKey(websiteAddress.toString());

const websiteKeys = Storage.getKeys(websitePrefixKey);
expect(websiteKeys).toHaveLength(
1,
`Expected one key for website ${websiteAddress.toString()}`,
);
expect(websiteKeys[0]).toStrictEqual(websitePrefixKey, 'Website keys');
});

test('should update website owner', () => {
setOf(websiteAddress, OWNER_KEY, scOwner.toString());
const args = new Args().add(websiteAddress).serialize();
updateWebsite(args);

const oldOwnerPrefixKey = _indexByOwnerBaseKey(websiteOwner.toString());
const oldOwnerKeys = Storage.getKeys(
stringToBytes(oldOwnerPrefixKey.toString()),
);
expect(oldOwnerKeys).toHaveLength(0, 'Old owner keys should be empty');

const newOwnerPrefixKey = _indexByOwnerBaseKey(scOwner.toString());

const newOwnerKeys = Storage.getKeys(newOwnerPrefixKey);
expect(newOwnerKeys).toHaveLength(1, 'New owner keys should have one key');

const websitePrefixKey = _addressToOwnerBaseKey(websiteAddress.toString());

const websiteKeys = Storage.getKeys(websitePrefixKey);
expect(websiteKeys).toHaveLength(1, 'Website keys should have one key');
});

test('should do nothing if the address is not a website', () => {
const args = new Args().add(scOwner).serialize();
updateWebsite(args);

const prefix = _addressToOwnerBaseKey(scOwner.toString());

const websiteKeys = Storage.getKeys(prefix);
expect(websiteKeys).toHaveLength(0);
});

test('should remove website if not a website anymore', () => {
const args = new Args().add(websiteAddress).serialize();
updateWebsite(args);

const websitePrefixKey = _addressToOwnerBaseKey(websiteAddress.toString());

const websiteKeys = Storage.getKeys(websitePrefixKey);
expect(websiteKeys).toHaveLength(1, 'Website keys should have one key');

deleteOf(websiteAddress, DEWEB_VERSION_TAG);
updateWebsite(args);

const updatedWebsiteKeys = Storage.getKeys(websitePrefixKey);
expect(updatedWebsiteKeys).toHaveLength(0, 'Website keys should be empty');

const ownerPrefixKey = _indexByOwnerBaseKey(websiteOwner.toString());
const ownerKeys = Storage.getKeys(ownerPrefixKey);
expect(ownerKeys).toHaveLength(0, 'Owner keys should be empty');
});
});
Empty file.
Loading

0 comments on commit 77056fb

Please sign in to comment.