├── airdrop └── smart-contract │ ├── .env.example │ ├── .gitignore │ ├── assembly │ ├── __tests__ │ │ └── as-pect.d.ts │ ├── const │ │ ├── mrc20-address.ts │ │ └── addressList.ts │ ├── tsconfig.json │ └── contracts │ │ └── airdrop.ts │ ├── .eslintrc.cjs │ ├── asconfig.json │ ├── workflows │ └── ci-tests.yml │ ├── tsconfig.json │ ├── as-pect.asconfig.json │ ├── src │ ├── utils.ts │ └── airdrop.ts │ ├── as-pect.config.js │ ├── package.json │ └── README.md ├── async-call ├── .gitignore ├── .eslintrc.cjs ├── .env.example ├── asconfig.json ├── assembly │ ├── tsconfig.json │ └── contracts │ │ └── main.ts ├── src │ ├── listen.ts │ ├── deploy.ts │ ├── utils.ts │ └── call.ts ├── README.md └── package.json ├── fungible-token ├── smart-contract │ ├── .env.example │ ├── .gitignore │ ├── .eslintrc.cjs │ ├── assembly │ │ ├── __tests__ │ │ │ └── as-pect.d.ts │ │ ├── tsconfig.json │ │ └── contracts │ │ │ └── token.ts │ ├── asconfig.json │ ├── .github │ │ └── workflows │ │ │ └── ci-tests.yml │ ├── src │ │ ├── utils.ts │ │ └── deploy.ts │ ├── tsconfig.json │ ├── as-pect.asconfig.json │ ├── as-pect.config.js │ ├── package.json │ └── README.md └── front │ └── react │ ├── src │ ├── vite-env.d.ts │ ├── main.tsx │ ├── App.css │ ├── index.css │ ├── assets │ │ └── react.svg │ └── App.tsx │ ├── tsconfig.json │ ├── .gitignore │ ├── index.html │ ├── vite.config.ts │ ├── tsconfig.node.json │ ├── tsconfig.app.json │ ├── eslint.config.js │ ├── package.json │ ├── public │ └── vite.svg │ └── README.md ├── deferred-call-manager ├── .gitignore ├── assembly │ ├── __tests__ │ │ ├── massa-example.spec.ts │ │ └── as-pect.d.ts │ ├── tsconfig.json │ ├── serializable │ │ └── history.ts │ ├── contracts │ │ └── main.ts │ └── internals.ts ├── .eslintrc.cjs ├── .env.example ├── asconfig.json ├── .github │ └── workflows │ │ └── ci-tests.yml ├── src │ ├── stop.ts │ ├── history.ts │ ├── serializable │ │ └── history.ts │ ├── listen.ts │ ├── deploy.ts │ └── utils.ts ├── tsconfig.json ├── as-pect.asconfig.json ├── as-pect.config.js ├── README.md └── package.json ├── hello-world ├── smart-contract │ ├── .gitignore │ ├── .eslintrc.cjs │ ├── assembly │ │ ├── __tests__ │ │ │ ├── as-pect.d.ts │ │ │ └── massa-example.spec.ts │ │ ├── tsconfig.json │ │ └── contracts │ │ │ └── main.ts │ ├── .env.example │ ├── asconfig.json │ ├── .github │ │ └── workflows │ │ │ └── ci-tests.yml │ ├── tsconfig.json │ ├── as-pect.asconfig.json │ ├── as-pect.config.js │ ├── src │ │ ├── deploy.ts │ │ ├── utils.ts │ │ └── call.ts │ ├── package.json │ └── README.md └── front │ ├── react │ ├── src │ │ ├── vite-env.d.ts │ │ ├── main.tsx │ │ ├── App.css │ │ ├── index.css │ │ ├── App.tsx │ │ └── assets │ │ │ └── react.svg │ ├── tsconfig.json │ ├── .gitignore │ ├── index.html │ ├── vite.config.ts │ ├── tsconfig.node.json │ ├── tsconfig.app.json │ ├── eslint.config.js │ ├── package.json │ ├── public │ │ └── vite.svg │ └── README.md │ └── vanilla-js │ ├── .gitignore │ ├── vite.config.ts │ ├── package.json │ ├── javascript.svg │ ├── index.html │ ├── public │ └── vite.svg │ ├── style.css │ └── app.js ├── .gitignore ├── .github ├── workflows │ ├── helloworld-ci.yml │ └── helloworld-daily-deploy.yml └── ISSUE_TEMPLATE │ ├── task.md │ └── bug.md ├── LICENSE ├── CONTRIBUTING.md └── README.md /airdrop/smart-contract/.env.example: -------------------------------------------------------------------------------- 1 | PRIVATE_KEY= 2 | -------------------------------------------------------------------------------- /async-call/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | .env 4 | -------------------------------------------------------------------------------- /fungible-token/smart-contract/.env.example: -------------------------------------------------------------------------------- 1 | PRIVATE_KEY= 2 | -------------------------------------------------------------------------------- /deferred-call-manager/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | .env 4 | -------------------------------------------------------------------------------- /airdrop/smart-contract/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | .env 4 | -------------------------------------------------------------------------------- /hello-world/smart-contract/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | .env 4 | -------------------------------------------------------------------------------- /fungible-token/smart-contract/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | build 3 | .env 4 | -------------------------------------------------------------------------------- /hello-world/front/react/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /async-call/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@massalabs'], 3 | }; 4 | -------------------------------------------------------------------------------- /fungible-token/front/react/src/vite-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /deferred-call-manager/assembly/__tests__/massa-example.spec.ts: -------------------------------------------------------------------------------- 1 | describe('TODO', () => {}); 2 | -------------------------------------------------------------------------------- /hello-world/smart-contract/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@massalabs'], 3 | }; 4 | -------------------------------------------------------------------------------- /fungible-token/smart-contract/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@massalabs'], 3 | }; 4 | -------------------------------------------------------------------------------- /airdrop/smart-contract/assembly/__tests__/as-pect.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /deferred-call-manager/assembly/__tests__/as-pect.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /fungible-token/smart-contract/assembly/__tests__/as-pect.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /hello-world/smart-contract/assembly/__tests__/as-pect.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | node_modules 3 | .DS_Store 4 | ledger.json 5 | yarn.lock 6 | .vscode 7 | screenshots/ 8 | .env 9 | 10 | -------------------------------------------------------------------------------- /airdrop/smart-contract/assembly/const/mrc20-address.ts: -------------------------------------------------------------------------------- 1 | export const mrc20Address = 2 | 'AS1adMwkCyNFf1XDYCkFGjP4CAGTeSRvUmnjN3Chw6mpmSsLuRnJ'; 3 | -------------------------------------------------------------------------------- /airdrop/smart-contract/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@massalabs'], 3 | rules: { 4 | 'no-console': 'off', 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /deferred-call-manager/.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@massalabs'], 3 | rules: { 4 | 'no-console': 'off', 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /fungible-token/front/react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.app.json" }, 5 | { "path": "./tsconfig.node.json" } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /hello-world/front/react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "files": [], 3 | "references": [ 4 | { "path": "./tsconfig.app.json" }, 5 | { "path": "./tsconfig.node.json" } 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /async-call/.env.example: -------------------------------------------------------------------------------- 1 | PRIVATE_KEY= 2 | #default value 3 | #JSON_RPC_URL_PUBLIC="https://buildnet.massa.net/api/v2:33035" 4 | #for local node 5 | #JSON_RPC_URL_PUBLIC="http://localhost:33035/api/v2" -------------------------------------------------------------------------------- /deferred-call-manager/.env.example: -------------------------------------------------------------------------------- 1 | PRIVATE_KEY= 2 | #default value 3 | #JSON_RPC_URL_PUBLIC="https://buildnet.massa.net/api/v2:33035" 4 | #for local node 5 | #JSON_RPC_URL_PUBLIC="http://localhost:33035/api/v2" -------------------------------------------------------------------------------- /hello-world/smart-contract/.env.example: -------------------------------------------------------------------------------- 1 | PRIVATE_KEY= 2 | #default value 3 | #JSON_RPC_URL_PUBLIC="https://buildnet.massa.net/api/v2:33035" 4 | #for local node 5 | #JSON_RPC_URL_PUBLIC="http://localhost:33035/api/v2" -------------------------------------------------------------------------------- /hello-world/front/react/src/main.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App.tsx' 4 | import './index.css' 5 | 6 | createRoot(document.getElementById('root')!).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /fungible-token/front/react/src/main.tsx: -------------------------------------------------------------------------------- 1 | import { StrictMode } from 'react' 2 | import { createRoot } from 'react-dom/client' 3 | import App from './App.tsx' 4 | import './index.css' 5 | 6 | createRoot(document.getElementById('root')!).render( 7 | 8 | 9 | , 10 | ) 11 | -------------------------------------------------------------------------------- /async-call/asconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "targets": { 3 | "release": { 4 | "sourceMap": true, 5 | "optimizeLevel": 3, 6 | "shrinkLevel": 3, 7 | "converge": true, 8 | "noAssert": false, 9 | "exportRuntime": true, 10 | "bindings": false 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /deferred-call-manager/asconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "targets": { 3 | "release": { 4 | "sourceMap": true, 5 | "optimizeLevel": 3, 6 | "shrinkLevel": 3, 7 | "converge": true, 8 | "noAssert": false, 9 | "exportRuntime": true, 10 | "bindings": false 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /airdrop/smart-contract/asconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "targets": { 3 | "release": { 4 | "sourceMap": true, 5 | "optimizeLevel": 3, 6 | "shrinkLevel": 3, 7 | "converge": true, 8 | "noAssert": false, 9 | "exportRuntime": true, 10 | "bindings": false 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /hello-world/smart-contract/asconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "targets": { 3 | "release": { 4 | "sourceMap": true, 5 | "optimizeLevel": 3, 6 | "shrinkLevel": 3, 7 | "converge": true, 8 | "noAssert": false, 9 | "exportRuntime": true, 10 | "bindings": false 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /fungible-token/smart-contract/asconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "targets": { 3 | "release": { 4 | "sourceMap": true, 5 | "optimizeLevel": 3, 6 | "shrinkLevel": 3, 7 | "converge": true, 8 | "noAssert": false, 9 | "exportRuntime": true, 10 | "bindings": false 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /async-call/assembly/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "assemblyscript/std/assembly.json", 3 | "include": [ 4 | "**/*.ts" 5 | ], 6 | "typedocOptions": { 7 | "exclude": "assembly/**/__tests__", 8 | "excludePrivate": true, 9 | "excludeProtected": true, 10 | "excludeExternals": true, 11 | "includeVersion": true, 12 | "skipErrorChecking": true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /hello-world/front/react/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /fungible-token/front/react/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /hello-world/front/vanilla-js/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | dist 12 | dist-ssr 13 | *.local 14 | 15 | # Editor directories and files 16 | .vscode/* 17 | !.vscode/extensions.json 18 | .idea 19 | .DS_Store 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | -------------------------------------------------------------------------------- /airdrop/smart-contract/assembly/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "assemblyscript/std/assembly.json", 3 | "include": [ 4 | "**/*.ts" 5 | ], 6 | "typedocOptions": { 7 | "exclude": "assembly/**/__tests__", 8 | "excludePrivate": true, 9 | "excludeProtected": true, 10 | "excludeExternals": true, 11 | "includeVersion": true, 12 | "skipErrorChecking": true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /deferred-call-manager/assembly/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "assemblyscript/std/assembly.json", 3 | "include": [ 4 | "**/*.ts" 5 | ], 6 | "typedocOptions": { 7 | "exclude": "assembly/**/__tests__", 8 | "excludePrivate": true, 9 | "excludeProtected": true, 10 | "excludeExternals": true, 11 | "includeVersion": true, 12 | "skipErrorChecking": true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /fungible-token/smart-contract/assembly/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "assemblyscript/std/assembly.json", 3 | "include": [ 4 | "**/*.ts" 5 | ], 6 | "typedocOptions": { 7 | "exclude": "assembly/**/__tests__", 8 | "excludePrivate": true, 9 | "excludeProtected": true, 10 | "excludeExternals": true, 11 | "includeVersion": true, 12 | "skipErrorChecking": true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /hello-world/smart-contract/assembly/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "assemblyscript/std/assembly.json", 3 | "include": [ 4 | "**/*.ts" 5 | ], 6 | "typedocOptions": { 7 | "exclude": "assembly/**/__tests__", 8 | "excludePrivate": true, 9 | "excludeProtected": true, 10 | "excludeExternals": true, 11 | "includeVersion": true, 12 | "skipErrorChecking": true 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /hello-world/front/vanilla-js/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import { nodePolyfills } from "vite-plugin-node-polyfills"; 3 | 4 | // https://vitejs.dev/config/ 5 | export default defineConfig({ 6 | plugins: [nodePolyfills()], 7 | resolve: { 8 | alias: { 9 | lodash: "lodash-es", 10 | }, 11 | }, 12 | build: { 13 | rollupOptions: { 14 | external: ["lodash"], 15 | }, 16 | }, 17 | }); 18 | -------------------------------------------------------------------------------- /airdrop/smart-contract/workflows/ci-tests.yml: -------------------------------------------------------------------------------- 1 | name: massa sc ci tests 2 | on: [push] 3 | jobs: 4 | unit-tests: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v3 8 | 9 | - uses: actions/setup-node@v3 10 | with: 11 | node-version: '18' 12 | cache: 'npm' 13 | 14 | - name: Install 15 | run: npm ci 16 | 17 | -name : Run build 18 | run: npm run build 19 | -------------------------------------------------------------------------------- /deferred-call-manager/.github/workflows/ci-tests.yml: -------------------------------------------------------------------------------- 1 | name: massa sc ci tests 2 | on: [push] 3 | jobs: 4 | unit-tests: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v3 8 | 9 | - uses: actions/setup-node@v3 10 | with: 11 | node-version: '18' 12 | cache: 'npm' 13 | 14 | - name: Install 15 | run: npm ci 16 | 17 | - name: Test 18 | run: npm run test 19 | -------------------------------------------------------------------------------- /hello-world/front/react/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /hello-world/smart-contract/.github/workflows/ci-tests.yml: -------------------------------------------------------------------------------- 1 | name: massa sc ci tests 2 | on: [push] 3 | jobs: 4 | unit-tests: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v3 8 | 9 | - uses: actions/setup-node@v3 10 | with: 11 | node-version: '18' 12 | cache: 'npm' 13 | 14 | - name: Install 15 | run: npm ci 16 | 17 | - name: Test 18 | run: npm run test 19 | -------------------------------------------------------------------------------- /fungible-token/front/react/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vite + React + TS 8 | 9 | 10 |
11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /fungible-token/smart-contract/.github/workflows/ci-tests.yml: -------------------------------------------------------------------------------- 1 | name: massa sc ci tests 2 | on: [push] 3 | jobs: 4 | unit-tests: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v3 8 | 9 | - uses: actions/setup-node@v3 10 | with: 11 | node-version: '18' 12 | cache: 'npm' 13 | 14 | - name: Install 15 | run: npm ci 16 | 17 | - name: Test 18 | run: npm run test 19 | -------------------------------------------------------------------------------- /fungible-token/front/react/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | import { nodePolyfills } from "vite-plugin-node-polyfills"; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [react(), nodePolyfills()], 8 | resolve: { 9 | alias: { 10 | lodash: "lodash-es", 11 | }, 12 | }, 13 | build: { 14 | rollupOptions: { 15 | external: ["lodash"], 16 | }, 17 | }, 18 | }); 19 | -------------------------------------------------------------------------------- /hello-world/front/react/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vite"; 2 | import react from "@vitejs/plugin-react"; 3 | import { nodePolyfills } from "vite-plugin-node-polyfills"; 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | plugins: [react(), nodePolyfills()], 8 | resolve: { 9 | alias: { 10 | lodash: "lodash-es", 11 | }, 12 | }, 13 | build: { 14 | rollupOptions: { 15 | external: ["lodash"], 16 | }, 17 | }, 18 | }); 19 | -------------------------------------------------------------------------------- /deferred-call-manager/src/stop.ts: -------------------------------------------------------------------------------- 1 | import { SmartContract } from '@massalabs/massa-web3'; 2 | import { getAccountProvider, getContractAddress } from './utils'; 3 | 4 | const provider = await getAccountProvider(); 5 | const contractAddress = await getContractAddress(); 6 | 7 | const contract = new SmartContract(provider, contractAddress); 8 | const operation = await contract.call('stop'); 9 | 10 | await operation.waitSpeculativeExecution(); 11 | console.log( 12 | `Recursive deferred call successfully stopped. OperationId: ${operation.id}`, 13 | ); 14 | -------------------------------------------------------------------------------- /fungible-token/smart-contract/src/utils.ts: -------------------------------------------------------------------------------- 1 | import * as dotenv from 'dotenv'; 2 | import { readFileSync } from 'fs'; 3 | import { fileURLToPath } from 'url'; 4 | import path from 'path'; 5 | 6 | dotenv.config(); 7 | 8 | export function getScByteCode(folderName: string, fileName: string): Buffer { 9 | // Obtain the current file name and directory paths 10 | const __filename = fileURLToPath(import.meta.url); 11 | const __dirname = path.dirname(path.dirname(__filename)); 12 | return readFileSync(path.join(__dirname, folderName, fileName)); 13 | } 14 | -------------------------------------------------------------------------------- /hello-world/front/react/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "lib": ["ES2023"], 5 | "module": "ESNext", 6 | "skipLibCheck": true, 7 | 8 | /* Bundler mode */ 9 | "moduleResolution": "bundler", 10 | "allowImportingTsExtensions": true, 11 | "isolatedModules": true, 12 | "moduleDetection": "force", 13 | "noEmit": true, 14 | 15 | /* Linting */ 16 | "strict": true, 17 | "noUnusedLocals": true, 18 | "noUnusedParameters": true, 19 | "noFallthroughCasesInSwitch": true 20 | }, 21 | "include": ["vite.config.ts"] 22 | } 23 | -------------------------------------------------------------------------------- /.github/workflows/helloworld-ci.yml: -------------------------------------------------------------------------------- 1 | name: Helloworld CI 2 | 3 | on: 4 | push: 5 | paths: 6 | - hello-world/** 7 | 8 | defaults: 9 | run: 10 | working-directory: ./hello-world/smart-contract 11 | 12 | jobs: 13 | unit-tests: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v3 17 | 18 | - uses: actions/setup-node@v3 19 | with: 20 | node-version: 18 21 | 22 | - name: Install 23 | run: npm ci 24 | 25 | - name: Code quality 26 | run: npm run fmt:check 27 | 28 | - name: Test 29 | run: npm run test 30 | -------------------------------------------------------------------------------- /fungible-token/front/react/tsconfig.node.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2022", 4 | "lib": ["ES2023"], 5 | "module": "ESNext", 6 | "skipLibCheck": true, 7 | 8 | /* Bundler mode */ 9 | "moduleResolution": "bundler", 10 | "allowImportingTsExtensions": true, 11 | "isolatedModules": true, 12 | "moduleDetection": "force", 13 | "noEmit": true, 14 | 15 | /* Linting */ 16 | "strict": true, 17 | "noUnusedLocals": true, 18 | "noUnusedParameters": true, 19 | "noFallthroughCasesInSwitch": true 20 | }, 21 | "include": ["vite.config.ts"] 22 | } 23 | -------------------------------------------------------------------------------- /hello-world/front/vanilla-js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vanilla-js", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "vite build", 9 | "preview": "vite preview" 10 | }, 11 | "devDependencies": { 12 | "@types/events": "^3.0.3", 13 | "@types/node": "^22.2.0", 14 | "vite": "^5.4.0", 15 | "vite-plugin-node-polyfills": "^0.22.0" 16 | }, 17 | "dependencies": { 18 | "@massalabs/massa-web3": "^5.1.2-dev", 19 | "@massalabs/wallet-provider": "^3.1.2-dev", 20 | "events": "^3.3.0", 21 | "lodash-es": "^4.17.21" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /deferred-call-manager/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true, 4 | "module": "es2022", 5 | "preserveConstEnums": true, 6 | "moduleResolution": "Node", 7 | "strict": true, 8 | "sourceMap": true, 9 | "target": "es2022", 10 | "types": ["node"] 11 | }, 12 | "include": ["./src/**/*.ts"], // Update the include path to match the actual location of your TypeScript files 13 | "exclude": ["node_modules"], 14 | "experimentalDecorators": true, 15 | "ts-node": { 16 | "esm": true, 17 | "experimentalSpecifierResolution": "node" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /hello-world/smart-contract/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true, 4 | "module": "es2022", 5 | "preserveConstEnums": true, 6 | "moduleResolution": "Node", 7 | "strict": true, 8 | "sourceMap": true, 9 | "target": "es2022", 10 | "types": ["node"] 11 | }, 12 | "include": ["./src/**/*.ts"], // Update the include path to match the actual location of your TypeScript files 13 | "exclude": ["node_modules"], 14 | "experimentalDecorators": true, 15 | "ts-node": { 16 | "esm": true, 17 | "experimentalSpecifierResolution": "node" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /fungible-token/smart-contract/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true, 4 | "module": "es2022", 5 | "preserveConstEnums": true, 6 | "moduleResolution": "Node", 7 | "strict": true, 8 | "sourceMap": true, 9 | "target": "es2022", 10 | "types": ["node"] 11 | }, 12 | "include": ["./src/**/*.ts"], // Update the include path to match the actual location of your TypeScript files 13 | "exclude": ["node_modules"], 14 | "experimentalDecorators": true, 15 | "ts-node": { 16 | "esm": true, 17 | "experimentalSpecifierResolution": "node" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /deferred-call-manager/src/history.ts: -------------------------------------------------------------------------------- 1 | import { deserializeObj } from '@massalabs/massa-web3'; 2 | import { History } from './serializable/history'; 3 | import { getAccountProvider, getContractAddress } from './utils'; 4 | 5 | const provider = await getAccountProvider(); 6 | const contractAddress = await getContractAddress(); 7 | 8 | const keyFilter = 'hist'; 9 | const historyKeys = await provider.getStorageKeys(contractAddress, keyFilter); 10 | 11 | const history = await provider.readStorage(contractAddress, historyKeys); 12 | 13 | history.map((data) => { 14 | const execution = deserializeObj(data, 0, History).instance; 15 | console.log('execution', execution); 16 | }); 17 | -------------------------------------------------------------------------------- /fungible-token/front/react/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "isolatedModules": true, 13 | "moduleDetection": "force", 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true 22 | }, 23 | "include": ["src"] 24 | } 25 | -------------------------------------------------------------------------------- /hello-world/front/react/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "useDefineForClassFields": true, 5 | "lib": ["ES2020", "DOM", "DOM.Iterable"], 6 | "module": "ESNext", 7 | "skipLibCheck": true, 8 | 9 | /* Bundler mode */ 10 | "moduleResolution": "bundler", 11 | "allowImportingTsExtensions": true, 12 | "isolatedModules": true, 13 | "moduleDetection": "force", 14 | "noEmit": true, 15 | "jsx": "react-jsx", 16 | 17 | /* Linting */ 18 | "strict": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": true, 21 | "noFallthroughCasesInSwitch": true 22 | }, 23 | "include": ["src"] 24 | } 25 | -------------------------------------------------------------------------------- /airdrop/smart-contract/assembly/const/addressList.ts: -------------------------------------------------------------------------------- 1 | export const addressList = [ 2 | 'AU1jCffxJFjMQRg1WkoT1gDiFvZGg1WuogiwBWQFZ2LJwEyHPRPZ', 3 | 'AU1rFqhTWvRyuJT3UH5ZZSBjALcAsjXCPPcgUkWaBghYsYicTrB5', 4 | 'AU1x44P7LWJfy3w6bL7fKmH8CxXzZq8a1odg3WKUoq6iqvs5Kcwv', 5 | 'AU1c3YbxDL5vyaJQ8mGQFBEABmmopMWCdhHQpUxcDkVAU4ya666S', 6 | 'AU1SjbSd8u4sutG7fSuxnPgTbiifrHJGN1paopKwDgDkDDTG8iJo', 7 | 'AU1HG96jNJXKVyqeEuwiTFMwfZvX2WVTjTTq8yzxcdYbSmW7n2Hx', 8 | 'AU1i4ey48VhVbG7YyRJHTZ6mkQTj8NESNCbyf8xDgJWbcEmbX8sk', 9 | 'AU12hrZyu1wCYAx8k76J8gu9gNksFzmpCA9ke21bsjV4wG5rpNN1j', 10 | 'AU1U41TqgyhTsWcXntev86FGm3gUD4vM7cKALJGCfyE2UJKZvYC9', 11 | 'AU1vjHCLS3AVApxm4kUCecuTQJuuZRoUbvsszZabLKZi8WUzAzrX', 12 | ]; 13 | -------------------------------------------------------------------------------- /airdrop/smart-contract/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true, 4 | "module": "es2022", 5 | "preserveConstEnums": true, 6 | "moduleResolution": "Node", 7 | "strict": true, 8 | "sourceMap": true, 9 | "target": "es2022", 10 | "types": ["node"] 11 | }, 12 | "include": ["./src/**/*.ts", "assembly/contracts/test-datastore.ts"], // Update the include path to match the actual location of your TypeScript files 13 | "exclude": ["node_modules"], 14 | "experimentalDecorators": true, 15 | "ts-node": { 16 | "esm": true, 17 | "experimentalSpecifierResolution": "node" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/task.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Task 3 | about: Create a new task for the Innovation team to work on 4 | title: '' 5 | assignees: '' 6 | 7 | --- 8 | **Context** 9 | *Describe / explain why we should do this: motivations, context or other info. Keep it brief and simple - PM* 10 | 11 | 12 | **User flow** 13 | *Describe the user flow using user stories so the end result is super clear - PM* 14 | 15 | 16 | **How to** 17 | *List the step-by-step to get it do if needed - PM* 18 | 19 | 20 | **Technical details** 21 | *Give the technical insights so anyone in the team can tackle the tasks - Dev* 22 | 23 | **QA testing** 24 | *Does this task require some QA tests ?* 25 | *If yes, explain how to validate it* -------------------------------------------------------------------------------- /fungible-token/smart-contract/assembly/contracts/token.ts: -------------------------------------------------------------------------------- 1 | import { u256 } from 'as-bignum/assembly'; 2 | import { mrc20Constructor } from '@massalabs/sc-standards/assembly/contracts/MRC20'; 3 | 4 | export function constructor(): void { 5 | mrc20Constructor('MassaToken', 'MT', 18, u256.fromU64(1010101010)); 6 | } 7 | 8 | export * from '@massalabs/sc-standards/assembly/contracts/MRC20'; 9 | export { mint } from '@massalabs/sc-standards/assembly/contracts/MRC20/mintable'; 10 | export { 11 | burn, 12 | burnFrom, 13 | } from '@massalabs/sc-standards/assembly/contracts/MRC20/burnable'; 14 | export { 15 | setOwner, 16 | onlyOwner, 17 | isOwner, 18 | } from '@massalabs/sc-standards/assembly/contracts/utils/ownership'; 19 | -------------------------------------------------------------------------------- /airdrop/smart-contract/as-pect.asconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "targets": { 3 | "coverage": { 4 | "lib": ["./node_modules/@as-covers/assembly/index.ts"], 5 | "transform": ["@as-covers/transform", "@as-pect/transform"] 6 | }, 7 | "noCoverage": { 8 | "transform": ["@as-pect/transform"] 9 | } 10 | }, 11 | "options": { 12 | "exportMemory": true, 13 | "outFile": "output.wasm", 14 | "textFile": "output.wat", 15 | "bindings": "raw", 16 | "exportStart": "_start", 17 | "exportRuntime": true, 18 | "use": ["RTRACE=1"], 19 | "debug": true, 20 | "exportTable": true 21 | }, 22 | "extends": "./asconfig.json", 23 | "entries": ["./node_modules/@as-pect/assembly/assembly/index.ts"] 24 | } -------------------------------------------------------------------------------- /deferred-call-manager/as-pect.asconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "targets": { 3 | "coverage": { 4 | "lib": ["./node_modules/@as-covers/assembly/index.ts"], 5 | "transform": ["@as-covers/transform", "@as-pect/transform"] 6 | }, 7 | "noCoverage": { 8 | "transform": ["@as-pect/transform"] 9 | } 10 | }, 11 | "options": { 12 | "exportMemory": true, 13 | "outFile": "output.wasm", 14 | "textFile": "output.wat", 15 | "bindings": "raw", 16 | "exportStart": "_start", 17 | "exportRuntime": true, 18 | "use": ["RTRACE=1"], 19 | "debug": true, 20 | "exportTable": true 21 | }, 22 | "extends": "./asconfig.json", 23 | "entries": ["./node_modules/@as-pect/assembly/assembly/index.ts"] 24 | } -------------------------------------------------------------------------------- /hello-world/smart-contract/as-pect.asconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "targets": { 3 | "coverage": { 4 | "lib": ["./node_modules/@as-covers/assembly/index.ts"], 5 | "transform": ["@as-covers/transform", "@as-pect/transform"] 6 | }, 7 | "noCoverage": { 8 | "transform": ["@as-pect/transform"] 9 | } 10 | }, 11 | "options": { 12 | "exportMemory": true, 13 | "outFile": "output.wasm", 14 | "textFile": "output.wat", 15 | "bindings": "raw", 16 | "exportStart": "_start", 17 | "exportRuntime": true, 18 | "use": ["RTRACE=1"], 19 | "debug": true, 20 | "exportTable": true 21 | }, 22 | "extends": "./asconfig.json", 23 | "entries": ["./node_modules/@as-pect/assembly/assembly/index.ts"] 24 | } -------------------------------------------------------------------------------- /airdrop/smart-contract/src/utils.ts: -------------------------------------------------------------------------------- 1 | import * as dotenv from 'dotenv'; 2 | import { readFileSync } from 'fs'; 3 | import { fileURLToPath } from 'url'; 4 | import path from 'path'; 5 | import { SCEvent } from '@massalabs/massa-web3'; 6 | 7 | dotenv.config(); 8 | 9 | export function getScByteCode(folderName: string, fileName: string): Buffer { 10 | // Obtain the current file name and directory paths 11 | const __filename = fileURLToPath(import.meta.url); 12 | const __dirname = path.dirname(path.dirname(__filename)); 13 | return readFileSync(path.join(__dirname, folderName, fileName)); 14 | } 15 | 16 | export function logEvent(event: SCEvent, i: number): void { 17 | console.log(`'Event nº ${i + 1}: '${event.data.toString()}`); 18 | } 19 | -------------------------------------------------------------------------------- /fungible-token/smart-contract/as-pect.asconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "targets": { 3 | "coverage": { 4 | "lib": ["./node_modules/@as-covers/assembly/index.ts"], 5 | "transform": ["@as-covers/transform", "@as-pect/transform"] 6 | }, 7 | "noCoverage": { 8 | "transform": ["@as-pect/transform"] 9 | } 10 | }, 11 | "options": { 12 | "exportMemory": true, 13 | "outFile": "output.wasm", 14 | "textFile": "output.wat", 15 | "bindings": "raw", 16 | "exportStart": "_start", 17 | "exportRuntime": true, 18 | "use": ["RTRACE=1"], 19 | "debug": true, 20 | "exportTable": true 21 | }, 22 | "extends": "./asconfig.json", 23 | "entries": ["./node_modules/@as-pect/assembly/assembly/index.ts"] 24 | } -------------------------------------------------------------------------------- /fungible-token/front/react/eslint.config.js: -------------------------------------------------------------------------------- 1 | import js from '@eslint/js' 2 | import globals from 'globals' 3 | import reactHooks from 'eslint-plugin-react-hooks' 4 | import reactRefresh from 'eslint-plugin-react-refresh' 5 | import tseslint from 'typescript-eslint' 6 | 7 | export default tseslint.config({ 8 | extends: [js.configs.recommended, ...tseslint.configs.recommended], 9 | files: ['**/*.{ts,tsx}'], 10 | ignores: ['dist'], 11 | languageOptions: { 12 | ecmaVersion: 2020, 13 | globals: globals.browser, 14 | }, 15 | plugins: { 16 | 'react-hooks': reactHooks, 17 | 'react-refresh': reactRefresh, 18 | }, 19 | rules: { 20 | ...reactHooks.configs.recommended.rules, 21 | 'react-refresh/only-export-components': [ 22 | 'warn', 23 | { allowConstantExport: true }, 24 | ], 25 | }, 26 | }) 27 | -------------------------------------------------------------------------------- /hello-world/front/react/eslint.config.js: -------------------------------------------------------------------------------- 1 | import js from '@eslint/js' 2 | import globals from 'globals' 3 | import reactHooks from 'eslint-plugin-react-hooks' 4 | import reactRefresh from 'eslint-plugin-react-refresh' 5 | import tseslint from 'typescript-eslint' 6 | 7 | export default tseslint.config({ 8 | extends: [js.configs.recommended, ...tseslint.configs.recommended], 9 | files: ['**/*.{ts,tsx}'], 10 | ignores: ['dist'], 11 | languageOptions: { 12 | ecmaVersion: 2020, 13 | globals: globals.browser, 14 | }, 15 | plugins: { 16 | 'react-hooks': reactHooks, 17 | 'react-refresh': reactRefresh, 18 | }, 19 | rules: { 20 | ...reactHooks.configs.recommended.rules, 21 | 'react-refresh/only-export-components': [ 22 | 'warn', 23 | { allowConstantExport: true }, 24 | ], 25 | }, 26 | }) 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a bug report to report a bug and help us to improve sc-examples 4 | title: '' 5 | labels: 'issue:bug' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | 15 | Steps to reproduce the behavior: 16 | 1. Go to '...' 17 | 2. Click on '....' 18 | 3. Scroll down to '....' 19 | 4. See error 20 | 21 | **Expected behavior** 22 | A clear and concise description of what you expected to happen. 23 | 24 | **Screenshots** 25 | If applicable, add screenshots to help explain your problem. 26 | 27 | **Desktop (please complete the following information):** 28 | - OS: [e.g. MacOS, Windows...] 29 | - Browser [e.g. chrome, safari] 30 | - Version [e.g. 22] 31 | 32 | **Additional context** 33 | Add any other context about the problem here. 34 | -------------------------------------------------------------------------------- /deferred-call-manager/assembly/serializable/history.ts: -------------------------------------------------------------------------------- 1 | import { Args, Result, Serializable } from '@massalabs/as-types'; 2 | 3 | export class History implements Serializable { 4 | constructor( 5 | public period: u64 = 0, 6 | public thread: u8 = 0, 7 | public callId: string = '', 8 | ) {} 9 | 10 | serialize(): StaticArray { 11 | return new Args() 12 | .add(this.period) 13 | .add(this.thread) 14 | .add(this.callId) 15 | .serialize(); 16 | } 17 | 18 | deserialize(data: StaticArray, offset: i32): Result { 19 | const args = new Args(data, offset); 20 | 21 | this.period = args.nextU64().expect("Can't deserialize period."); 22 | this.thread = args.nextU8().expect("Can't deserialize thread."); 23 | this.callId = args.nextString().expect("Can't deserialize callId."); 24 | 25 | return new Result(args.offset); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /deferred-call-manager/src/serializable/history.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Args, 3 | IDeserializedResult, 4 | ISerializable, 5 | } from '@massalabs/massa-web3'; 6 | 7 | export class History implements ISerializable { 8 | constructor( 9 | public period: bigint = 0n, 10 | public thread: number = 0, 11 | public callId: string = '', 12 | ) {} 13 | 14 | serialize(): Uint8Array { 15 | const data = new Args() 16 | .addU64(this.period) 17 | .addU8(BigInt(this.thread)) 18 | .addString(this.callId) 19 | .serialize(); 20 | return new Uint8Array(data); 21 | } 22 | 23 | deserialize(data: Uint8Array, offset: number): IDeserializedResult { 24 | const args = new Args(data, offset); 25 | 26 | this.period = args.nextU64(); 27 | this.thread = Number(args.nextU8()); 28 | this.callId = args.nextString(); 29 | 30 | return { instance: this, offset: args.getOffset() }; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /async-call/src/listen.ts: -------------------------------------------------------------------------------- 1 | import { EventPoller, SCEvent } from '@massalabs/massa-web3'; 2 | import { scheduler } from 'timers/promises'; 3 | import { getAccountProvider, getContractAddress } from './utils'; 4 | 5 | const provider = await getAccountProvider(); 6 | const contractAddress = await getContractAddress(); 7 | 8 | let stop = false; 9 | 10 | const onData = async (events: SCEvent[]) => { 11 | for (const event of events) { 12 | console.log( 13 | `Event period: ${event.context.slot.period} thread: ${event.context.slot.thread} -`, 14 | event.data, 15 | ); 16 | } 17 | }; 18 | 19 | const onError = (error: Error) => { 20 | console.error('Error:', error); 21 | stop = true; 22 | }; 23 | const { stopPolling } = EventPoller.start( 24 | provider, 25 | { 26 | smartContractAddress: contractAddress, 27 | }, 28 | onData, 29 | onError, 30 | 5000, 31 | ); 32 | 33 | while (!stop) { 34 | await scheduler.wait(5000); 35 | } 36 | stopPolling(); 37 | -------------------------------------------------------------------------------- /deferred-call-manager/src/listen.ts: -------------------------------------------------------------------------------- 1 | import { EventPoller, SCEvent } from '@massalabs/massa-web3'; 2 | import { scheduler } from 'timers/promises'; 3 | import { getAccountProvider, getContractAddress } from './utils'; 4 | 5 | const provider = await getAccountProvider(); 6 | const contractAddress = await getContractAddress(); 7 | 8 | let stop = false; 9 | 10 | const onData = async (events: SCEvent[]) => { 11 | for (const event of events) { 12 | console.log( 13 | `Event period: ${event.context.slot.period} thread: ${event.context.slot.thread} -`, 14 | event.data, 15 | ); 16 | } 17 | }; 18 | 19 | const onError = (error: Error) => { 20 | console.error('Error:', error); 21 | stop = true; 22 | }; 23 | const { stopPolling } = EventPoller.start( 24 | provider, 25 | { 26 | smartContractAddress: contractAddress, 27 | }, 28 | onData, 29 | onError, 30 | 5000, 31 | ); 32 | 33 | while (!stop) { 34 | await scheduler.wait(5000); 35 | } 36 | stopPolling(); 37 | -------------------------------------------------------------------------------- /hello-world/front/vanilla-js/javascript.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /deferred-call-manager/as-pect.config.js: -------------------------------------------------------------------------------- 1 | import createMockedABI from '@massalabs/massa-as-sdk/vm-mock'; 2 | 3 | export default { 4 | /** 5 | * A set of globs passed to the glob package that qualify typescript files for testing. 6 | */ 7 | entries: ['assembly/__tests__/**/*.spec.ts'], 8 | /** 9 | * A set of globs passed to the glob package that quality files to be added to each test. 10 | */ 11 | include: ['assembly/__tests__/**/*.include.ts'], 12 | /** 13 | * A set of regexp that will disclude source files from testing. 14 | */ 15 | disclude: [/node_modules/], 16 | /** 17 | * Add your required AssemblyScript imports here. 18 | */ 19 | async instantiate(memory, createImports, instantiate, binary) { 20 | return createMockedABI(memory, createImports, instantiate, binary); 21 | }, 22 | /** Enable code coverage. */ 23 | // coverage: ["assembly/**/*.ts"], 24 | /** 25 | * Specify if the binary wasm file should be written to the file system. 26 | */ 27 | outputBinary: false, 28 | }; 29 | -------------------------------------------------------------------------------- /airdrop/smart-contract/as-pect.config.js: -------------------------------------------------------------------------------- 1 | import createMockedABI from '@massalabs/massa-as-sdk/vm-mock'; 2 | 3 | export default { 4 | /** 5 | * A set of globs passed to the glob package that qualify typescript files for testing. 6 | */ 7 | entries: ['assembly/__tests__/**/*.spec.ts'], 8 | /** 9 | * A set of globs passed to the glob package that quality files to be added to each test. 10 | */ 11 | include: ['assembly/__tests__/**/*.include.ts'], 12 | /** 13 | * A set of regexp that will disclude source files from testing. 14 | */ 15 | disclude: [/node_modules/], 16 | /** 17 | * Add your required AssemblyScript imports here. 18 | */ 19 | async instantiate(memory, createImports, instantiate, binary) { 20 | return createMockedABI(memory, createImports, instantiate, binary); 21 | }, 22 | /** Enable code coverage. */ 23 | // coverage: ["assembly/**/*.ts"], 24 | /** 25 | * Specify if the binary wasm file should be written to the file system. 26 | */ 27 | outputBinary: false, 28 | }; 29 | -------------------------------------------------------------------------------- /hello-world/smart-contract/as-pect.config.js: -------------------------------------------------------------------------------- 1 | import createMockedABI from '@massalabs/massa-as-sdk/vm-mock'; 2 | 3 | export default { 4 | /** 5 | * A set of globs passed to the glob package that qualify typescript files for testing. 6 | */ 7 | entries: ['assembly/__tests__/**/*.spec.ts'], 8 | /** 9 | * A set of globs passed to the glob package that quality files to be added to each test. 10 | */ 11 | include: ['assembly/__tests__/**/*.include.ts'], 12 | /** 13 | * A set of regexp that will disclude source files from testing. 14 | */ 15 | disclude: [/node_modules/], 16 | /** 17 | * Add your required AssemblyScript imports here. 18 | */ 19 | async instantiate(memory, createImports, instantiate, binary) { 20 | return createMockedABI(memory, createImports, instantiate, binary); 21 | }, 22 | /** Enable code coverage. */ 23 | // coverage: ["assembly/**/*.ts"], 24 | /** 25 | * Specify if the binary wasm file should be written to the file system. 26 | */ 27 | outputBinary: false, 28 | }; 29 | -------------------------------------------------------------------------------- /fungible-token/smart-contract/as-pect.config.js: -------------------------------------------------------------------------------- 1 | import createMockedABI from '@massalabs/massa-as-sdk/vm-mock'; 2 | 3 | export default { 4 | /** 5 | * A set of globs passed to the glob package that qualify typescript files for testing. 6 | */ 7 | entries: ['assembly/__tests__/**/*.spec.ts'], 8 | /** 9 | * A set of globs passed to the glob package that quality files to be added to each test. 10 | */ 11 | include: ['assembly/__tests__/**/*.include.ts'], 12 | /** 13 | * A set of regexp that will disclude source files from testing. 14 | */ 15 | disclude: [/node_modules/], 16 | /** 17 | * Add your required AssemblyScript imports here. 18 | */ 19 | async instantiate(memory, createImports, instantiate, binary) { 20 | return createMockedABI(memory, createImports, instantiate, binary); 21 | }, 22 | /** Enable code coverage. */ 23 | // coverage: ["assembly/**/*.ts"], 24 | /** 25 | * Specify if the binary wasm file should be written to the file system. 26 | */ 27 | outputBinary: false, 28 | }; 29 | -------------------------------------------------------------------------------- /fungible-token/smart-contract/src/deploy.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | import { Account, Args, Mas, Web3Provider } from '@massalabs/massa-web3'; 3 | import { getScByteCode } from './utils'; 4 | 5 | async function deploy() { 6 | const account = await Account.fromEnv(); 7 | const provider = Web3Provider.buildnet(account); 8 | 9 | console.log('Deploying contract...'); 10 | 11 | const byteCode = getScByteCode('build', 'token.wasm'); 12 | const tokenArgs = new Args() 13 | .addString('Massa Token') 14 | .addString('MAS') 15 | .addU8(9n) 16 | .addU256(120000000000n * 10n ** 9n); 17 | 18 | const contract = await provider.deploySC({ 19 | coins: Mas.fromString('1'), 20 | byteCode, 21 | parameter: tokenArgs.serialize(), 22 | }); 23 | 24 | console.log('Contract deployed at:', contract.address); 25 | 26 | const events = await provider.getEvents({ 27 | smartContractAddress: contract.address, 28 | }); 29 | 30 | for (const event of events) { 31 | console.log('Event: ', event.data); 32 | } 33 | } 34 | 35 | deploy(); 36 | -------------------------------------------------------------------------------- /hello-world/front/vanilla-js/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Message App 7 | 8 | 9 | 10 |
11 |
12 |

Message App

13 | 14 |
15 | 21 | 22 |
23 | 24 |
25 |

26 |
27 |
28 |
29 |
30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /async-call/src/deploy.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | import { Args, Mas, SmartContract } from '@massalabs/massa-web3'; 3 | import { getAccountProvider, getScByteCode } from './utils'; 4 | 5 | async function deployContract() { 6 | const provider = await getAccountProvider(); 7 | 8 | console.log('Deploying contract...'); 9 | 10 | const byteCode = getScByteCode('build', 'main.wasm'); 11 | 12 | const constructorArgs = new Args().addString('Massa'); 13 | 14 | const contract = await SmartContract.deploy( 15 | provider, 16 | byteCode, 17 | constructorArgs, 18 | { coins: Mas.fromString('1') }, 19 | ); 20 | 21 | console.log('Contract deployed at:', contract.address); 22 | console.log( 23 | `You might want to add the line: \nCONTRACT_ADDRESS="${contract.address}"\n to your .env file`, 24 | ); 25 | 26 | const events = await provider.getEvents({ 27 | smartContractAddress: contract.address, 28 | }); 29 | 30 | for (const event of events) { 31 | console.log('Event message:', event.data); 32 | } 33 | } 34 | 35 | await deployContract(); 36 | -------------------------------------------------------------------------------- /deferred-call-manager/assembly/contracts/main.ts: -------------------------------------------------------------------------------- 1 | import { Context, Storage } from '@massalabs/massa-as-sdk'; 2 | import { Args, stringToBytes, u64ToBytes } from '@massalabs/as-types'; 3 | import { 4 | cancelCall, 5 | NEXT_CALL_ID_KEY, 6 | registerCall, 7 | TASK_COUNT_KEY, 8 | } from '../internals'; 9 | 10 | // Export task function 11 | export { processTask } from '../internals'; 12 | 13 | export function constructor(binArgs: StaticArray): void { 14 | assert(Context.isDeployingContract()); 15 | 16 | const period = new Args(binArgs).nextU64().expect('Unable to decode period'); 17 | 18 | Storage.set(TASK_COUNT_KEY, u64ToBytes(0)); 19 | registerCall(period); 20 | } 21 | 22 | export function getNextCallId(_: StaticArray): StaticArray { 23 | assert(Storage.has(NEXT_CALL_ID_KEY), 'No deferred call planned'); 24 | return stringToBytes(Storage.get(NEXT_CALL_ID_KEY)); 25 | } 26 | 27 | export function stop(_: StaticArray): void { 28 | assert(Storage.has(NEXT_CALL_ID_KEY), 'No deferred call to stop'); 29 | cancelCall(Storage.get(NEXT_CALL_ID_KEY)); 30 | } 31 | -------------------------------------------------------------------------------- /hello-world/smart-contract/src/deploy.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | import { Args, Mas } from '@massalabs/massa-web3'; 3 | import { getScByteCode, getAccountProvider } from './utils'; 4 | 5 | async function deployContract() { 6 | const provider = await getAccountProvider(); 7 | 8 | console.log('Deploying contract...'); 9 | 10 | const byteCode = getScByteCode('build', 'main.wasm'); 11 | 12 | const constructorArgs = new Args().addString('Massa'); 13 | 14 | const contract = await provider.deploySC({ 15 | coins: Mas.fromString('1'), 16 | byteCode, 17 | parameter: constructorArgs.serialize(), 18 | }); 19 | 20 | console.log('Contract deployed at:', contract.address); 21 | console.log( 22 | `You might want to add the line: \nCONTRACT_ADDRESS="${contract.address}"\n to your .env file`, 23 | ); 24 | 25 | const events = await provider.getEvents({ 26 | smartContractAddress: contract.address, 27 | }); 28 | 29 | for (const event of events) { 30 | console.log('Event message:', event.data); 31 | } 32 | } 33 | 34 | await deployContract(); 35 | -------------------------------------------------------------------------------- /hello-world/front/react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc -b && vite build", 9 | "lint": "eslint .", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@massalabs/massa-web3": "^5.1.2-dev", 14 | "@massalabs/wallet-provider": "^3.1.2-dev", 15 | "events": "^3.3.0", 16 | "lodash-es": "^4.17.21", 17 | "react": "^18.3.1", 18 | "react-dom": "^18.3.1" 19 | }, 20 | "devDependencies": { 21 | "@eslint/js": "^9.8.0", 22 | "@types/events": "^3.0.3", 23 | "@types/node": "^22.2.0", 24 | "@types/react": "^18.3.3", 25 | "@types/react-dom": "^18.3.0", 26 | "@vitejs/plugin-react": "^4.3.1", 27 | "eslint": "^9.8.0", 28 | "eslint-plugin-react-hooks": "^5.1.0-rc.0", 29 | "eslint-plugin-react-refresh": "^0.4.9", 30 | "globals": "^15.9.0", 31 | "typescript": "^5.5.3", 32 | "typescript-eslint": "^8.0.0", 33 | "vite": "^5.4.0", 34 | "vite-plugin-node-polyfills": "^0.22.0" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /fungible-token/front/react/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react", 3 | "private": true, 4 | "version": "0.0.0", 5 | "type": "module", 6 | "scripts": { 7 | "dev": "vite", 8 | "build": "tsc -b && vite build", 9 | "lint": "eslint .", 10 | "preview": "vite preview" 11 | }, 12 | "dependencies": { 13 | "@massalabs/massa-web3": "^5.1.2-dev", 14 | "@massalabs/wallet-provider": "^3.1.2-dev", 15 | "events": "^3.3.0", 16 | "lodash-es": "^4.17.21", 17 | "react": "^18.3.1", 18 | "react-dom": "^18.3.1" 19 | }, 20 | "devDependencies": { 21 | "@eslint/js": "^9.8.0", 22 | "@types/events": "^3.0.3", 23 | "@types/node": "^22.2.0", 24 | "@types/react": "^18.3.3", 25 | "@types/react-dom": "^18.3.0", 26 | "@vitejs/plugin-react": "^4.3.1", 27 | "eslint": "^9.8.0", 28 | "eslint-plugin-react-hooks": "^5.1.0-rc.0", 29 | "eslint-plugin-react-refresh": "^0.4.9", 30 | "globals": "^15.9.0", 31 | "typescript": "^5.5.3", 32 | "typescript-eslint": "^8.0.0", 33 | "vite": "^5.4.0", 34 | "vite-plugin-node-polyfills": "^0.22.0" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Massa 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /.github/workflows/helloworld-daily-deploy.yml: -------------------------------------------------------------------------------- 1 | name: Helloworld Daily Deploy 2 | 3 | on: 4 | push: 5 | paths: 6 | - hello-world/** 7 | workflow_dispatch: 8 | schedule: 9 | - cron: "0 7 * * *" 10 | 11 | jobs: 12 | deploy-hello-world: 13 | defaults: 14 | run: 15 | working-directory: ./hello-world/smart-contract/ 16 | 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | - name: Checkout code 21 | uses: actions/checkout@v3 22 | 23 | - name: Install node 24 | uses: actions/setup-node@v3 25 | with: 26 | node-version: "18" 27 | cache: "npm" 28 | cache-dependency-path: ./hello-world/smart-contract/package-lock.json 29 | 30 | - name: Install dependencies 31 | run: npm install 32 | 33 | - name: Deploy 34 | run: | 35 | if npm run deploy | grep -q "Contract deployed"; then 36 | echo "Contract successfully deployed!" 37 | else 38 | echo "Failed to deploy contract ..." 39 | exit 1 40 | fi 41 | env: 42 | JSON_RPC_URL_PUBLIC: ${{ secrets.JSON_RPC_URL_PUBLIC }} 43 | WALLET_PRIVATE_KEY: ${{ secrets.WALLET_PRIVATE_KEY }} 44 | -------------------------------------------------------------------------------- /hello-world/front/react/src/App.css: -------------------------------------------------------------------------------- 1 | .app-container { 2 | display: flex; 3 | justify-content: center; 4 | align-items: center; 5 | min-height: 100vh; 6 | min-width: 100vw; 7 | background-color: #ffffffa9; 8 | font-family: Arial, sans-serif; 9 | } 10 | .card { 11 | background-color: white; 12 | border-radius: 8px; 13 | box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); 14 | padding: 20px; 15 | width: 300px; 16 | box-sizing: border-box; 17 | } 18 | .card-title { 19 | font-size: 24px; 20 | font-weight: bold; 21 | text-align: center; 22 | margin-bottom: 20px; 23 | } 24 | .form { 25 | display: flex; 26 | flex-direction: column; 27 | } 28 | 29 | .input { 30 | width: 100%; 31 | padding: 10px; 32 | 33 | border: 1px solid #ccc; 34 | border-radius: 4px; 35 | box-sizing: border-box; 36 | } 37 | 38 | .button { 39 | width: 100%; 40 | padding: 10px; 41 | background-color: #4b4b4b; 42 | color: white; 43 | border: none; 44 | border-radius: 4px; 45 | cursor: pointer; 46 | font-size: 16px; 47 | margin-top: 10px; 48 | } 49 | .button:hover { 50 | background-color: #7d7d7d; 51 | } 52 | .message { 53 | margin-top: 20px; 54 | font-size: 18px; 55 | font-weight: bold; 56 | text-align: center; 57 | } 58 | -------------------------------------------------------------------------------- /deferred-call-manager/README.md: -------------------------------------------------------------------------------- 1 | # Deferred Call Manager Contract 2 | 3 | This contract manages deferred function calls, allowing functions to be scheduled for execution at a later time. It provides mechanisms to add, execute, and remove recursive task using deferred calls. The contract schedule next task execution and store the execution infos like slot and callId. Every task schedule its next execution. 4 | 5 | ## Key Functionalities 6 | 7 | - Start a recursive task to execute every given periods. 8 | - Executing the next deferred call and schedule the next one. 9 | - Stop the task recursion by canceling the next planned call. 10 | 11 | This contract is useful for scenarios where a smart contract needs to be recursively call at fixed time interval. 12 | The execution will last until stopped or contract coins are insufficient to next execution storage or deferred call slot booking fee. 13 | 14 | ## Setup 15 | 16 | ```shell 17 | npm i 18 | ``` 19 | 20 | Create `.env` and set `PRIVATE_KEY`: 21 | 22 | ```shell 23 | cp .env.example .env 24 | ``` 25 | 26 | ## Deploy 27 | 28 | ```shell 29 | npm run deploy 30 | ``` 31 | 32 | ## Listen to Events 33 | 34 | ```shell 35 | npm run listen 36 | ``` 37 | 38 | ## Get Execution History 39 | 40 | ```shell 41 | npm run history 42 | ``` 43 | -------------------------------------------------------------------------------- /deferred-call-manager/src/deploy.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | import { Args, Mas, SmartContract } from '@massalabs/massa-web3'; 3 | import { getAccountProvider, getScByteCode } from './utils'; 4 | 5 | async function deployContract() { 6 | const provider = await getAccountProvider(); 7 | 8 | console.log('Deploying contract...'); 9 | 10 | const byteCode = getScByteCode('build', 'main.wasm'); 11 | 12 | // 1 minutes in period of 16 seconds 13 | const periodInSeconds = 16; 14 | const minutes = 1; 15 | const periods = Math.round((minutes * 60) / periodInSeconds); 16 | 17 | const constructorArgs = new Args().addU64(BigInt(periods)); 18 | 19 | const contract = await SmartContract.deploy( 20 | provider, 21 | byteCode, 22 | constructorArgs, 23 | { coins: Mas.fromString('1') }, 24 | ); 25 | 26 | console.log('Contract deployed at:', contract.address); 27 | console.log( 28 | `You might want to add the line: \nCONTRACT_ADDRESS="${contract.address}"\n to your .env file`, 29 | ); 30 | 31 | const events = await provider.getEvents({ 32 | smartContractAddress: contract.address, 33 | }); 34 | 35 | for (const event of events) { 36 | console.log('Event message:', event.data); 37 | } 38 | } 39 | 40 | await deployContract(); 41 | -------------------------------------------------------------------------------- /async-call/src/utils.ts: -------------------------------------------------------------------------------- 1 | import * as dotenv from 'dotenv'; 2 | import { readFileSync } from 'fs'; 3 | import { fileURLToPath } from 'url'; 4 | import path from 'path'; 5 | import 'dotenv/config'; 6 | import { Account, Web3Provider } from '@massalabs/massa-web3'; 7 | 8 | dotenv.config(); 9 | 10 | export async function getContractAddress() { 11 | const contractAddress = process.env.CONTRACT_ADDRESS; 12 | if (!contractAddress) { 13 | throw new Error('CONTRACT_ADDRESS is not set in .env file'); 14 | } 15 | return contractAddress; 16 | } 17 | export function getScByteCode(folderName: string, fileName: string): Buffer { 18 | // Obtain the current file name and directory paths 19 | const __filename = fileURLToPath(import.meta.url); 20 | const __dirname = path.dirname(path.dirname(__filename)); 21 | return readFileSync(path.join(__dirname, folderName, fileName)); 22 | } 23 | 24 | export async function getAccountProvider() { 25 | const account = await Account.fromEnv(); 26 | 27 | let provider: Web3Provider; 28 | if (process.env.JSON_RPC_URL_PUBLIC) { 29 | const rpcUrl = process.env.JSON_RPC_URL_PUBLIC; 30 | provider = Web3Provider.fromRPCUrl(rpcUrl, account); 31 | } else { 32 | provider = Web3Provider.buildnet(account); 33 | } 34 | return provider; 35 | } 36 | -------------------------------------------------------------------------------- /deferred-call-manager/src/utils.ts: -------------------------------------------------------------------------------- 1 | import * as dotenv from 'dotenv'; 2 | import { readFileSync } from 'fs'; 3 | import { fileURLToPath } from 'url'; 4 | import path from 'path'; 5 | import 'dotenv/config'; 6 | import { Account, Web3Provider } from '@massalabs/massa-web3'; 7 | 8 | dotenv.config(); 9 | 10 | export async function getContractAddress() { 11 | const contractAddress = process.env.CONTRACT_ADDRESS; 12 | if (!contractAddress) { 13 | throw new Error('CONTRACT_ADDRESS is not set in .env file'); 14 | } 15 | return contractAddress; 16 | } 17 | export function getScByteCode(folderName: string, fileName: string): Buffer { 18 | // Obtain the current file name and directory paths 19 | const __filename = fileURLToPath(import.meta.url); 20 | const __dirname = path.dirname(path.dirname(__filename)); 21 | return readFileSync(path.join(__dirname, folderName, fileName)); 22 | } 23 | 24 | export async function getAccountProvider() { 25 | const account = await Account.fromEnv(); 26 | 27 | let provider: Web3Provider; 28 | if (process.env.JSON_RPC_URL_PUBLIC) { 29 | const rpcUrl = process.env.JSON_RPC_URL_PUBLIC; 30 | provider = Web3Provider.fromRPCUrl(rpcUrl, account); 31 | } else { 32 | provider = Web3Provider.buildnet(account); 33 | } 34 | return provider; 35 | } 36 | -------------------------------------------------------------------------------- /hello-world/smart-contract/assembly/__tests__/massa-example.spec.ts: -------------------------------------------------------------------------------- 1 | import { Args, bytesToString, stringToBytes } from '@massalabs/as-types'; 2 | import { constructor, setMessage, getMessage } from '../contracts/main'; 3 | import { 4 | Address, 5 | resetStorage, 6 | setDeployContext, 7 | } from '@massalabs/massa-as-sdk'; 8 | 9 | const USER1_ADDRESS = new Address( 10 | 'AU12UBnqTHDQALpocVBnkPNy7y5CndUJQTLutaVDDFgMJcq5kQiKq', 11 | ); 12 | 13 | describe('Hello world', () => { 14 | beforeEach(() => { 15 | // Remove all data from the data store 16 | resetStorage(); 17 | // Needed to call the constructor function 18 | setDeployContext(USER1_ADDRESS.toString()); 19 | constructor(new Args().add('Massa test').serialize()); 20 | }); 21 | 22 | test('Update message', () => { 23 | // Here we use Args object to serialize the message 24 | setMessage(new Args().add('Hello, world!').serialize()); 25 | const message = getMessage(); 26 | expect(message).toStrictEqual(stringToBytes('Hello, world!')); 27 | }); 28 | 29 | test('Get message', () => { 30 | const message = getMessage(); 31 | // Because the function returns a StaticArray, we need to convert it to a string 32 | expect(bytesToString(message)).toStrictEqual('Massa test'); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /fungible-token/front/react/src/App.css: -------------------------------------------------------------------------------- 1 | .app-container { 2 | display: flex; 3 | justify-content: center; 4 | align-items: center; 5 | min-height: 100vh; 6 | min-width: 100vw; 7 | background-color: #ffffffa9; 8 | font-family: Arial, sans-serif; 9 | } 10 | .card { 11 | background-color: white; 12 | border-radius: 8px; 13 | box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); 14 | padding: 20px; 15 | box-sizing: border-box; 16 | } 17 | .card-title { 18 | font-size: 24px; 19 | font-weight: bold; 20 | text-align: center; 21 | margin-bottom: 20px; 22 | } 23 | .card-sub-title { 24 | font-size: 16px; 25 | font-weight: bold; 26 | text-align: center; 27 | margin-bottom: 20px; 28 | } 29 | 30 | .form { 31 | display: flex; 32 | flex-direction: column; 33 | } 34 | 35 | .input { 36 | width: 100%; 37 | padding: 10px; 38 | border: 1px solid #ccc; 39 | border-radius: 4px; 40 | box-sizing: border-box; 41 | margin-top: 10px; 42 | } 43 | 44 | .button { 45 | width: 100%; 46 | padding: 10px; 47 | background-color: #4b4b4b; 48 | color: white; 49 | border: none; 50 | border-radius: 4px; 51 | cursor: pointer; 52 | font-size: 16px; 53 | margin-top: 10px; 54 | } 55 | .button:hover { 56 | background-color: #7d7d7d; 57 | } 58 | .message { 59 | margin-top: 20px; 60 | font-size: 18px; 61 | font-weight: bold; 62 | text-align: center; 63 | } 64 | -------------------------------------------------------------------------------- /hello-world/front/react/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /fungible-token/front/react/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /fungible-token/front/react/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | a { 17 | font-weight: 500; 18 | color: #646cff; 19 | text-decoration: inherit; 20 | } 21 | a:hover { 22 | color: #535bf2; 23 | } 24 | 25 | body { 26 | margin: 0; 27 | display: flex; 28 | place-items: center; 29 | min-width: 320px; 30 | min-height: 100vh; 31 | } 32 | 33 | h1 { 34 | font-size: 3.2em; 35 | line-height: 1.1; 36 | } 37 | 38 | button { 39 | border-radius: 8px; 40 | border: 1px solid transparent; 41 | padding: 0.6em 1.2em; 42 | font-size: 1em; 43 | font-weight: 500; 44 | font-family: inherit; 45 | background-color: #1a1a1a; 46 | cursor: pointer; 47 | transition: border-color 0.25s; 48 | } 49 | button:hover { 50 | border-color: #646cff; 51 | } 52 | button:focus, 53 | button:focus-visible { 54 | outline: 4px auto -webkit-focus-ring-color; 55 | } 56 | 57 | @media (prefers-color-scheme: light) { 58 | :root { 59 | color: #213547; 60 | background-color: #ffffff; 61 | } 62 | a:hover { 63 | color: #747bff; 64 | } 65 | button { 66 | background-color: #f9f9f9; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /hello-world/front/react/src/index.css: -------------------------------------------------------------------------------- 1 | :root { 2 | font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif; 3 | line-height: 1.5; 4 | font-weight: 400; 5 | 6 | color-scheme: light dark; 7 | color: rgba(255, 255, 255, 0.87); 8 | background-color: #242424; 9 | 10 | font-synthesis: none; 11 | text-rendering: optimizeLegibility; 12 | -webkit-font-smoothing: antialiased; 13 | -moz-osx-font-smoothing: grayscale; 14 | } 15 | 16 | a { 17 | font-weight: 500; 18 | color: #646cff; 19 | text-decoration: inherit; 20 | } 21 | a:hover { 22 | color: #535bf2; 23 | } 24 | 25 | body { 26 | margin: 0; 27 | display: flex; 28 | place-items: center; 29 | min-width: 320px; 30 | min-height: 100vh; 31 | } 32 | 33 | h1 { 34 | font-size: 3.2em; 35 | line-height: 1.1; 36 | } 37 | 38 | button { 39 | border-radius: 8px; 40 | border: 1px solid transparent; 41 | padding: 0.6em 1.2em; 42 | font-size: 1em; 43 | font-weight: 500; 44 | font-family: inherit; 45 | background-color: #1a1a1a; 46 | cursor: pointer; 47 | transition: border-color 0.25s; 48 | } 49 | button:hover { 50 | border-color: #646cff; 51 | } 52 | button:focus, 53 | button:focus-visible { 54 | outline: 4px auto -webkit-focus-ring-color; 55 | } 56 | 57 | @media (prefers-color-scheme: light) { 58 | :root { 59 | color: #213547; 60 | background-color: #ffffff; 61 | } 62 | a:hover { 63 | color: #747bff; 64 | } 65 | button { 66 | background-color: #f9f9f9; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /hello-world/front/vanilla-js/public/vite.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /hello-world/smart-contract/src/utils.ts: -------------------------------------------------------------------------------- 1 | import * as dotenv from 'dotenv'; 2 | import { readFileSync } from 'fs'; 3 | import { fileURLToPath } from 'url'; 4 | import path from 'path'; 5 | import 'dotenv/config'; 6 | import { Account, Web3Provider } from '@massalabs/massa-web3'; 7 | 8 | dotenv.config(); 9 | 10 | export async function getContractAddress() { 11 | const contractAddress = process.env.CONTRACT_ADDRESS; 12 | if (!contractAddress) { 13 | throw new Error('CONTRACT_ADDRESS is not set in .env file'); 14 | } 15 | return contractAddress; 16 | } 17 | export function getScByteCode(folderName: string, fileName: string): Buffer { 18 | // Obtain the current file name and directory paths 19 | const __filename = fileURLToPath(import.meta.url); 20 | const __dirname = path.dirname(path.dirname(__filename)); 21 | return readFileSync(path.join(__dirname, folderName, fileName)); 22 | } 23 | 24 | export async function getAccountProvider() { 25 | const account = await Account.fromEnv().catch((error) => { 26 | console.log('Error getting account:', error); 27 | console.log('This is expected when deploying from the CI pipeline'); 28 | console.log('Using WALLET_PRIVATE_KEY from environment variables'); 29 | return Account.fromEnv('WALLET_PRIVATE_KEY'); 30 | }); 31 | 32 | let provider: Web3Provider; 33 | if (process.env.JSON_RPC_URL_PUBLIC) { 34 | const rpcUrl = process.env.JSON_RPC_URL_PUBLIC; 35 | provider = Web3Provider.fromRPCUrl(rpcUrl, account); 36 | } else { 37 | provider = Web3Provider.buildnet(account); 38 | } 39 | return provider; 40 | } 41 | -------------------------------------------------------------------------------- /hello-world/front/vanilla-js/style.css: -------------------------------------------------------------------------------- 1 | .app-container { 2 | display: flex; 3 | justify-content: center; 4 | align-items: center; 5 | min-height: 100vh; 6 | min-width: 100vw; 7 | font-family: Arial, sans-serif; 8 | } 9 | 10 | .card { 11 | background-color: white; 12 | border-radius: 8px; 13 | box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); 14 | padding: 20px; 15 | width: 300px; 16 | box-sizing: border-box; 17 | } 18 | 19 | .card-title { 20 | font-size: 24px; 21 | font-weight: bold; 22 | text-align: center; 23 | margin-bottom: 20px; 24 | } 25 | 26 | .input { 27 | width: 100%; 28 | padding: 10px; 29 | border: 1px solid #ccc; 30 | border-radius: 4px; 31 | box-sizing: border-box; 32 | margin-bottom: 10px; 33 | } 34 | 35 | .button { 36 | width: 100%; 37 | padding: 10px; 38 | background-color: #4b4b4b; 39 | color: white; 40 | border: none; 41 | border-radius: 4px; 42 | cursor: pointer; 43 | font-size: 16px; 44 | margin-top: 10px; 45 | } 46 | 47 | .button:hover { 48 | background-color: #7d7d7d; 49 | } 50 | 51 | .message { 52 | margin-top: 20px; 53 | font-size: 18px; 54 | font-weight: bold; 55 | text-align: center; 56 | } 57 | 58 | .error { 59 | color: #ff3333; 60 | font-size: 14px; 61 | position: fixed; 62 | bottom: 20px; 63 | left: 0; 64 | right: 0; 65 | text-align: center; 66 | background-color: rgba(255, 200, 200, 0.9); 67 | padding: 10px; 68 | border-radius: 4px; 69 | box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); 70 | transition: opacity 0.3s ease-in-out; 71 | opacity: 0; 72 | } 73 | 74 | .error.visible { 75 | opacity: 1; 76 | } 77 | -------------------------------------------------------------------------------- /async-call/src/call.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | import { 3 | Args, 4 | Mas, 5 | OperationStatus, 6 | SmartContract, 7 | } from '@massalabs/massa-web3'; 8 | import { getAccountProvider, getContractAddress } from './utils'; 9 | 10 | async function triggerAsyncHello(message: string) { 11 | const contractAddress = await getContractAddress(); 12 | const provider = await getAccountProvider(); 13 | 14 | console.log('Will trigger async hello...'); 15 | 16 | const contract = new SmartContract(provider, contractAddress); 17 | const operation = await contract.call( 18 | 'asyncHello', // function name 19 | new Args().serialize(), // arguments 20 | { 21 | // options 22 | coins: Mas.fromString('0.01'), // coins 23 | maxGas: BigInt(3_100_000), // gas limit 24 | fee: Mas.fromString('0.01'), // fee 25 | }, 26 | ); 27 | 28 | console.log( 29 | 'asyncHello function called successfully, operation id:', 30 | operation.id, 31 | ); 32 | 33 | console.log('Waiting for operation to be finalized...'); 34 | const status = await operation.waitFinalExecution(); 35 | console.log('Operation status:', OperationStatus[status]); 36 | if (status !== OperationStatus.Success) { 37 | throw new Error('Operation failed'); 38 | } 39 | 40 | const events = await provider.getEvents({ 41 | smartContractAddress: contractAddress, 42 | operationId: operation.id, 43 | }); 44 | 45 | for (const event of events) { 46 | console.log( 47 | `Event: "${event.data}" received for operation: ${event.context.origin_operation_id}`, 48 | ); 49 | } 50 | } 51 | 52 | await triggerAsyncHello('Hello, Massa friends!'); 53 | -------------------------------------------------------------------------------- /async-call/README.md: -------------------------------------------------------------------------------- 1 | # Async Call Example 2 | 3 | This repository contains an example of an asynchronous smart contract using the Massa blockchain framework. The contract demonstrates how to deploy a contract and schedule asynchronous calls. This contract is based on the Hello World example. 4 | 5 | ## Overview 6 | 7 | The main functionalities of the contract include: 8 | 9 | - **Constructor**: Initializes the contract and stores a message. 10 | - **AsyncHello**: A function that triggers itself asynchronously every two periods. 11 | - **SetMessage**: Updates the stored message in the contract. 12 | - **GetMessage**: Retrieves the stored message from the contract. 13 | 14 | ## Getting Started 15 | 16 | ### Prerequisites 17 | 18 | - Node.js 19 | - npm 20 | - Massa SDK 21 | 22 | ### Installation 23 | 24 | 1. Clone the repository: 25 | 26 | ```bash 27 | git clone https://github.com/massalabs/massa-sc-examples.git 28 | cd massa-sc-examples/async-call 29 | ``` 30 | 31 | 2. Install the dependencies: 32 | 33 | ```bash 34 | npm install 35 | ``` 36 | 37 | ### Building the Contract 38 | 39 | To compile the smart contract, run: 40 | 41 | ```bash 42 | npm run build 43 | ``` 44 | 45 | ### Deploying the Contract 46 | 47 | To deploy the contract, run: 48 | 49 | ```bash 50 | npm run deploy 51 | ``` 52 | 53 | ### Triggering the Async Call 54 | 55 | The async call is triggered by the `asyncHello` function. The first time it is called, it schedules the next call and so on. 56 | 57 | To trigger the first async call, run: 58 | 59 | ```bash 60 | npm run call 61 | ``` 62 | 63 | ### Watching the Events generated by the Async Call 64 | 65 | To watch the events, run: 66 | 67 | ```bash 68 | npm run listen 69 | ``` 70 | 71 | ## License 72 | 73 | -------------------------------------------------------------------------------- /hello-world/smart-contract/assembly/contracts/main.ts: -------------------------------------------------------------------------------- 1 | import { Context, generateEvent, Storage } from '@massalabs/massa-as-sdk'; 2 | import { Args, stringToBytes } from '@massalabs/as-types'; 3 | 4 | /** 5 | * This function is meant to be called only one time: when the contract is deployed. 6 | * 7 | * @param binaryArgs - Arguments serialized with Args 8 | */ 9 | export function constructor(binaryArgs: StaticArray): void { 10 | // This line is important. It ensures that this function can't be called in the future. 11 | // If you remove this check, someone could call your constructor function and reset your smart contract. 12 | if (!Context.isDeployingContract()) return; 13 | 14 | const args = new Args(binaryArgs); 15 | 16 | const message = args 17 | .nextString() 18 | .expect('Name argument is missing or invalid'); 19 | 20 | Storage.set(stringToBytes('messageKey'), stringToBytes(message)); 21 | generateEvent(`Constructor called with message ${message}`); 22 | } 23 | 24 | /** 25 | * This function updates the message stored in the contract storage. 26 | * 27 | * @param binaryArgs - Arguments serialized with Args 28 | */ 29 | export function setMessage(binaryArgs: StaticArray): void { 30 | const args = new Args(binaryArgs); 31 | 32 | const message = args 33 | .nextString() 34 | .expect('Message argument is missing or invalid'); 35 | 36 | Storage.set('messageKey', message); 37 | generateEvent(`Message updated to ${message}`); 38 | } 39 | 40 | /** 41 | * This function returns the message stored in the contract storage. 42 | */ 43 | export function getMessage(): StaticArray { 44 | const message = Storage.get('messageKey'); 45 | // We could also serialize with Args 46 | return stringToBytes(message); 47 | } 48 | -------------------------------------------------------------------------------- /hello-world/front/react/README.md: -------------------------------------------------------------------------------- 1 | # React + TypeScript + Vite 2 | 3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. 4 | 5 | Currently, two official plugins are available: 6 | 7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh 8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh 9 | 10 | ## Expanding the ESLint configuration 11 | 12 | If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: 13 | 14 | - Configure the top-level `parserOptions` property like this: 15 | 16 | ```js 17 | export default tseslint.config({ 18 | languageOptions: { 19 | // other options... 20 | parserOptions: { 21 | project: ['./tsconfig.node.json', './tsconfig.app.json'], 22 | tsconfigRootDir: import.meta.dirname, 23 | }, 24 | }, 25 | }) 26 | ``` 27 | 28 | - Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked` 29 | - Optionally add `...tseslint.configs.stylisticTypeChecked` 30 | - Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config: 31 | 32 | ```js 33 | // eslint.config.js 34 | import react from 'eslint-plugin-react' 35 | 36 | export default tseslint.config({ 37 | // Set the react version 38 | settings: { react: { version: '18.3' } }, 39 | plugins: { 40 | // Add the react plugin 41 | react, 42 | }, 43 | rules: { 44 | // other rules... 45 | // Enable its recommended rules 46 | ...react.configs.recommended.rules, 47 | ...react.configs['jsx-runtime'].rules, 48 | }, 49 | }) 50 | ``` 51 | -------------------------------------------------------------------------------- /fungible-token/front/react/README.md: -------------------------------------------------------------------------------- 1 | # React + TypeScript + Vite 2 | 3 | This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. 4 | 5 | Currently, two official plugins are available: 6 | 7 | - [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh 8 | - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh 9 | 10 | ## Expanding the ESLint configuration 11 | 12 | If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: 13 | 14 | - Configure the top-level `parserOptions` property like this: 15 | 16 | ```js 17 | export default tseslint.config({ 18 | languageOptions: { 19 | // other options... 20 | parserOptions: { 21 | project: ['./tsconfig.node.json', './tsconfig.app.json'], 22 | tsconfigRootDir: import.meta.dirname, 23 | }, 24 | }, 25 | }) 26 | ``` 27 | 28 | - Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked` 29 | - Optionally add `...tseslint.configs.stylisticTypeChecked` 30 | - Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config: 31 | 32 | ```js 33 | // eslint.config.js 34 | import react from 'eslint-plugin-react' 35 | 36 | export default tseslint.config({ 37 | // Set the react version 38 | settings: { react: { version: '18.3' } }, 39 | plugins: { 40 | // Add the react plugin 41 | react, 42 | }, 43 | rules: { 44 | // other rules... 45 | // Enable its recommended rules 46 | ...react.configs.recommended.rules, 47 | ...react.configs['jsx-runtime'].rules, 48 | }, 49 | }) 50 | ``` 51 | -------------------------------------------------------------------------------- /fungible-token/smart-contract/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-massa-sc", 3 | "version": "0.0.2", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "asp --summary", 8 | "build": "massa-as-compile", 9 | "clean": "rimraf build", 10 | "deploy": "npm run build && tsx src/deploy.ts", 11 | "prettier": "prettier '**/src/**/*.ts' --check && as-prettier --check assembly", 12 | "prettier:fix": "prettier '**/src/**/*.ts' --write && as-prettier --write assembly", 13 | "lint": "eslint .", 14 | "lint:fix": "eslint . --fix", 15 | "fmt:check": "npm run prettier && npm run lint", 16 | "fmt": "npm run prettier:fix && npm run lint:fix" 17 | }, 18 | "keywords": [], 19 | "author": "", 20 | "license": "ISC", 21 | "devDependencies": { 22 | "@as-pect/cli": "^8.1.0", 23 | "@assemblyscript/loader": "^0.27.29", 24 | "@massalabs/as-types": "^2.0.0", 25 | "@massalabs/eslint-config": "^0.0.11", 26 | "@massalabs/massa-as-sdk": "^2.5.4", 27 | "@massalabs/massa-sc-compiler": "^0.2.1-dev", 28 | "@massalabs/massa-sc-deployer": "^1.3.0", 29 | "@massalabs/sc-standards": "^1.3.0", 30 | "@massalabs/massa-web3": "^5.1.2-dev", 31 | "@massalabs/prettier-config-as": "^0.0.2", 32 | "@types/node": "^18.11.10", 33 | "assemblyscript": "^0.27.29", 34 | "assemblyscript-prettier": "^1.0.7", 35 | "dotenv": "^16.0.3", 36 | "prettier": "^2.8.1", 37 | "tslib": "^2.4.0", 38 | "tsx": "^4.7.0", 39 | "typescript": "^4.8.4" 40 | }, 41 | "overrides": { 42 | "visitor-as": { 43 | "assemblyscript": "$assemblyscript" 44 | } 45 | }, 46 | "type": "module", 47 | "prettier": "@massalabs/prettier-config-as", 48 | "engines": { 49 | "node": ">=16" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /async-call/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-massa-sc", 3 | "version": "0.0.2", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "asp --summary", 8 | "build": "massa-as-compile", 9 | "clean": "rimraf build", 10 | "deploy": "npm run build && tsx src/deploy.ts", 11 | "call": "tsx src/call.ts", 12 | "listen": "tsx src/listen.ts", 13 | "prettier": "prettier '**/src/**/*.ts' --check && as-prettier --check assembly", 14 | "prettier:fix": "prettier '**/src/**/*.ts' --write && as-prettier --write assembly", 15 | "lint": "eslint assembly", 16 | "lint:fix": "eslint assembly --fix", 17 | "fmt:check": "npm run prettier && npm run lint", 18 | "fmt": "npm run prettier:fix && npm run lint:fix" 19 | }, 20 | "keywords": [], 21 | "author": "", 22 | "license": "ISC", 23 | "devDependencies": { 24 | "@as-pect/cli": "^8.1.0", 25 | "@assemblyscript/loader": "^0.27.29", 26 | "@massalabs/as-types": "^2.0.0", 27 | "@massalabs/eslint-config": "^0.0.11", 28 | "@massalabs/massa-as-sdk": "^3.0.1-dev", 29 | "@massalabs/massa-sc-compiler": "^0.2.1-dev", 30 | "@massalabs/massa-sc-deployer": "^2.2.0", 31 | "@massalabs/massa-web3": "^5.2.0", 32 | "@massalabs/prettier-config-as": "^0.0.2", 33 | "@types/node": "^18.11.10", 34 | "assemblyscript": "^0.27.29", 35 | "assemblyscript-prettier": "^1.0.7", 36 | "dotenv": "^16.0.3", 37 | "prettier": "^2.8.1", 38 | "tslib": "^2.4.0", 39 | "tsx": "^4.7.0", 40 | "typescript": "^4.8.4" 41 | }, 42 | "overrides": { 43 | "visitor-as": { 44 | "assemblyscript": "$assemblyscript" 45 | } 46 | }, 47 | "type": "module", 48 | "prettier": "@massalabs/prettier-config-as", 49 | "engines": { 50 | "node": ">=16" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /hello-world/smart-contract/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-massa-sc", 3 | "version": "0.0.2", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "asp --summary", 8 | "build": "massa-as-compile", 9 | "clean": "rimraf build", 10 | "deploy": "npm run build && tsx src/deploy.ts", 11 | "call": "tsx src/call.ts", 12 | "prettier": "prettier '**/src/**/*.ts' --check && as-prettier --check assembly", 13 | "prettier:fix": "prettier '**/src/**/*.ts' --write && as-prettier --write assembly", 14 | "lint": "eslint assembly", 15 | "lint:fix": "eslint assembly --fix", 16 | "fmt:check": "npm run prettier && npm run lint", 17 | "fmt": "npm run prettier:fix && npm run lint:fix" 18 | }, 19 | "keywords": [], 20 | "author": "", 21 | "license": "ISC", 22 | "devDependencies": { 23 | "@as-pect/cli": "^8.1.0", 24 | "@assemblyscript/loader": "^0.27.29", 25 | "@massalabs/as-types": "^2.0.0", 26 | "@massalabs/eslint-config": "^0.0.11", 27 | "@massalabs/massa-as-sdk": "^3.0.1-dev", 28 | "@massalabs/massa-sc-compiler": "^0.2.1-dev", 29 | "@massalabs/massa-sc-deployer": "^2.2.0", 30 | "@massalabs/massa-web3": "^5.2.0", 31 | "@massalabs/prettier-config-as": "^0.0.2", 32 | "@types/node": "^18.11.10", 33 | "assemblyscript": "^0.27.29", 34 | "assemblyscript-prettier": "^1.0.7", 35 | "dotenv": "^16.0.3", 36 | "prettier": "^2.8.1", 37 | "tslib": "^2.4.0", 38 | "tsx": "^4.7.0", 39 | "typescript": "^4.8.4" 40 | }, 41 | "overrides": { 42 | "visitor-as": { 43 | "assemblyscript": "$assemblyscript" 44 | }, 45 | "esbuild": "0.19.12" 46 | }, 47 | "type": "module", 48 | "prettier": "@massalabs/prettier-config-as", 49 | "engines": { 50 | "node": ">=16" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /airdrop/smart-contract/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "execute-airdrop", 3 | "version": "0.0.2", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "asp --summary", 8 | "build": "massa-as-compile", 9 | "clean": "rimraf build", 10 | "airdrop": "npm run build && tsx src/airdrop.ts", 11 | "prettier": "prettier '**/src/**/*.ts' --check && as-prettier --check assembly", 12 | "prettier:fix": "prettier '**/src/**/*.ts' --write && as-prettier --write assembly", 13 | "lint": "eslint .", 14 | "lint:fix": "eslint . --fix", 15 | "fmt:check": "npm run prettier && npm run lint", 16 | "fmt": "npm run prettier:fix && npm run lint:fix" 17 | }, 18 | "keywords": [], 19 | "author": "", 20 | "license": "ISC", 21 | "devDependencies": { 22 | "@as-pect/cli": "^8.1.0", 23 | "@assemblyscript/loader": "^0.27.29", 24 | "@massalabs/as-types": "^2.0.0", 25 | "@massalabs/eslint-config": "^0.0.11", 26 | "@massalabs/massa-as-sdk": "^2.5.4-dev", 27 | "@massalabs/massa-sc-compiler": "^0.2.1-dev", 28 | "@massalabs/massa-sc-deployer": "^1.3.0", 29 | "@massalabs/prettier-config-as": "^0.0.2", 30 | "@massalabs/sc-standards": "^1.2.3-dev", 31 | "@types/node": "^18.11.10", 32 | "assemblyscript": "^0.27.29", 33 | "assemblyscript-prettier": "^1.0.7", 34 | "dotenv": "^16.0.3", 35 | "prettier": "^2.8.1", 36 | "tslib": "^2.4.0", 37 | "tsx": "^4.7.0", 38 | "typescript": "^4.8.4" 39 | }, 40 | "overrides": { 41 | "visitor-as": { 42 | "assemblyscript": "$assemblyscript" 43 | } 44 | }, 45 | "type": "module", 46 | "prettier": "@massalabs/prettier-config-as", 47 | "engines": { 48 | "node": ">=16" 49 | }, 50 | "dependencies": { 51 | "@massalabs/massa-web3": "^5.0.1-dev.20241127124628" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /deferred-call-manager/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "my-massa-sc", 3 | "version": "0.0.2", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "asp --summary", 8 | "build": "massa-as-compile", 9 | "clean": "rimraf build", 10 | "deploy": "npm run build && tsx src/deploy.ts", 11 | "listen": "tsx src/listen.ts", 12 | "history": "tsx src/history.ts", 13 | "stop": "tsx src/stop.ts", 14 | "prettier": "prettier '**/src/**/*.ts' --check && as-prettier --check assembly", 15 | "prettier:fix": "prettier '**/src/**/*.ts' --write && as-prettier --write assembly", 16 | "lint": "eslint .", 17 | "lint:fix": "eslint . --fix", 18 | "fmt:check": "npm run prettier && npm run lint", 19 | "fmt": "npm run prettier:fix && npm run lint:fix" 20 | }, 21 | "keywords": [], 22 | "author": "", 23 | "license": "ISC", 24 | "devDependencies": { 25 | "@as-pect/cli": "^8.1.0", 26 | "@assemblyscript/loader": "^0.27.29", 27 | "@massalabs/as-types": "^2.0.0", 28 | "@massalabs/eslint-config": "^0.0.11", 29 | "@massalabs/massa-as-sdk": "^3.0.1-dev", 30 | "@massalabs/massa-sc-compiler": "^0.2.1-dev", 31 | "@massalabs/massa-sc-deployer": "^2.2.0", 32 | "@massalabs/massa-web3": "^5.2.0", 33 | "@massalabs/prettier-config-as": "^0.0.2", 34 | "@types/node": "^18.11.10", 35 | "assemblyscript": "^0.27.29", 36 | "assemblyscript-prettier": "^1.0.7", 37 | "dotenv": "^16.0.3", 38 | "prettier": "^2.8.1", 39 | "tslib": "^2.4.0", 40 | "tsx": "^4.7.0", 41 | "typescript": "^4.8.4" 42 | }, 43 | "overrides": { 44 | "visitor-as": { 45 | "assemblyscript": "$assemblyscript" 46 | } 47 | }, 48 | "type": "module", 49 | "prettier": "@massalabs/prettier-config-as", 50 | "engines": { 51 | "node": ">=16" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to massa-sc-examples 2 | Thank you for considering contributing to massa-sc-examples! 3 | 4 | ## Reporting Bugs 5 | If you discover a bug, please create a [new issue](https://github.com/massalabs/massa-sc-examples/issues/new?assignees=&labels=issue%3Abug&template=bug.md&title=) on our GitHub repository. 6 | In your issue, please include a clear and concise description of the bug, any relevant code snippets, error messages, and steps to reproduce the issue. 7 | 8 | ## Contributing Code 9 | We welcome contributions in the form of bug fixes, enhancements, and new features. 10 | 11 | To contribute code, please follow these steps: 12 | 13 | 1. Fork the massa-sc-examples repository to your own account. 14 | 2. Create a new branch from the `main` branch for your changes. 15 | 3. Make your changes and commit them to your branch. 16 | 4. Push your branch to your fork. 17 | 5. Create a pull request from your branch to the develop branch of the massa-sc-examples repository. 18 | 19 | > **NOTE:** When creating a pull request, please include a clear and concise title and description of your changes, as well as any relevant context or background information. 20 | 21 | ## Code Style 22 | Please ensure that your code follows the existing code style used in the project. 23 | We use the [MassaLabs Prettier configuration](https://github.com/massalabs/prettier-config-as) and [MassaLabs ESLint configuration](https://github.com/massalabs/eslint-config) for formatting and linting. 24 | 25 | You can run the following command to format your code before committing: 26 | 27 | ```sh 28 | npm run fmt 29 | ``` 30 | 31 | ## Tests 32 | Please ensure that your changes include any necessary tests in the CI. 33 | We use [as-pect library](https://as-pect.gitbook.io/as-pect/) for unit testing. 34 | 35 | You can run the following command to run the tests: 36 | 37 | ```sh 38 | npm run test 39 | ``` 40 | 41 | ## License 42 | By contributing to massa-sc-examples, you agree that your contributions will be licensed under the MIT License. 43 | -------------------------------------------------------------------------------- /fungible-token/smart-contract/README.md: -------------------------------------------------------------------------------- 1 | # My Massa Smart-contract Project 2 | 3 | ## Build 4 | 5 | By default this will build all files in `assembly/contracts` directory. 6 | 7 | ```shell 8 | npm run build 9 | ``` 10 | 11 | ## Deploy a smart contract 12 | 13 | Prerequisites : 14 | 15 | - You must add a `.env` file at the root of the repository with the following keys set to valid values : 16 | - WALLET_SECRET_KEY="wallet_secret_key" 17 | - JSON_RPC_URL_PUBLIC= 18 | 19 | These keys will be the ones used by the deployer script to interact with the blockchain. 20 | 21 | The following command will build contracts in `assembly/contracts` directory and execute the deployment script 22 | `src/deploy.ts`. This script will deploy on the node specified in the `.env` file. 23 | 24 | ```shell 25 | npm run deploy 26 | ``` 27 | 28 | You can modify `src/deploy.ts` to change the smart contract being deployed, and to pass arguments to the constructor 29 | function: 30 | 31 | - line 31: specify what contract you want to deploy 32 | - line 33: create the `Args` object to pass to the constructor of the contract you want to deploy 33 | 34 | When the deployment operation is executed on-chain, the 35 | [constructor](https://github.com/massalabs/massa-sc-toolkit/blob/main/packages/sc-project-initializer/commands/init/assembly/contracts/main.ts#L10) 36 | function of the smart contract being deployed will 37 | be called with the arguments provided in the deployment script. 38 | 39 | The deployment script uses [massa-sc-deployer library](https://www.npmjs.com/package/@massalabs/massa-sc-deployer) 40 | to deploy smart contracts. 41 | 42 | You can edit this script and use [massa-web3 library](https://www.npmjs.com/package/@massalabs/massa-web3) 43 | to create advanced deployment procedure. 44 | 45 | For more information, please visit our ReadTheDocs about 46 | [Massa smart-contract development](https://docs.massa.net/en/latest/web3-dev/smart-contracts.html). 47 | 48 | ## Unit tests 49 | 50 | The test framework documentation is available here: [as-pect docs](https://as-pect.gitbook.io/as-pect) 51 | 52 | ```shell 53 | npm run test 54 | ``` 55 | 56 | ## Format code 57 | 58 | ```shell 59 | npm run fmt 60 | ``` 61 | -------------------------------------------------------------------------------- /airdrop/smart-contract/assembly/contracts/airdrop.ts: -------------------------------------------------------------------------------- 1 | import { Address, generateEvent, Storage } from '@massalabs/massa-as-sdk'; 2 | import { bytesToU32, stringToBytes, u32ToBytes } from '@massalabs/as-types'; 3 | import { u256 } from 'as-bignum/assembly'; 4 | import { addressList } from '../const/addressList'; 5 | import { mrc20Address } from '../const/mrc20-address'; 6 | import { TokenWrapper } from '@massalabs/sc-standards/assembly/contracts/FT'; 7 | import { getBalanceEntryCost } from '@massalabs/sc-standards/assembly/contracts//FT/token-external'; 8 | 9 | const VERSION_KEY = stringToBytes('airdrop_version'); // Key to store the version of the airdrop 10 | const VERSION = u32(1); // Increment this number to run the airdrop again 11 | const AIRDROP_LIMIT = 850; // Maximum number of transfers per block 12 | 13 | export const MRC20_ADDRESS = new Address(mrc20Address); 14 | 15 | /** Update this value to the amount you wish to airdrop at each account */ 16 | const TOKEN_AMOUNT = 20; // Amount of tokens to airdrop 17 | 18 | /** 19 | * Main function to run the airdrop. Will be automatically called when executing the contract. 20 | */ 21 | export function main(_: StaticArray): void { 22 | checkAndSetAirdropVersion(); // Can be removed if you know what you are doing 23 | validateAddressLimit(); 24 | 25 | const coin = new TokenWrapper(MRC20_ADDRESS); 26 | const decimals = coin.decimals(); 27 | 28 | const amount = u256.fromU64(TOKEN_AMOUNT) * u256.fromU64(10 ** decimals); 29 | 30 | for (let i = 0; i < addressList.length; i++) { 31 | const cost = getBalanceEntryCost(mrc20Address, addressList[i]); 32 | generateEvent(cost.toString()); 33 | coin.transfer(new Address(addressList[i]), amount, cost); 34 | } 35 | 36 | generateEvent('Airdrop done'); 37 | } 38 | 39 | function checkAndSetAirdropVersion(): void { 40 | const previousVersion = Storage.has(VERSION_KEY) 41 | ? bytesToU32(Storage.get(VERSION_KEY)) 42 | : 0; 43 | 44 | assert( 45 | VERSION > previousVersion, 46 | `Airdrop already done for version ${VERSION}, please increase version number to ${ 47 | previousVersion + 1 48 | }`, 49 | ); 50 | 51 | Storage.set(VERSION_KEY, u32ToBytes(VERSION)); 52 | } 53 | 54 | function validateAddressLimit(): void { 55 | assert( 56 | addressList.length <= AIRDROP_LIMIT, 57 | 'Too many addresses. The number of transfers exceeds the block limit.', 58 | ); 59 | } 60 | -------------------------------------------------------------------------------- /hello-world/smart-contract/README.md: -------------------------------------------------------------------------------- 1 | # My Massa Smart-contract Project 2 | 3 | ## Build 4 | 5 | By default this will build all files in `assembly/contracts` directory. 6 | 7 | ```shell 8 | npm run build 9 | ``` 10 | 11 | ## Deploy a smart contract 12 | 13 | Prerequisites : 14 | 15 | - You must add a `.env` file at the root of the repository with the following keys set to valid values : 16 | - WALLET_SECRET_KEY="wallet_secret_key" 17 | - JSON_RPC_URL_PUBLIC= 18 | 19 | These keys will be the ones used by the deployer script to interact with the blockchain. 20 | 21 | The following command will build contracts in `assembly/contracts` directory and execute the deployment script 22 | `src/deploy.ts`. This script will deploy on the node specified in the `.env` file. 23 | 24 | ```shell 25 | npm run deploy 26 | ``` 27 | 28 | You can modify `src/deploy.ts` to change the smart contract being deployed, and to pass arguments to the constructor 29 | function: 30 | 31 | - line 31: specify what contract you want to deploy 32 | - line 33: create the `Args` object to pass to the constructor of the contract you want to deploy 33 | 34 | When the deployment operation is executed on-chain, the 35 | [constructor](https://github.com/massalabs/massa-sc-toolkit/blob/main/packages/sc-project-initializer/commands/init/assembly/contracts/main.ts#L10) 36 | function of the smart contract being deployed will 37 | be called with the arguments provided in the deployment script. 38 | 39 | The deployment script uses [massa-sc-deployer library](https://www.npmjs.com/package/@massalabs/massa-sc-deployer) 40 | to deploy smart contracts. 41 | 42 | You can edit this script and use [massa-web3 library](https://www.npmjs.com/package/@massalabs/massa-web3) 43 | to create advanced deployment procedure. 44 | 45 | For more information, please visit our ReadTheDocs about 46 | [Massa smart-contract development](https://docs.massa.net/en/latest/web3-dev/smart-contracts.html). 47 | 48 | ## Call a smart contract 49 | 50 | Prerequisites : 51 | 52 | - You must update the `.env` file at the root of the repository with the key: 53 | - CONTRACT_ADDRESS= 54 | where `` is the address of the smart contract the deployment script has returned. 55 | 56 | The following command will call the `setMessage` function of the smart contract previously deployed. 57 | 58 | ```shell 59 | npm run call 60 | ``` 61 | 62 | ## Unit tests 63 | 64 | The test framework documentation is available here: [as-pect docs](https://as-pect.gitbook.io/as-pect) 65 | 66 | ```shell 67 | npm run test 68 | ``` 69 | 70 | ## Format code 71 | 72 | ```shell 73 | npm run fmt 74 | ``` 75 | -------------------------------------------------------------------------------- /airdrop/smart-contract/src/airdrop.ts: -------------------------------------------------------------------------------- 1 | import { Account, Mas, MRC20, Web3Provider } from '@massalabs/massa-web3'; 2 | import * as dotenv from 'dotenv'; 3 | import { getScByteCode, logEvent } from './utils'; 4 | import { addressList } from '../assembly/const/addressList'; 5 | import { mrc20Address } from '../assembly/const/mrc20-address'; 6 | 7 | dotenv.config(); 8 | 9 | /* -------------------------------------------------------------------------- */ 10 | /* Init Provider */ 11 | /* -------------------------------------------------------------------------- */ 12 | const account = await Account.fromEnv(); 13 | const provider = Web3Provider.buildnet(account); 14 | 15 | /* -------------------------------------------------------------------------- */ 16 | /* Init MRC20 */ 17 | /* -------------------------------------------------------------------------- */ 18 | const mrc20 = new MRC20(provider, mrc20Address); 19 | const mr20Symbol = await mrc20.symbol(); 20 | let mrc20Balance = await mrc20.balanceOf(account.address.toString()); 21 | 22 | console.log(`My Mas balance: ${await provider.balance()}`); 23 | console.log(`My ${mr20Symbol} balance: ${mrc20Balance}`); 24 | 25 | /* -------------------------------------------------------------------------- */ 26 | /* Airdrop */ 27 | /* -------------------------------------------------------------------------- */ 28 | const operation = await provider.executeSC({ 29 | byteCode: getScByteCode('build', 'airdrop.wasm'), 30 | maxCoins: Mas.fromString('10'), // Maximum amount of coins allowed to be spend during the execution 31 | }); 32 | 33 | const events = await operation.getFinalEvents(); 34 | 35 | for (const [index, event] of events.entries()) { 36 | if (event.data.toString().includes('Error')) { 37 | throw new Error(`Error in event nº ${index + 1}: ${event.data.toString()}`); 38 | } 39 | logEvent(event, index); 40 | } 41 | 42 | /* -------------------------------------------------------------------------- */ 43 | /* Final Balances */ 44 | /* -------------------------------------------------------------------------- */ 45 | 46 | const balances = await mrc20.balancesOf(addressList); 47 | for (const { address, balance } of balances) { 48 | console.log(`Address: ${address}, Balance: ${balance.toString()}`); 49 | } 50 | 51 | mrc20Balance = await mrc20.balanceOf(account.address.toString()); 52 | 53 | console.log('My final MAS balance:', (await provider.balance()).toString()); 54 | console.log('My final', mr20Symbol, 'balance:', mrc20Balance.toString()); 55 | -------------------------------------------------------------------------------- /hello-world/smart-contract/src/call.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | import 'dotenv/config'; 3 | import { 4 | Account, 5 | Args, 6 | Mas, 7 | Web3Provider, 8 | OperationStatus, 9 | SmartContract, 10 | bytesToStr, 11 | } from '@massalabs/massa-web3'; 12 | import { getAccountProvider, getContractAddress } from './utils'; 13 | 14 | /** 15 | * Call the `setMessage` function of the smart contract previously deployed. 16 | * 17 | * Prerequisites : 18 | * - You must update the `.env` file at the root of the repository with the key: 19 | * - CONTRACT_ADDRESS="contract_address" 20 | * where `"contract_address"` is the address of the smart contract the deployment 21 | * script has returned. 22 | * 23 | * After the `setMessage` function is called, the smart contract will emit an 24 | * event. 25 | * This function will wait for the event to be emitted and then display the 26 | * event data and the origin operation id. 27 | */ 28 | async function callSetMessage(message: string) { 29 | const contractAddress = await getContractAddress(); 30 | const provider = await getAccountProvider(); 31 | 32 | console.log('Calling setMessage function...'); 33 | 34 | const helloContract = new SmartContract(provider, contractAddress); 35 | const operation = await helloContract.call( 36 | 'setMessage', 37 | new Args().addString(message).serialize(), 38 | { 39 | coins: Mas.fromString('0.01'), 40 | }, 41 | ); 42 | 43 | console.log( 44 | 'setMessage function called successfully, operation id:', 45 | operation.id, 46 | ); 47 | 48 | console.log('Waiting for operation to be finalized...'); 49 | const status = await operation.waitFinalExecution(); 50 | console.log('Operation status:', OperationStatus[status]); 51 | if (status !== OperationStatus.Success) { 52 | throw new Error('Operation failed'); 53 | } 54 | 55 | const events = await provider.getEvents({ 56 | smartContractAddress: contractAddress, 57 | operationId: operation.id, 58 | }); 59 | 60 | for (const event of events) { 61 | console.log( 62 | `Event: "${event.data}" received for operation: ${event.context.origin_operation_id}`, 63 | ); 64 | } 65 | } 66 | 67 | async function callGetMessage() { 68 | const contractAddress = await getContractAddress(); 69 | const provider = await getAccountProvider(); 70 | 71 | const helloContract = new SmartContract(provider, contractAddress); 72 | const message = await helloContract.read( 73 | 'getMessage', 74 | new Args().serialize(), 75 | { 76 | coins: Mas.fromString('0.01'), 77 | }, 78 | ); 79 | 80 | console.log('Message:', bytesToStr(message.value)); 81 | } 82 | 83 | await callSetMessage('Hello, Massa friends!'); 84 | 85 | await callGetMessage(); 86 | -------------------------------------------------------------------------------- /async-call/assembly/contracts/main.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Context, 3 | generateEvent, 4 | Storage, 5 | asyncCall, 6 | Slot, 7 | } from '@massalabs/massa-as-sdk'; 8 | import { Args, stringToBytes } from '@massalabs/as-types'; 9 | 10 | // Constants for asyncCall gas and fee 11 | const ASYNC_CALL_GAS: u64 = 2100_000; 12 | const ASYNC_CALL_FEE: u64 = 1; 13 | const MSG_KEY = 'messageKey'; 14 | /** 15 | * This function is meant to be called only one time: when the contract is deployed. 16 | * 17 | * @param binaryArgs - Arguments serialized with Args 18 | */ 19 | export function constructor(binaryArgs: StaticArray): void { 20 | // This line is important. It ensures that this function can't be called in the future. 21 | // If you remove this check, someone could call your constructor function and reset your smart contract. 22 | if (!Context.isDeployingContract()) return; 23 | 24 | const args = new Args(binaryArgs); 25 | 26 | const message = args 27 | .nextString() 28 | .expect('Name argument is missing or invalid'); 29 | 30 | Storage.set(MSG_KEY, message); 31 | generateEvent(`Constructor called with message ${message}`); 32 | } 33 | 34 | /** 35 | * This function auto triggers itself asynchronously, 36 | * it will call itself every 2 periods. 37 | */ 38 | export function asyncHello(): void { 39 | generateEvent(`Hello friend!`); 40 | 41 | const currentPeriod = Context.currentPeriod(); 42 | const currentThread = Context.currentThread(); 43 | 44 | // Schedule the async call for 2 periods in the future 45 | const startSlot = new Slot(currentPeriod + 2, currentThread); 46 | const endSlot = new Slot(currentPeriod + 3, currentThread); 47 | 48 | asyncCall( 49 | Context.callee(), // target: the current contract 50 | 'asyncHello', // functionName: the function to call asynchronously 51 | startSlot, // startSlot: the slot when the call becomes valid 52 | endSlot, // endSlot: the slot when the call expires 53 | ASYNC_CALL_GAS, // maxGas: maximum gas for the call 54 | ASYNC_CALL_FEE, // rawFee: fee for the call 55 | ); 56 | 57 | generateEvent( 58 | `Next call scheduled for period ${startSlot.period} thread ${startSlot.thread}`, 59 | ); 60 | } 61 | 62 | 63 | /** 64 | * This function updates the message stored in the contract storage. 65 | * 66 | * @param binaryArgs - Arguments serialized with Args 67 | */ 68 | export function setMessage(binaryArgs: StaticArray): void { 69 | const args = new Args(binaryArgs); 70 | 71 | const message = args 72 | .nextString() 73 | .expect('Message argument is missing or invalid'); 74 | 75 | Storage.set(MSG_KEY, message); 76 | generateEvent(`Message updated to ${message}`); 77 | } 78 | 79 | /** 80 | * This function returns the message stored in the contract storage. 81 | */ 82 | export function getMessage(): StaticArray { 83 | return Storage.get(stringToBytes(MSG_KEY)); 84 | } 85 | -------------------------------------------------------------------------------- /deferred-call-manager/assembly/internals.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Args, 3 | bytesToU64, 4 | stringToBytes, 5 | u64ToBytes, 6 | } from '@massalabs/as-types'; 7 | import { 8 | balance, 9 | Context, 10 | deferredCallCancel, 11 | deferredCallExists, 12 | deferredCallQuote, 13 | deferredCallRegister, 14 | findCheapestSlot, 15 | generateEvent, 16 | Storage, 17 | } from '@massalabs/massa-as-sdk'; 18 | import { History } from './serializable/history'; 19 | 20 | export const NEXT_CALL_ID_KEY = 'callId'; 21 | export const HISTORY_KEY = stringToBytes('hist'); 22 | export const TASK_COUNT_KEY = stringToBytes('idx'); 23 | 24 | export function registerCall(period: u64): void { 25 | const initBal = balance(); 26 | generateEvent('Current contract balance: ' + initBal.toString()); 27 | 28 | const maxGas = 20_000_000; 29 | const paramsSize = 0; 30 | const bookingPeriod = Context.currentPeriod() + period; 31 | const slot = findCheapestSlot( 32 | bookingPeriod, 33 | bookingPeriod, 34 | maxGas, 35 | paramsSize, 36 | ); 37 | 38 | const cost = deferredCallQuote(slot, maxGas, paramsSize); 39 | const callId = deferredCallRegister( 40 | Context.callee().toString(), 41 | 'processTask', 42 | slot, 43 | maxGas, 44 | new Args().add(period).serialize(), 45 | // No need to provide coins as processTask is internal function 46 | 0, 47 | ); 48 | 49 | const bookingCost = initBal - balance(); 50 | 51 | Storage.set(NEXT_CALL_ID_KEY, callId); 52 | generateEvent( 53 | `Deferred call registered. id: ${callId}. Booked slot period: ${bookingPeriod.toString()}.\ 54 | Booking cost: ${bookingCost.toString()}, quote: ${cost.toString()}`, 55 | ); 56 | } 57 | 58 | function getTaskIndex(): u64 { 59 | return bytesToU64(Storage.get(TASK_COUNT_KEY)); 60 | } 61 | 62 | function getHistoryKey(taskIndex: u64): StaticArray { 63 | return HISTORY_KEY.concat(u64ToBytes(taskIndex)); 64 | } 65 | 66 | export function processTask(binArgs: StaticArray): void { 67 | assert( 68 | Context.callee() === Context.caller(), 69 | 'The caller must be the contract itself', 70 | ); 71 | 72 | const taskIndex = getTaskIndex(); 73 | const callId = Storage.get(NEXT_CALL_ID_KEY); 74 | 75 | generateEvent(`Processing task ${taskIndex}. Call id : ${callId}`); 76 | 77 | // Save execution history 78 | const key = getHistoryKey(taskIndex); 79 | Storage.set( 80 | key, 81 | new History( 82 | Context.currentPeriod(), 83 | Context.currentThread(), 84 | callId, 85 | ).serialize(), 86 | ); 87 | 88 | // Increment task index 89 | Storage.set(TASK_COUNT_KEY, u64ToBytes(taskIndex + 1)); 90 | 91 | const period = new Args(binArgs).nextU64().expect('Unable to decode period'); 92 | registerCall(period); 93 | } 94 | 95 | export function cancelCall(callId: string): void { 96 | if (deferredCallExists(callId)) { 97 | deferredCallCancel(callId); 98 | generateEvent('Deferred call canceled. id : ' + callId); 99 | } else { 100 | generateEvent('Deferred call does not exist. id: ' + callId); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /hello-world/front/vanilla-js/app.js: -------------------------------------------------------------------------------- 1 | import { getWallets, WalletName } from "@massalabs/wallet-provider"; 2 | import { Args, bytesToStr, OperationStatus } from "@massalabs/massa-web3"; 3 | 4 | const CONTRACT_ADDRESS = 5 | "AS12mFfp7XA8U5QyRPBWNT5V5BLeEMxuoxHft5Ph8y9uGH2SecDXw"; 6 | 7 | let provider; 8 | 9 | function showError(message) { 10 | const errorElement = document.getElementById("errorMessage"); 11 | errorElement.textContent = message; 12 | errorElement.classList.add("visible"); 13 | setTimeout(() => { 14 | errorElement.classList.remove("visible"); 15 | }, 3000); 16 | } 17 | 18 | async function initProvider() { 19 | try { 20 | const walletList = await getWallets(); 21 | const wallet = walletList.find( 22 | (provider) => provider.name() === WalletName.MassaWallet 23 | ); 24 | if (!wallet) { 25 | throw new Error( 26 | "Wallet not detected. To proceed, please install the Massa wallet and configure it for the Buildnet network" 27 | ); 28 | } 29 | 30 | const accounts = await wallet.accounts(); 31 | 32 | if (accounts.length === 0) { 33 | throw new Error("No accounts found"); 34 | } 35 | 36 | provider = accounts[0]; 37 | } catch (error) { 38 | showError(error.message); 39 | } 40 | } 41 | 42 | async function getMessage() { 43 | if (!provider) { 44 | showError("No provider found"); 45 | return ""; 46 | } 47 | try { 48 | const result = await provider.readSC({ 49 | func: "getMessage", 50 | target: CONTRACT_ADDRESS, 51 | }); 52 | 53 | return bytesToStr(result.value); 54 | } catch (error) { 55 | showError("Failed to get message: " + error.message); 56 | return ""; 57 | } 58 | } 59 | 60 | async function setMessage(message) { 61 | if (!provider) { 62 | showError("No provider found"); 63 | return; 64 | } 65 | 66 | if (!message) { 67 | showError("Message cannot be empty"); 68 | return; 69 | } 70 | 71 | try { 72 | const op = await provider.callSC({ 73 | parameter: new Args().addString(message).serialize(), 74 | func: "setMessage", 75 | target: CONTRACT_ADDRESS, 76 | }); 77 | 78 | const status = await op.waitSpeculativeExecution(); 79 | 80 | if (status !== OperationStatus.SpeculativeSuccess) { 81 | throw new Error("Transaction failed"); 82 | } 83 | 84 | updateMessage(); 85 | } catch (error) { 86 | showError("Failed to set message: " + error.message); 87 | } 88 | } 89 | 90 | async function updateMessage() { 91 | const messageElement = document.getElementById("message"); 92 | messageElement.textContent = await getMessage(); 93 | } 94 | 95 | document.addEventListener("DOMContentLoaded", async () => { 96 | await initProvider(); 97 | 98 | if (!provider) { 99 | document.querySelector(".app-container").textContent = 100 | "Loading Provider..."; 101 | return; 102 | } 103 | 104 | const form = document.getElementById("messageForm"); 105 | const inputMessage = document.getElementById("inputMessage"); 106 | const getMessageBtn = document.getElementById("getMessageBtn"); 107 | 108 | form.addEventListener("submit", async (e) => { 109 | e.preventDefault(); 110 | await setMessage(inputMessage.value); 111 | inputMessage.value = ""; 112 | }); 113 | 114 | getMessageBtn.addEventListener("click", updateMessage); 115 | }); 116 | -------------------------------------------------------------------------------- /airdrop/smart-contract/README.md: -------------------------------------------------------------------------------- 1 | # Execute Airdrop 2 | --- 3 | ## Overview 4 | 5 | `Execute airdrop` is an example designed to demonstrate the use of `executeSc` for executing smart contracts directly on-chain without deployment. This repository showcases an **Airdrop** smart contract, which distributes MRC20 tokens to a predefined list of addresses in a single atomic operation. 6 | 7 | The **Airdrop** smart contract leverages `executeSc` to ensure that the operation is atomic — if any transaction fails, all transactions in the airdrop revert, preventing partial token distribution. 8 | 9 | --- 10 | 11 | ## Prerequisites 12 | 13 | - [Node.js](https://nodejs.org/) (v18+) 14 | - Massa Account 15 | - [Node.js](https://nodejs.org/) (v18+) 16 | - Massa Account 17 | - MRC20 Token Contract (Deployed). Check the [fungible token standard](https://github.com/massalabs/massa-standards/tree/main/smart-contracts/assembly/contracts/FT) for more details. 18 | 19 | 20 | ## Installation 21 | 22 | 1. Install dependencies: 23 | ```bash 24 | npm install 25 | ``` 26 | 27 | 2. Configure environment variables by creating a `.env` file: 28 | ```plaintext 29 | PRIVATE_KEY=your_private_key 30 | ``` 31 | 32 | 3. Update the `addressList` in `addressList.ts` with the recipient addresses for the airdrop. 33 | 4. Update MRC20 contract address in `assembly/contracts/mrc20-address.ts` contract. 34 | 5. Update token amount in `airdrop.ts` contract. 35 | 36 | 37 | ## Scripts 38 | 39 | Build the smart contracts: 40 | ```bash 41 | npm run build 42 | ``` 43 | 44 | Execute the Airdrop smart contract: 45 | ```bash 46 | npm run airdrop 47 | ``` 48 | 49 | ## Smart Contracts 50 | 51 | ### Airdrop Contract 52 | - Distributes an `amount`of Tokens tokens to each address in the predefined `addressList`. 53 | - Key Features: 54 | - Validates that the airdrop has not been executed previously (version control). 55 | - Ensures the number of recipients does not exceed block limits. 56 | - **Important**: 57 | - **Version Tracking**: Update the `VERSION` constant in the `airdrop.ts` contract file before executing a new airdrop. 58 | - **MRC20 Contract Address**: Replace the placeholder MRC20 address in the `assembly/contracts/mrc20-address.ts` file with the actual deployed MRC20 address. 59 | 60 | 61 | ## Usage 62 | 63 | ### Executing the Airdrop 64 | 1. Ensure the MRC20 tokens are minted and available in your wallet. 65 | 2. **Update `airdrop.ts`**: 66 | - Set the correct `VERSION` value if running the airdrop for the first time or after modifications. 67 | - Replace the placeholder MRC20 contract address with the actual one. 68 | 3. Run the Airdrop contract: 69 | `npm run airdrop` 70 | 71 | 4. Check the balances of recipient addresses in `addressList` to verify successful distribution. 72 | 73 | 74 | ## Address List 75 | 76 | The recipient addresses for the airdrop are defined in `addressList.ts`. Update this list with your desired addresses before execution. Limited to 850 addresses per airdrop due to block limits. 77 | 78 | ```typescript 79 | export const addressList = [ 80 | 'AU1jCffxJFjMQRg1WkoT1gDiFvZGg1WuogiwBWQFZ2LJwEyHPRPZ', 81 | 'AU1rFqhTWvRyuJT3UH5ZZSBjALcAsjXCPPcgUkWaBghYsYicTrB5', 82 | // Add more addresses as needed 83 | ]; 84 | ``` 85 | 86 | 87 | ## Notes 88 | 89 | - **Atomic Execution**: Leveraging `executeSc` ensures that either all transactions succeed, or none are executed, preventing partial token distributions. 90 | - **Version Control**: Always update the `VERSION` in the Airdrop contract to prevent accidental reruns. 91 | - **MRC20 Contract Address**: Ensure the MRC20 contract address is updated in `assembly/contracts/mrc20-address` before executing the airdrop. 92 | -------------------------------------------------------------------------------- /hello-world/front/react/src/App.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect } from "react"; 2 | import "./App.css"; 3 | import { getWallets, WalletName } from "@massalabs/wallet-provider"; 4 | import { 5 | Args, 6 | bytesToStr, 7 | OperationStatus, 8 | Provider, 9 | } from "@massalabs/massa-web3"; 10 | 11 | const CONTRACT_ADDRESS = 12 | "AS12mFfp7XA8U5QyRPBWNT5V5BLeEMxuoxHft5Ph8y9uGH2SecDXw"; 13 | 14 | function App() { 15 | const [provider, setProvider] = useState(); 16 | const [message, setMessage] = useState(""); 17 | const [inputMessage, setInputMessage] = useState(""); 18 | 19 | const getMessage = async () => { 20 | if (!provider) { 21 | console.log("No provider found"); 22 | return ""; 23 | } 24 | const result = await provider.readSC({ 25 | func: "getMessage", 26 | target: CONTRACT_ADDRESS, 27 | }); 28 | 29 | return bytesToStr(result.value); 30 | }; 31 | 32 | async function initProvider() { 33 | const walletList = await getWallets(); 34 | const wallet = walletList.find( 35 | (provider) => provider.name() === WalletName.MassaWallet 36 | ); 37 | if (!wallet) { 38 | console.log("No wallet found"); 39 | return; 40 | } 41 | 42 | const accounts = await wallet?.accounts(); 43 | 44 | if (accounts.length === 0) { 45 | console.log("No accounts found"); 46 | return; 47 | } 48 | 49 | // We use the first account as the provider 50 | const provider = accounts[0]; 51 | setProvider(provider); 52 | } 53 | 54 | useEffect(() => { 55 | initProvider(); 56 | }, []); 57 | 58 | const handleSubmit = async (e: React.FormEvent) => { 59 | if (!provider) { 60 | alert("No provider found"); 61 | return; 62 | } 63 | 64 | e.preventDefault(); 65 | 66 | if (!inputMessage) { 67 | alert("Message cannot be empty"); 68 | } 69 | 70 | const op = await provider.callSC({ 71 | parameter: new Args().addString(inputMessage).serialize(), 72 | func: "setMessage", 73 | target: CONTRACT_ADDRESS, 74 | }); 75 | 76 | const status = await op.waitSpeculativeExecution(); 77 | 78 | if (status !== OperationStatus.SpeculativeSuccess) { 79 | alert("Failed to set message"); 80 | return; 81 | } 82 | 83 | setMessage(await getMessage()); 84 | setInputMessage(""); 85 | }; 86 | 87 | if (!provider) { 88 | return ( 89 |
90 |

Loading Provider...

91 |

92 | Please install the Massa wallet and configure it for the Buildnet 93 | network 94 |

95 |
96 | ); 97 | } 98 | 99 | return ( 100 |
101 |
102 |

Message App

103 |
104 | setInputMessage(e.target.value)} 108 | placeholder="Enter a message" 109 | className="input" 110 | /> 111 | 114 |
115 | 121 |
122 |

{message}

123 |
124 |
125 |
126 | ); 127 | } 128 | 129 | export default App; 130 | -------------------------------------------------------------------------------- /fungible-token/front/react/src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /hello-world/front/react/src/assets/react.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Massa Smart Contract Development 2 | 3 | This repository provides information and resources for developing smart contracts on the Massa blockchain using the latest tooling. 4 | 5 | > **Important Version Information** 6 | > 7 | > This project uses the next version of Massa development tools, which includes significant improvements and new features. If you need to reference older versions or examples, please check the `legacy` folder in this repository. 8 | 9 | ## Current Tooling 10 | 11 | The Massa blockchain ecosystem now uses the following tools for smart contract development: 12 | 13 | - [Massa Smart Contract Toolkit](https://github.com/massalabs/massa-sc-toolkit): A comprehensive toolkit for developing, testing, and deploying smart contracts on Massa. 14 | - [Massa Web3](https://github.com/massalabs/massa-web3/tree/next): A JavaScript library for interacting with the Massa blockchain. 15 | - [Massa wallet-provider](https://github.com/massalabs/wallet-provider/tree/next): A Web3 provider for connecting to the Massa wallet. 16 | 17 | ## Hello World Project 18 | 19 | This repository includes a Hello World project to help you get started with Massa smart contract development. Here's what you need to know: 20 | 21 | 1. **Smart Contract Setup**: 22 | 23 | - Navigate to the `smart-contract` folder. 24 | - Create a `.env` file in this folder. 25 | - Add a private key that owns some coins to the `.env` file. 26 | - **Important**: Be careful not to push the `.env` file to version control. 27 | 28 | 2. **Testing**: 29 | 30 | - Run tests using the command: `npm run test` 31 | 32 | 3. **Deployment**: 33 | - Check the deploy file to understand how contracts are deployed. 34 | - Deploy the contract using: `npm run deploy` 35 | 36 | # Massa Smart Contract Development 37 | 38 | ## Front-end Implementations 39 | 40 | We provide two front-end implementations for interacting with the smart contract: 41 | 42 | 1. **Vanilla JavaScript Version**: 43 | 44 | - Located in the `vanilla-js` folder. 45 | - Setup: Run `npm install` 46 | - Start the development server: `npm run dev` 47 | 48 | 2. **React Version**: 49 | - Located in the `react` folder. 50 | - Setup: Run `npm install` 51 | - Start the development server: `npm run dev` 52 | 53 | Both versions demonstrate the same functionality but use different technologies. 54 | 55 | ### Vite Configuration and Polyfills 56 | 57 | To ensure compatibility with Vite and to provide necessary polyfills, we have done the following: 58 | 59 | 1. Install required dependencies: 60 | 61 | ``` 62 | npm install lodash-es 63 | npm install vite-plugin-node-polyfills 64 | ``` 65 | 66 | 2. Create a `vite.config.js` file in your project root with the following content: 67 | 68 | ```javascript 69 | import { defineConfig } from "vite"; 70 | import { nodePolyfills } from "vite-plugin-node-polyfills"; 71 | 72 | export default defineConfig({ 73 | plugins: [nodePolyfills()], 74 | resolve: { 75 | alias: { 76 | lodash: "lodash-es", 77 | }, 78 | }, 79 | build: { 80 | rollupOptions: { 81 | external: ["lodash"], 82 | }, 83 | }, 84 | }); 85 | ``` 86 | 87 | This configuration adds the necessary Node.js polyfills and resolves lodash to its ES module version. 88 | 89 | **Use it in your own Vite projects to ensure compatibility with the Massa Web3 library.** 90 | 91 | ## Resources 92 | 93 | - [Massa Documentation](https://docs.massa.net/) 94 | - [Massa Smart Contract Development Guide](https://docs.massa.net/docs/build/smart-contract/intro) 95 | - [Massa Web3 API Reference (legacy version)](https://web3.docs.massa.net/) 96 | - [Massa official website](https://massa.net/) 97 | 98 | ## Legacy Projects 99 | 100 | For reference to older projects and examples, please check the `legacy` folder in this repository. Note that these projects may use outdated tools or approaches and are kept for historical purposes only. 101 | 102 | ## Contributing 103 | 104 | We welcome contributions to improve smart contract development resources for Massa. Please see the [CONTRIBUTING file](CONTRIBUTING.md) for more information on how to contribute. 105 | 106 | ## License 107 | 108 | This repository is licensed under the [MIT License](LICENSE). 109 | -------------------------------------------------------------------------------- /fungible-token/front/react/src/App.tsx: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useCallback } from "react"; 2 | import "./App.css"; 3 | import { getWallets, WalletName } from "@massalabs/wallet-provider"; 4 | import { MRC20, OperationStatus, Provider } from "@massalabs/massa-web3"; 5 | 6 | const CONTRACT_ADDRESS = 7 | "AS12J2t29NT5VyZVQHBCmQFLNFqwpiZZtwcbHQTHWLJtWFXsz3U96"; 8 | 9 | function App() { 10 | const [provider, setProvider] = useState(); 11 | const [tokenName, setTokenName] = useState(""); 12 | const [tokenSymbol, setTokenSymbol] = useState(""); 13 | const [totalSupply, setTotalSupply] = useState(0n); 14 | const [userBalance, setUserBalance] = useState(0n); 15 | const [userAddress, setUserAddress] = useState(""); 16 | const [mrc20, setMrc20] = useState(); 17 | const [recipientAddress, setRecipientAddress] = useState(""); 18 | const [transferAmount, setTransferAmount] = useState(""); 19 | const [transferStatus, setTransferStatus] = useState(""); 20 | 21 | useEffect(() => { 22 | if (provider) { 23 | setMrc20(new MRC20(provider, CONTRACT_ADDRESS)); 24 | } 25 | }, [provider]); 26 | 27 | const fetchTokenInfo = useCallback(async () => { 28 | if (!mrc20) { 29 | console.log("MRC20 instance not initialized"); 30 | return; 31 | } 32 | 33 | try { 34 | setTokenName(await mrc20.name()); 35 | setTokenSymbol(await mrc20.symbol()); 36 | setTotalSupply(await mrc20.totalSupply()); 37 | setUserBalance(await mrc20.balanceOf(userAddress)); 38 | } catch (error) { 39 | console.error("Error fetching token info:", error); 40 | } 41 | }, [mrc20, userAddress]); 42 | 43 | useEffect(() => { 44 | const initProvider = async () => { 45 | const walletList = await getWallets(); 46 | const wallet = walletList.find( 47 | (provider) => provider.name() === WalletName.MassaWallet 48 | ); 49 | if (!wallet) { 50 | console.log("No wallet found"); 51 | return; 52 | } 53 | 54 | const accounts = await wallet?.accounts(); 55 | 56 | if (accounts.length === 0) { 57 | console.log("No accounts found"); 58 | return; 59 | } 60 | 61 | const provider = accounts[0]; 62 | setProvider(provider); 63 | setUserAddress(await provider.address); 64 | }; 65 | initProvider(); 66 | }, []); 67 | 68 | useEffect(() => { 69 | if (mrc20) { 70 | fetchTokenInfo(); 71 | } 72 | }, [fetchTokenInfo, mrc20]); 73 | 74 | const handleTransfer = async (e: React.FormEvent) => { 75 | e.preventDefault(); 76 | if (!mrc20) { 77 | setTransferStatus("MRC20 instance not initialized"); 78 | return; 79 | } 80 | 81 | try { 82 | const amount = BigInt(transferAmount); 83 | const operation = await mrc20.transfer(recipientAddress, amount); 84 | 85 | setTransferStatus(`Transfer initiated. Operation ID: ${operation.id}`); 86 | 87 | const status = await operation.waitSpeculativeExecution(); 88 | 89 | operation.getSpeculativeEvents().then((events) => { 90 | console.log("Speculative events:", events); 91 | }); 92 | 93 | if (status === OperationStatus.SpeculativeSuccess) { 94 | setTransferStatus("Transfer successful!"); 95 | fetchTokenInfo(); // Refresh token info after transfer 96 | } else { 97 | setTransferStatus("Transfer failed"); 98 | } 99 | } catch (error) { 100 | console.error("Transfer error:", error); 101 | setTransferStatus(`Transfer failed: ${error}`); 102 | } 103 | }; 104 | 105 | if (!provider) { 106 | return
Loading Provider...
; 107 | } 108 | 109 | return ( 110 |
111 |
112 |

Token Info DApp

113 |

114 | Deploy your own token with your address to have a positive balance. 115 |

116 |
117 |

118 | Token Name: {tokenName} 119 |

120 |

121 | Token Symbol: {tokenSymbol} 122 |

123 |

124 | Total Supply: {totalSupply.toString()} 125 |

126 |

127 | Your Address: {userAddress} 128 |

129 |

130 | Your Balance: {userBalance.toString()} 131 |

132 |
133 | 136 | 137 |

Transfer Tokens

138 |
139 | setRecipientAddress(e.target.value)} 143 | placeholder="Recipient Address" 144 | className="input" 145 | /> 146 | setTransferAmount(e.target.value)} 150 | placeholder="Amount" 151 | className="input" 152 | /> 153 | 156 |
157 | {transferStatus &&

{transferStatus}

} 158 |
159 |
160 | ); 161 | } 162 | 163 | export default App; 164 | --------------------------------------------------------------------------------