├── src ├── token_assets │ ├── assets │ │ ├── favicon.ico │ │ └── main.css │ └── src │ │ ├── components │ │ ├── Header.jsx │ │ ├── App.jsx │ │ ├── Faucet.jsx │ │ ├── Balance.jsx │ │ └── Transfer.jsx │ │ ├── index.html │ │ └── index.jsx ├── declarations │ ├── token │ │ ├── token.did │ │ ├── token.did.d.ts │ │ ├── token.did.js │ │ └── index.js │ └── token_assets │ │ ├── index.js │ │ ├── token_assets.did.d.ts │ │ ├── assetstorage.did │ │ ├── token_assets.did │ │ └── token_assets.did.js └── token │ └── main.mo ├── .gitignore ├── tsconfig.json ├── dfx.json ├── LICENSE ├── package.json ├── README.md └── webpack.config.js /src/token_assets/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arjuncvinod/Crypto-Token/HEAD/src/token_assets/assets/favicon.ico -------------------------------------------------------------------------------- /src/declarations/token/token.did: -------------------------------------------------------------------------------- 1 | service : { 2 | balanceOf: (principal) -> (nat) query; 3 | getSymbol: () -> (text) query; 4 | payOut: () -> (text); 5 | transfer: (principal, nat) -> (text); 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Various IDEs and Editors 2 | .vscode/ 3 | .idea/ 4 | **/*~ 5 | 6 | # Mac OSX temporary files 7 | .DS_Store 8 | **/.DS_Store 9 | 10 | # dfx temporary files 11 | .dfx/ 12 | 13 | # frontend code 14 | node_modules/ 15 | dist/ 16 | -------------------------------------------------------------------------------- /src/declarations/token/token.did.d.ts: -------------------------------------------------------------------------------- 1 | import type { Principal } from '@dfinity/principal'; 2 | export interface _SERVICE { 3 | 'balanceOf' : (arg_0: Principal) => Promise, 4 | 'getSymbol' : () => Promise, 5 | 'payOut' : () => Promise, 6 | 'transfer' : (arg_0: Principal, arg_1: bigint) => Promise, 7 | } 8 | -------------------------------------------------------------------------------- /src/token_assets/src/components/Header.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | function Header() { 4 | return ( 5 |
6 | 14 |
15 | ); 16 | } 17 | 18 | export default Header; 19 | -------------------------------------------------------------------------------- /src/declarations/token/token.did.js: -------------------------------------------------------------------------------- 1 | export const idlFactory = ({ IDL }) => { 2 | return IDL.Service({ 3 | 'balanceOf' : IDL.Func([IDL.Principal], [IDL.Nat], ['query']), 4 | 'getSymbol' : IDL.Func([], [IDL.Text], ['query']), 5 | 'payOut' : IDL.Func([], [IDL.Text], []), 6 | 'transfer' : IDL.Func([IDL.Principal, IDL.Nat], [IDL.Text], []), 7 | }); 8 | }; 9 | export const init = ({ IDL }) => { return []; }; 10 | -------------------------------------------------------------------------------- /src/token_assets/src/components/App.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import Header from "./Header"; 3 | import Faucet from "./Faucet"; 4 | import Balance from "./Balance"; 5 | import Transfer from "./Transfer"; 6 | 7 | function App(props) { 8 | 9 | return ( 10 |
11 |
12 | 13 | 14 | 15 |
16 | ); 17 | } 18 | 19 | export default App; 20 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2018", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */ 4 | "lib": ["ES2018", "DOM"], /* Specify library files to be included in the compilation. */ 5 | "allowJs": true, /* Allow javascript files to be compiled. */ 6 | "jsx": "react", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 7 | }, 8 | "include": ["src/**/*"], 9 | } -------------------------------------------------------------------------------- /src/token_assets/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | DFaucet 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /dfx.json: -------------------------------------------------------------------------------- 1 | { 2 | "canisters": { 3 | "token": { 4 | "main": "src/token/main.mo", 5 | "type": "motoko" 6 | }, 7 | "token_assets": { 8 | "dependencies": [ 9 | "token" 10 | ], 11 | "frontend": { 12 | "entrypoint": "src/token_assets/src/index.html" 13 | }, 14 | "source": [ 15 | "src/token_assets/assets", 16 | "dist/token_assets/" 17 | ], 18 | "type": "assets" 19 | } 20 | }, 21 | "defaults": { 22 | "build": { 23 | "args": "", 24 | "packtool": "" 25 | } 26 | }, 27 | "dfx": "0.9.3", 28 | "networks": { 29 | "local": { 30 | "bind": "127.0.0.1:8000", 31 | "type": "ephemeral" 32 | } 33 | }, 34 | "version": 1 35 | } 36 | -------------------------------------------------------------------------------- /src/token_assets/src/index.jsx: -------------------------------------------------------------------------------- 1 | import ReactDOM from "react-dom"; 2 | import React from "react"; 3 | import App from "./components/App"; 4 | import { AuthClient } from "@dfinity/auth-client"; 5 | import { Principal } from "@dfinity/principal"; 6 | 7 | const init = async () => { 8 | const authClient = await AuthClient.create(); 9 | 10 | if (await authClient.isAuthenticated()) { 11 | handleAuthenticated(authClient); 12 | } else { 13 | await authClient.login({ 14 | identityProvider: "https://identity.ic0.app/#authorize", 15 | onSuccess: () => { 16 | handleAuthenticated(authClient); 17 | }, 18 | }); 19 | } 20 | }; 21 | 22 | async function handleAuthenticated(authClient) { 23 | const identity = await authClient.getIdentity(); 24 | const userPrincipal = identity._principal.toString(); 25 | console.log(userPrincipal); 26 | ReactDOM.render( 27 | , 28 | document.getElementById("root") 29 | ); 30 | } 31 | 32 | init(); 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Arjun C Vinod 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. 22 | -------------------------------------------------------------------------------- /src/token_assets/src/components/Faucet.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { canisterId, createActor } from "../../../declarations/token"; 3 | import { AuthClient } from "@dfinity/auth-client"; 4 | 5 | function Faucet(props) { 6 | 7 | const [isDisabled, setDisable] = useState(false); 8 | const [buttonText, setText] = useState("Gimme gimme"); 9 | 10 | async function handleClick(event) { 11 | setDisable(true); 12 | 13 | const authClient = await AuthClient.create(); 14 | const identity = await authClient.getIdentity(); 15 | 16 | const authenticatedCanister = createActor(canisterId, { 17 | agentOptions: { 18 | identity, 19 | }, 20 | }); 21 | 22 | const result = await authenticatedCanister.payOut(); 23 | setText(result); 24 | } 25 | 26 | return ( 27 |
28 |

29 | 30 | 🚰 31 | 32 | Faucet 33 |

34 | 35 |

36 | 43 |

44 |
45 | ); 46 | } 47 | 48 | export default Faucet; 49 | -------------------------------------------------------------------------------- /src/token_assets/src/components/Balance.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { Principal } from '@dfinity/principal'; 3 | import { token } from "../../../declarations/token"; 4 | 5 | function Balance() { 6 | 7 | const [inputValue, setInput] = useState(""); 8 | const [balanceResult, setBalance] = useState(""); 9 | const [cryptoSymbol, setSymbol] = useState(""); 10 | const [isHidden, setHidden] = useState(true); 11 | 12 | async function handleClick() { 13 | // console.log(inputValue); 14 | const principal = Principal.fromText(inputValue); 15 | const balance = await token.balanceOf(principal); 16 | setBalance(balance.toLocaleString()); 17 | setSymbol(await token.getSymbol()); 18 | setHidden(false); 19 | } 20 | 21 | 22 | return ( 23 |
24 | 25 |

26 | setInput(e.target.value)} 32 | /> 33 |

34 |

35 | 41 |

42 | 43 |
44 | ); 45 | } 46 | 47 | export default Balance; 48 | -------------------------------------------------------------------------------- /src/declarations/token/index.js: -------------------------------------------------------------------------------- 1 | import { Actor, HttpAgent } from "@dfinity/agent"; 2 | 3 | // Imports and re-exports candid interface 4 | import { idlFactory } from './token.did.js'; 5 | export { idlFactory } from './token.did.js'; 6 | // CANISTER_ID is replaced by webpack based on node environment 7 | export const canisterId = process.env.TOKEN_CANISTER_ID; 8 | 9 | /** 10 | * 11 | * @param {string | import("@dfinity/principal").Principal} canisterId Canister ID of Agent 12 | * @param {{agentOptions?: import("@dfinity/agent").HttpAgentOptions; actorOptions?: import("@dfinity/agent").ActorConfig}} [options] 13 | * @return {import("@dfinity/agent").ActorSubclass} 14 | */ 15 | export const createActor = (canisterId, options) => { 16 | const agent = new HttpAgent({ ...options?.agentOptions }); 17 | 18 | // Fetch root key for certificate validation during development 19 | if(process.env.NODE_ENV !== "production") { 20 | agent.fetchRootKey().catch(err=>{ 21 | console.warn("Unable to fetch root key. Check to ensure that your local replica is running"); 22 | console.error(err); 23 | }); 24 | } 25 | 26 | // Creates an actor with using the candid interface and the HttpAgent 27 | return Actor.createActor(idlFactory, { 28 | agent, 29 | canisterId, 30 | ...options?.actorOptions, 31 | }); 32 | }; 33 | 34 | /** 35 | * A ready-to-use agent for the token canister 36 | * @type {import("@dfinity/agent").ActorSubclass} 37 | */ 38 | export const token = createActor(canisterId); 39 | -------------------------------------------------------------------------------- /src/declarations/token_assets/index.js: -------------------------------------------------------------------------------- 1 | import { Actor, HttpAgent } from "@dfinity/agent"; 2 | 3 | // Imports and re-exports candid interface 4 | import { idlFactory } from './token_assets.did.js'; 5 | export { idlFactory } from './token_assets.did.js'; 6 | // CANISTER_ID is replaced by webpack based on node environment 7 | export const canisterId = process.env.TOKEN_ASSETS_CANISTER_ID; 8 | 9 | /** 10 | * 11 | * @param {string | import("@dfinity/principal").Principal} canisterId Canister ID of Agent 12 | * @param {{agentOptions?: import("@dfinity/agent").HttpAgentOptions; actorOptions?: import("@dfinity/agent").ActorConfig}} [options] 13 | * @return {import("@dfinity/agent").ActorSubclass} 14 | */ 15 | export const createActor = (canisterId, options) => { 16 | const agent = new HttpAgent({ ...options?.agentOptions }); 17 | 18 | // Fetch root key for certificate validation during development 19 | if(process.env.NODE_ENV !== "production") { 20 | agent.fetchRootKey().catch(err=>{ 21 | console.warn("Unable to fetch root key. Check to ensure that your local replica is running"); 22 | console.error(err); 23 | }); 24 | } 25 | 26 | // Creates an actor with using the candid interface and the HttpAgent 27 | return Actor.createActor(idlFactory, { 28 | agent, 29 | canisterId, 30 | ...options?.actorOptions, 31 | }); 32 | }; 33 | 34 | /** 35 | * A ready-to-use agent for the token_assets canister 36 | * @type {import("@dfinity/agent").ActorSubclass} 37 | */ 38 | export const token_assets = createActor(canisterId); 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "faucet_assets", 3 | "version": "0.1.0", 4 | "description": "Internet Computer starter application", 5 | "keywords": [ 6 | "Internet Computer", 7 | "Motoko", 8 | "JavaScript", 9 | "Canister" 10 | ], 11 | "scripts": { 12 | "build": "webpack", 13 | "prebuild": "npm run copy:types", 14 | "start": "webpack serve --mode development --env development", 15 | "prestart": "npm run copy:types", 16 | "copy:types": "rsync -avr .dfx/$(echo ${DFX_NETWORK:-'**'})/canisters/** --exclude='assets/' --exclude='idl/' --exclude='*.wasm' --delete src/declarations" 17 | }, 18 | "devDependencies": { 19 | "@dfinity/agent": "0.10.4", 20 | "@dfinity/candid": "0.10.4", 21 | "@dfinity/principal": "0.10.4", 22 | "@material-ui/core": "4.6.1", 23 | "@material-ui/icons": "4.5.1", 24 | "assert": "2.0.0", 25 | "buffer": "6.0.3", 26 | "copy-webpack-plugin": "^10.2.4", 27 | "css-loader": "^6.5.1", 28 | "events": "3.3.0", 29 | "html-webpack-plugin": "5.5.0", 30 | "process": "0.11.10", 31 | "stream-browserify": "3.0.0", 32 | "style-loader": "^3.3.1", 33 | "terser-webpack-plugin": "5.3.1", 34 | "ts-loader": "^9.2.6", 35 | "typescript": "^4.5.5", 36 | "util": "0.12.4", 37 | "webpack": "5.69.1", 38 | "webpack-cli": "4.9.2", 39 | "webpack-dev-server": "^4.4.0" 40 | }, 41 | "browserslist": [ 42 | "last 2 chrome version", 43 | "last 2 firefox version", 44 | "last 2 safari version", 45 | "last 2 edge version" 46 | ], 47 | "dependencies": { 48 | "react": "^16.8.2", 49 | "react-dom": "^16.8.2", 50 | "react-scripts": "5.0.0", 51 | "@dfinity/auth-client": "^0.10.4", 52 | "@dfinity/authentication": "^0.10.4", 53 | "@dfinity/identity": "^0.10.4", 54 | "lit-html": "^1.4.1", 55 | "ts-loader": "^9.2.3", 56 | "typescript": "^4.3.5" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/token/main.mo: -------------------------------------------------------------------------------- 1 | import Principal "mo:base/Principal"; 2 | import HashMap "mo:base/HashMap"; 3 | import Debug "mo:base/Debug"; 4 | import Iter "mo:base/Iter"; 5 | 6 | actor Token { 7 | 8 | let owner : Principal = Principal.fromText(""); 9 | let totalSupply : Nat = 1000000000000000; 10 | let symbol : Text = "DANG"; 11 | 12 | private stable var balanceEntries : [(Principal, Nat)] = []; 13 | private var balances = HashMap.HashMap(1, Principal.equal, Principal.hash); 14 | if (balances.size() < 1) { 15 | balances.put(owner, totalSupply); 16 | }; 17 | 18 | public query func balanceOf(who: Principal) : async Nat { 19 | 20 | let balance : Nat = switch (balances.get(who)) { 21 | case null 0; 22 | case (?result) result; 23 | }; 24 | 25 | return balance; 26 | }; 27 | 28 | public query func getSymbol() : async Text { 29 | return symbol; 30 | }; 31 | 32 | public shared(msg) func payOut() : async Text { 33 | Debug.print(debug_show(msg.caller)); 34 | if (balances.get(msg.caller) == null) { 35 | let amount = 100; 36 | let result = await transfer(msg.caller, amount); 37 | return result; 38 | } else { 39 | return "Already Claimed" 40 | } 41 | }; 42 | 43 | public shared(msg) func transfer(to: Principal, amount: Nat) : async Text { 44 | let fromBalance = await balanceOf(msg.caller); 45 | if (fromBalance > amount) { 46 | let newFromBalance : Nat = fromBalance - amount; 47 | balances.put(msg.caller, newFromBalance); 48 | 49 | let toBalance = await balanceOf(to); 50 | let newToBalance = toBalance + amount; 51 | balances.put(to, newToBalance); 52 | 53 | return "Success"; 54 | } else { 55 | return "Insufficient Funds" 56 | } 57 | 58 | }; 59 | 60 | system func preupgrade() { 61 | balanceEntries := Iter.toArray(balances.entries()); 62 | }; 63 | 64 | system func postupgrade() { 65 | balances := HashMap.fromIter(balanceEntries.vals(), 1, Principal.equal, Principal.hash); 66 | if (balances.size() < 1) { 67 | balances.put(owner, totalSupply); 68 | }; 69 | }; 70 | 71 | }; 72 | 73 | 74 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Crypto Token 2 | #### React frontend and Motoko Backend 3 | #### Built while learning Motoko 4 | #### Screenshot 5 | ![image](https://github.com/arjuncvinod/Crypto-Token/assets/68469520/c5e7706d-9130-400f-8458-82bb062341a6) 6 | 7 | 8 | 1. Find out your principal id: 9 | 10 | ``` 11 | dfx identity get-principal 12 | ``` 13 | 14 | 2. Save it somewhere. 15 | 16 | e.g. My principal id is: gbdev-tyqsv-hnvqv-7mgz4-4kcfl-wbv6x-6khez-y56gq-uohqs-quomc-uqe 17 | 18 | 19 | 3. Format and store it in a command line variable: 20 | ``` 21 | OWNER_PUBLIC_KEY="principal \"$( \dfx identity get-principal )\"" 22 | ``` 23 | 24 | 4. Check that step 3 worked by printing it out: 25 | ``` 26 | echo $OWNER_PUBLIC_KEY 27 | ``` 28 | 29 | 5. Check the owner's balance: 30 | ``` 31 | dfx canister call token balanceOf "( $OWNER_PUBLIC_KEY )" 32 | ``` 33 | 34 | # Charge the Canister 35 | 36 | 37 | 1. Check canister ID: 38 | ``` 39 | dfx canister id token 40 | ``` 41 | 42 | 2. Save canister ID into a command line variable: 43 | ``` 44 | CANISTER_PUBLIC_KEY="principal \"$( \dfx canister id token )\"" 45 | ``` 46 | 47 | 3. Check canister ID has been successfully saved: 48 | ``` 49 | echo $CANISTER_PUBLIC_KEY 50 | ``` 51 | 52 | 4. Transfer half a billion tokens to the canister Principal ID: 53 | ``` 54 | dfx canister call token transfer "($CANISTER_PUBLIC_KEY, 500_000_000)" 55 | ``` 56 | 57 | # Deploy the Project to the Live IC Network 58 | 59 | 1. Create and deploy canisters: 60 | 61 | ``` 62 | dfx deploy --network ic 63 | ``` 64 | 65 | 2. Check the live canister ID: 66 | ``` 67 | dfx canister --network ic id token 68 | ``` 69 | 70 | 3. Save the live canister ID to a command line variable: 71 | ``` 72 | LIVE_CANISTER_KEY="principal \"$( \dfx canister --network ic id token )\"" 73 | ``` 74 | 75 | 4. Check that it worked: 76 | ``` 77 | echo $LIVE_CANISTER_KEY 78 | ``` 79 | 80 | 5. Transfer some tokens to the live canister: 81 | ``` 82 | dfx canister --network ic call token transfer "($LIVE_CANISTER_KEY, 50_000_000)" 83 | ``` 84 | 85 | 6. Get live canister front-end id: 86 | ``` 87 | dfx canister --network ic id token_assets 88 | ``` 89 | 7. Copy the id from step 6 and add .raw.ic0.app to the end to form a URL. 90 | e.g. zdv65-7qaaa-aaaai-qibdq-cai.raw.ic0.app 91 | -------------------------------------------------------------------------------- /src/token_assets/src/components/Transfer.jsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { Principal } from '@dfinity/principal'; 3 | import { canisterId, createActor } from "../../../declarations/token"; 4 | import { AuthClient } from "@dfinity/auth-client"; 5 | 6 | function Transfer() { 7 | 8 | const [recipientId, setId] = useState(""); 9 | const [amount, setAmount] = useState(""); 10 | const [isHidden, setHidden] = useState(true); 11 | const [feedback, setFeedback] = useState(""); 12 | const [isDisabled, setDisable] = useState(false); 13 | 14 | async function handleClick() { 15 | setHidden(true); 16 | setDisable(true); 17 | const recipient = Principal.fromText(recipientId); 18 | const amountToTransfer = Number(amount); 19 | 20 | const authClient = await AuthClient.create(); 21 | const identity = await authClient.getIdentity(); 22 | const authenticatedCanister = createActor(canisterId, { 23 | agentOptions: { 24 | identity, 25 | }, 26 | }); 27 | 28 | const result = await authenticatedCanister.transfer(recipient, amountToTransfer); 29 | setFeedback(result); 30 | setHidden(false); 31 | setDisable(false); 32 | } 33 | 34 | return ( 35 |
36 |
37 |
38 | To Account: 39 |
    40 |
  • 41 | setId(e.target.value)} 46 | /> 47 |
  • 48 |
49 |
50 |
51 | Amount: 52 |
    53 |
  • 54 | setAmount(e.target.value)} 59 | /> 60 |
  • 61 |
62 |
63 |

64 | 71 |

72 | 73 |
74 |
75 | ); 76 | } 77 | 78 | export default Transfer; 79 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const webpack = require("webpack"); 3 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 4 | const TerserPlugin = require("terser-webpack-plugin"); 5 | const CopyPlugin = require("copy-webpack-plugin"); 6 | 7 | function initCanisterEnv() { 8 | let localCanisters, prodCanisters; 9 | try { 10 | localCanisters = require(path.resolve( 11 | ".dfx", 12 | "local", 13 | "canister_ids.json" 14 | )); 15 | } catch (error) { 16 | console.log("No local canister_ids.json found. Continuing production"); 17 | } 18 | try { 19 | prodCanisters = require(path.resolve("canister_ids.json")); 20 | } catch (error) { 21 | console.log("No production canister_ids.json found. Continuing with local"); 22 | } 23 | 24 | const network = 25 | process.env.DFX_NETWORK || 26 | (process.env.NODE_ENV === "production" ? "ic" : "local"); 27 | 28 | const canisterConfig = network === "local" ? localCanisters : prodCanisters; 29 | 30 | return Object.entries(canisterConfig).reduce((prev, current) => { 31 | const [canisterName, canisterDetails] = current; 32 | prev[canisterName.toUpperCase() + "_CANISTER_ID"] = 33 | canisterDetails[network]; 34 | return prev; 35 | }, {}); 36 | } 37 | const canisterEnvVariables = initCanisterEnv(); 38 | 39 | const isDevelopment = process.env.NODE_ENV !== "production"; 40 | 41 | const frontendDirectory = "token_assets"; 42 | 43 | const asset_entry = path.join("src", frontendDirectory, "src", "index.html"); 44 | 45 | module.exports = { 46 | target: "web", 47 | mode: isDevelopment ? "development" : "production", 48 | entry: { 49 | // The frontend.entrypoint points to the HTML file for this build, so we need 50 | // to replace the extension to `.js`. 51 | index: path.join(__dirname, asset_entry).replace(/\.html$/, ".jsx"), 52 | }, 53 | devtool: isDevelopment ? "source-map" : false, 54 | optimization: { 55 | minimize: !isDevelopment, 56 | minimizer: [new TerserPlugin()], 57 | }, 58 | resolve: { 59 | extensions: [".js", ".ts", ".jsx", ".tsx"], 60 | fallback: { 61 | assert: require.resolve("assert/"), 62 | buffer: require.resolve("buffer/"), 63 | events: require.resolve("events/"), 64 | stream: require.resolve("stream-browserify/"), 65 | util: require.resolve("util/"), 66 | }, 67 | }, 68 | output: { 69 | filename: "index.js", 70 | path: path.join(__dirname, "dist", frontendDirectory), 71 | }, 72 | 73 | // Depending in the language or framework you are using for 74 | // front-end development, add module loaders to the default 75 | // webpack configuration. For example, if you are using React 76 | // modules and CSS as described in the "Adding a stylesheet" 77 | // tutorial, uncomment the following lines: 78 | module: { 79 | rules: [ 80 | { test: /\.(ts|tsx|jsx)$/, loader: "ts-loader" }, 81 | { test: /\.css$/, use: ['style-loader','css-loader'] } 82 | ] 83 | }, 84 | plugins: [ 85 | new HtmlWebpackPlugin({ 86 | template: path.join(__dirname, asset_entry), 87 | cache: false, 88 | }), 89 | 90 | new webpack.EnvironmentPlugin({ 91 | NODE_ENV: "development", 92 | ...canisterEnvVariables, 93 | }), 94 | new webpack.ProvidePlugin({ 95 | Buffer: [require.resolve("buffer/"), "Buffer"], 96 | process: require.resolve("process/browser"), 97 | }), 98 | ], 99 | // proxy /api to port 8000 during development 100 | devServer: { 101 | proxy: { 102 | "/api": { 103 | target: "http://localhost:8000", 104 | changeOrigin: true, 105 | pathRewrite: { 106 | "^/api": "/api", 107 | }, 108 | }, 109 | }, 110 | hot: true, 111 | watchFiles: [path.resolve(__dirname, "src", frontendDirectory)], 112 | liveReload: true, 113 | }, 114 | }; 115 | -------------------------------------------------------------------------------- /src/token_assets/assets/main.css: -------------------------------------------------------------------------------- 1 | html { 2 | background: #a5a4ce; 3 | font-family: System, monospace; 4 | font-size: 10pt; 5 | } 6 | 7 | body { 8 | padding: 0; 9 | margin: 0; 10 | } 11 | 12 | span:after { 13 | content: " "; 14 | display: inline-block; 15 | width: 2%; 16 | } 17 | 18 | fieldset { 19 | float: left; 20 | padding-right: 18px; 21 | } 22 | 23 | #logo { 24 | font-family: "Times"; 25 | font-size: 20pt; 26 | } 27 | 28 | .window { 29 | position: relative; 30 | cursor: default; 31 | margin: 2em auto; 32 | width: 80%; 33 | background: #3465a4; 34 | color: white; 35 | border: 6px double white; 36 | padding: 1em; 37 | box-shadow: 0 0 0 3px #3465a4, 1em 1em 3px 0 rgba(0, 0, 0, 0.5); 38 | max-width: 640px; 39 | } 40 | 41 | .window.white { 42 | background: silver; 43 | color: black; 44 | border-color: white; 45 | box-shadow: 0 0 0 3px silver, 1em 1em 3px 0 rgba(0, 0, 0, 0.5); 46 | } 47 | 48 | .window.half-width { 49 | width: 50%; 50 | } 51 | 52 | .window h1 { 53 | text-align: center; 54 | } 55 | 56 | .window.blue p { 57 | color: white; 58 | text-shadow: 0 0 2px white; 59 | } 60 | 61 | button { 62 | margin: 0; 63 | padding: 0; 64 | border: none; 65 | cursor: pointer; 66 | } 67 | 68 | button, 69 | .button, 70 | .button:link { 71 | display: inline-block; 72 | font-weight: bolder; 73 | color: white; 74 | font-family: inherit; 75 | font-size: inherit; 76 | background: green; 77 | padding: 0 1em; 78 | box-shadow: 0.5em 0.5em 3px rgba(0, 0, 0, 0.5); 79 | position: relative; 80 | transition: 0.2s all ease-in; 81 | border: 1px outset green; 82 | } 83 | 84 | button.full-width, 85 | .button.full-width { 86 | display: block; 87 | text-align: center; 88 | } 89 | 90 | button:before, 91 | .button:before { 92 | top: 0; 93 | left: 0; 94 | right: 0; 95 | bottom: 0; 96 | content: ""; 97 | position: absolute; 98 | /*background: rgba(255,255,0,.5); /* DEBUG CLICK AREA */ 99 | } 100 | 101 | button:hover, 102 | .button:active, 103 | .button:focus, 104 | .button:hover { 105 | transform: translate3d(0.25em, 0.25em, 10em); 106 | box-shadow: 0 0 0 rgba(0, 0, 0, 0.5); 107 | background: limegreen; 108 | } 109 | 110 | button:hover:before, 111 | .button:hover:before, 112 | button:focus:before, 113 | .button:focus:before { 114 | top: -1em; 115 | left: -1em; 116 | } 117 | 118 | .button.pressed { 119 | box-shadow: none; 120 | left: 0.25em; 121 | top: 0.25em; 122 | margin-right: 0.25em; 123 | background: gray; 124 | border: 1px outset #707070; 125 | } 126 | 127 | button:disabled { 128 | transform: translate3d(0.25em, 0.25em, 10em); 129 | box-shadow: 0 0 0 rgba(0, 0, 0, 0.5); 130 | background: gray; 131 | border: 1px outset #707070; 132 | } 133 | 134 | button:first-letter, 135 | .button:first-letter { 136 | color: yellow; 137 | } 138 | 139 | button#btn-transfer { 140 | margin-top: 20px; 141 | } 142 | 143 | input, 144 | textarea { 145 | background: blue; 146 | color: aqua; 147 | width: 100%; 148 | max-width: 100%; 149 | font-size: 12pt; 150 | } 151 | input:disabled { 152 | background: #505070; 153 | color: #d0d0d0; 154 | border: 2px solid #505070; 155 | } 156 | 157 | .window > textarea { 158 | width: 100%; 159 | border: none; 160 | } 161 | 162 | ul { 163 | margin: 0; 164 | padding: 0; 165 | } 166 | 167 | li { 168 | margin: 0; 169 | padding: 0; 170 | list-style: none; 171 | } 172 | 173 | .trade-buttons { 174 | text-align: center; 175 | margin-top: 20px; 176 | } 177 | 178 | div .transfer { 179 | display: table; 180 | margin: auto; 181 | } 182 | -------------------------------------------------------------------------------- /src/declarations/token_assets/token_assets.did.d.ts: -------------------------------------------------------------------------------- 1 | import type { Principal } from '@dfinity/principal'; 2 | export type BatchId = bigint; 3 | export type BatchOperationKind = { 'CreateAsset' : CreateAssetArguments } | 4 | { 'UnsetAssetContent' : UnsetAssetContentArguments } | 5 | { 'DeleteAsset' : DeleteAssetArguments } | 6 | { 'SetAssetContent' : SetAssetContentArguments } | 7 | { 'Clear' : ClearArguments }; 8 | export type ChunkId = bigint; 9 | export type ClearArguments = {}; 10 | export interface CreateAssetArguments { 'key' : Key, 'content_type' : string } 11 | export interface DeleteAssetArguments { 'key' : Key } 12 | export type HeaderField = [string, string]; 13 | export interface HttpRequest { 14 | 'url' : string, 15 | 'method' : string, 16 | 'body' : Array, 17 | 'headers' : Array, 18 | } 19 | export interface HttpResponse { 20 | 'body' : Array, 21 | 'headers' : Array, 22 | 'streaming_strategy' : [] | [StreamingStrategy], 23 | 'status_code' : number, 24 | } 25 | export type Key = string; 26 | export interface SetAssetContentArguments { 27 | 'key' : Key, 28 | 'sha256' : [] | [Array], 29 | 'chunk_ids' : Array, 30 | 'content_encoding' : string, 31 | } 32 | export interface StreamingCallbackHttpResponse { 33 | 'token' : [] | [StreamingCallbackToken], 34 | 'body' : Array, 35 | } 36 | export interface StreamingCallbackToken { 37 | 'key' : Key, 38 | 'sha256' : [] | [Array], 39 | 'index' : bigint, 40 | 'content_encoding' : string, 41 | } 42 | export type StreamingStrategy = { 43 | 'Callback' : { 44 | 'token' : StreamingCallbackToken, 45 | 'callback' : [Principal, string], 46 | } 47 | }; 48 | export type Time = bigint; 49 | export interface UnsetAssetContentArguments { 50 | 'key' : Key, 51 | 'content_encoding' : string, 52 | } 53 | export interface _SERVICE { 54 | 'authorize' : (arg_0: Principal) => Promise, 55 | 'clear' : (arg_0: ClearArguments) => Promise, 56 | 'commit_batch' : ( 57 | arg_0: { 'batch_id' : BatchId, 'operations' : Array }, 58 | ) => Promise, 59 | 'create_asset' : (arg_0: CreateAssetArguments) => Promise, 60 | 'create_batch' : (arg_0: {}) => Promise<{ 'batch_id' : BatchId }>, 61 | 'create_chunk' : ( 62 | arg_0: { 'content' : Array, 'batch_id' : BatchId }, 63 | ) => Promise<{ 'chunk_id' : ChunkId }>, 64 | 'delete_asset' : (arg_0: DeleteAssetArguments) => Promise, 65 | 'get' : ( 66 | arg_0: { 'key' : Key, 'accept_encodings' : Array }, 67 | ) => Promise< 68 | { 69 | 'content' : Array, 70 | 'sha256' : [] | [Array], 71 | 'content_type' : string, 72 | 'content_encoding' : string, 73 | 'total_length' : bigint, 74 | } 75 | >, 76 | 'get_chunk' : ( 77 | arg_0: { 78 | 'key' : Key, 79 | 'sha256' : [] | [Array], 80 | 'index' : bigint, 81 | 'content_encoding' : string, 82 | }, 83 | ) => Promise<{ 'content' : Array }>, 84 | 'http_request' : (arg_0: HttpRequest) => Promise, 85 | 'http_request_streaming_callback' : ( 86 | arg_0: StreamingCallbackToken, 87 | ) => Promise<[] | [StreamingCallbackHttpResponse]>, 88 | 'list' : (arg_0: {}) => Promise< 89 | Array< 90 | { 91 | 'key' : Key, 92 | 'encodings' : Array< 93 | { 94 | 'modified' : Time, 95 | 'sha256' : [] | [Array], 96 | 'length' : bigint, 97 | 'content_encoding' : string, 98 | } 99 | >, 100 | 'content_type' : string, 101 | } 102 | > 103 | >, 104 | 'set_asset_content' : (arg_0: SetAssetContentArguments) => Promise, 105 | 'store' : ( 106 | arg_0: { 107 | 'key' : Key, 108 | 'content' : Array, 109 | 'sha256' : [] | [Array], 110 | 'content_type' : string, 111 | 'content_encoding' : string, 112 | }, 113 | ) => Promise, 114 | 'unset_asset_content' : (arg_0: UnsetAssetContentArguments) => Promise< 115 | undefined 116 | >, 117 | } 118 | -------------------------------------------------------------------------------- /src/declarations/token_assets/assetstorage.did: -------------------------------------------------------------------------------- 1 | type BatchId = nat; 2 | type ChunkId = nat; 3 | type Key = text; 4 | type Time = int; 5 | 6 | type CreateAssetArguments = record { 7 | key: Key; 8 | content_type: text; 9 | }; 10 | 11 | // Add or change content for an asset, by content encoding 12 | type SetAssetContentArguments = record { 13 | key: Key; 14 | content_encoding: text; 15 | chunk_ids: vec ChunkId; 16 | sha256: opt blob; 17 | }; 18 | 19 | // Remove content for an asset, by content encoding 20 | type UnsetAssetContentArguments = record { 21 | key: Key; 22 | content_encoding: text; 23 | }; 24 | 25 | // Delete an asset 26 | type DeleteAssetArguments = record { 27 | key: Key; 28 | }; 29 | 30 | // Reset everything 31 | type ClearArguments = record {}; 32 | 33 | type BatchOperationKind = variant { 34 | CreateAsset: CreateAssetArguments; 35 | SetAssetContent: SetAssetContentArguments; 36 | 37 | UnsetAssetContent: UnsetAssetContentArguments; 38 | DeleteAsset: DeleteAssetArguments; 39 | 40 | Clear: ClearArguments; 41 | }; 42 | 43 | type HeaderField = record { text; text; }; 44 | 45 | type HttpRequest = record { 46 | method: text; 47 | url: text; 48 | headers: vec HeaderField; 49 | body: blob; 50 | }; 51 | 52 | type HttpResponse = record { 53 | status_code: nat16; 54 | headers: vec HeaderField; 55 | body: blob; 56 | streaming_strategy: opt StreamingStrategy; 57 | }; 58 | 59 | type StreamingCallbackHttpResponse = record { 60 | body: blob; 61 | token: opt StreamingCallbackToken; 62 | }; 63 | 64 | type StreamingCallbackToken = record { 65 | key: Key; 66 | content_encoding: text; 67 | index: nat; 68 | sha256: opt blob; 69 | }; 70 | 71 | type StreamingStrategy = variant { 72 | Callback: record { 73 | callback: func (StreamingCallbackToken) -> (opt StreamingCallbackHttpResponse) query; 74 | token: StreamingCallbackToken; 75 | }; 76 | }; 77 | 78 | service: { 79 | 80 | get: (record { 81 | key: Key; 82 | accept_encodings: vec text; 83 | }) -> (record { 84 | content: blob; // may be the entirety of the content, or just chunk index 0 85 | content_type: text; 86 | content_encoding: text; 87 | sha256: opt blob; // sha256 of entire asset encoding, calculated by dfx and passed in SetAssetContentArguments 88 | total_length: nat; // all chunks except last have size == content.size() 89 | }) query; 90 | 91 | // if get() returned chunks > 1, call this to retrieve them. 92 | // chunks may or may not be split up at the same boundaries as presented to create_chunk(). 93 | get_chunk: (record { 94 | key: Key; 95 | content_encoding: text; 96 | index: nat; 97 | sha256: opt blob; // sha256 of entire asset encoding, calculated by dfx and passed in SetAssetContentArguments 98 | }) -> (record { content: blob }) query; 99 | 100 | list : (record {}) -> (vec record { 101 | key: Key; 102 | content_type: text; 103 | encodings: vec record { 104 | content_encoding: text; 105 | sha256: opt blob; // sha256 of entire asset encoding, calculated by dfx and passed in SetAssetContentArguments 106 | length: nat; // Size of this encoding's blob. Calculated when uploading assets. 107 | modified: Time; 108 | }; 109 | }) query; 110 | 111 | create_batch : (record {}) -> (record { batch_id: BatchId }); 112 | 113 | create_chunk: (record { batch_id: BatchId; content: blob }) -> (record { chunk_id: ChunkId }); 114 | 115 | // Perform all operations successfully, or reject 116 | commit_batch: (record { batch_id: BatchId; operations: vec BatchOperationKind }) -> (); 117 | 118 | create_asset: (CreateAssetArguments) -> (); 119 | set_asset_content: (SetAssetContentArguments) -> (); 120 | unset_asset_content: (UnsetAssetContentArguments) -> (); 121 | 122 | delete_asset: (DeleteAssetArguments) -> (); 123 | 124 | clear: (ClearArguments) -> (); 125 | 126 | // Single call to create an asset with content for a single content encoding that 127 | // fits within the message ingress limit. 128 | store: (record { 129 | key: Key; 130 | content_type: text; 131 | content_encoding: text; 132 | content: blob; 133 | sha256: opt blob 134 | }) -> (); 135 | 136 | http_request: (request: HttpRequest) -> (HttpResponse) query; 137 | http_request_streaming_callback: (token: StreamingCallbackToken) -> (opt StreamingCallbackHttpResponse) query; 138 | 139 | authorize: (principal) -> (); 140 | } 141 | -------------------------------------------------------------------------------- /src/declarations/token_assets/token_assets.did: -------------------------------------------------------------------------------- 1 | type BatchId = nat; 2 | type ChunkId = nat; 3 | type Key = text; 4 | type Time = int; 5 | 6 | type CreateAssetArguments = record { 7 | key: Key; 8 | content_type: text; 9 | }; 10 | 11 | // Add or change content for an asset, by content encoding 12 | type SetAssetContentArguments = record { 13 | key: Key; 14 | content_encoding: text; 15 | chunk_ids: vec ChunkId; 16 | sha256: opt blob; 17 | }; 18 | 19 | // Remove content for an asset, by content encoding 20 | type UnsetAssetContentArguments = record { 21 | key: Key; 22 | content_encoding: text; 23 | }; 24 | 25 | // Delete an asset 26 | type DeleteAssetArguments = record { 27 | key: Key; 28 | }; 29 | 30 | // Reset everything 31 | type ClearArguments = record {}; 32 | 33 | type BatchOperationKind = variant { 34 | CreateAsset: CreateAssetArguments; 35 | SetAssetContent: SetAssetContentArguments; 36 | 37 | UnsetAssetContent: UnsetAssetContentArguments; 38 | DeleteAsset: DeleteAssetArguments; 39 | 40 | Clear: ClearArguments; 41 | }; 42 | 43 | type HeaderField = record { text; text; }; 44 | 45 | type HttpRequest = record { 46 | method: text; 47 | url: text; 48 | headers: vec HeaderField; 49 | body: blob; 50 | }; 51 | 52 | type HttpResponse = record { 53 | status_code: nat16; 54 | headers: vec HeaderField; 55 | body: blob; 56 | streaming_strategy: opt StreamingStrategy; 57 | }; 58 | 59 | type StreamingCallbackHttpResponse = record { 60 | body: blob; 61 | token: opt StreamingCallbackToken; 62 | }; 63 | 64 | type StreamingCallbackToken = record { 65 | key: Key; 66 | content_encoding: text; 67 | index: nat; 68 | sha256: opt blob; 69 | }; 70 | 71 | type StreamingStrategy = variant { 72 | Callback: record { 73 | callback: func (StreamingCallbackToken) -> (opt StreamingCallbackHttpResponse) query; 74 | token: StreamingCallbackToken; 75 | }; 76 | }; 77 | 78 | service: { 79 | 80 | get: (record { 81 | key: Key; 82 | accept_encodings: vec text; 83 | }) -> (record { 84 | content: blob; // may be the entirety of the content, or just chunk index 0 85 | content_type: text; 86 | content_encoding: text; 87 | sha256: opt blob; // sha256 of entire asset encoding, calculated by dfx and passed in SetAssetContentArguments 88 | total_length: nat; // all chunks except last have size == content.size() 89 | }) query; 90 | 91 | // if get() returned chunks > 1, call this to retrieve them. 92 | // chunks may or may not be split up at the same boundaries as presented to create_chunk(). 93 | get_chunk: (record { 94 | key: Key; 95 | content_encoding: text; 96 | index: nat; 97 | sha256: opt blob; // sha256 of entire asset encoding, calculated by dfx and passed in SetAssetContentArguments 98 | }) -> (record { content: blob }) query; 99 | 100 | list : (record {}) -> (vec record { 101 | key: Key; 102 | content_type: text; 103 | encodings: vec record { 104 | content_encoding: text; 105 | sha256: opt blob; // sha256 of entire asset encoding, calculated by dfx and passed in SetAssetContentArguments 106 | length: nat; // Size of this encoding's blob. Calculated when uploading assets. 107 | modified: Time; 108 | }; 109 | }) query; 110 | 111 | create_batch : (record {}) -> (record { batch_id: BatchId }); 112 | 113 | create_chunk: (record { batch_id: BatchId; content: blob }) -> (record { chunk_id: ChunkId }); 114 | 115 | // Perform all operations successfully, or reject 116 | commit_batch: (record { batch_id: BatchId; operations: vec BatchOperationKind }) -> (); 117 | 118 | create_asset: (CreateAssetArguments) -> (); 119 | set_asset_content: (SetAssetContentArguments) -> (); 120 | unset_asset_content: (UnsetAssetContentArguments) -> (); 121 | 122 | delete_asset: (DeleteAssetArguments) -> (); 123 | 124 | clear: (ClearArguments) -> (); 125 | 126 | // Single call to create an asset with content for a single content encoding that 127 | // fits within the message ingress limit. 128 | store: (record { 129 | key: Key; 130 | content_type: text; 131 | content_encoding: text; 132 | content: blob; 133 | sha256: opt blob 134 | }) -> (); 135 | 136 | http_request: (request: HttpRequest) -> (HttpResponse) query; 137 | http_request_streaming_callback: (token: StreamingCallbackToken) -> (opt StreamingCallbackHttpResponse) query; 138 | 139 | authorize: (principal) -> (); 140 | } 141 | -------------------------------------------------------------------------------- /src/declarations/token_assets/token_assets.did.js: -------------------------------------------------------------------------------- 1 | export const idlFactory = ({ IDL }) => { 2 | const ClearArguments = IDL.Record({}); 3 | const BatchId = IDL.Nat; 4 | const Key = IDL.Text; 5 | const CreateAssetArguments = IDL.Record({ 6 | 'key' : Key, 7 | 'content_type' : IDL.Text, 8 | }); 9 | const UnsetAssetContentArguments = IDL.Record({ 10 | 'key' : Key, 11 | 'content_encoding' : IDL.Text, 12 | }); 13 | const DeleteAssetArguments = IDL.Record({ 'key' : Key }); 14 | const ChunkId = IDL.Nat; 15 | const SetAssetContentArguments = IDL.Record({ 16 | 'key' : Key, 17 | 'sha256' : IDL.Opt(IDL.Vec(IDL.Nat8)), 18 | 'chunk_ids' : IDL.Vec(ChunkId), 19 | 'content_encoding' : IDL.Text, 20 | }); 21 | const BatchOperationKind = IDL.Variant({ 22 | 'CreateAsset' : CreateAssetArguments, 23 | 'UnsetAssetContent' : UnsetAssetContentArguments, 24 | 'DeleteAsset' : DeleteAssetArguments, 25 | 'SetAssetContent' : SetAssetContentArguments, 26 | 'Clear' : ClearArguments, 27 | }); 28 | const HeaderField = IDL.Tuple(IDL.Text, IDL.Text); 29 | const HttpRequest = IDL.Record({ 30 | 'url' : IDL.Text, 31 | 'method' : IDL.Text, 32 | 'body' : IDL.Vec(IDL.Nat8), 33 | 'headers' : IDL.Vec(HeaderField), 34 | }); 35 | const StreamingCallbackToken = IDL.Record({ 36 | 'key' : Key, 37 | 'sha256' : IDL.Opt(IDL.Vec(IDL.Nat8)), 38 | 'index' : IDL.Nat, 39 | 'content_encoding' : IDL.Text, 40 | }); 41 | const StreamingCallbackHttpResponse = IDL.Record({ 42 | 'token' : IDL.Opt(StreamingCallbackToken), 43 | 'body' : IDL.Vec(IDL.Nat8), 44 | }); 45 | const StreamingStrategy = IDL.Variant({ 46 | 'Callback' : IDL.Record({ 47 | 'token' : StreamingCallbackToken, 48 | 'callback' : IDL.Func( 49 | [StreamingCallbackToken], 50 | [IDL.Opt(StreamingCallbackHttpResponse)], 51 | ['query'], 52 | ), 53 | }), 54 | }); 55 | const HttpResponse = IDL.Record({ 56 | 'body' : IDL.Vec(IDL.Nat8), 57 | 'headers' : IDL.Vec(HeaderField), 58 | 'streaming_strategy' : IDL.Opt(StreamingStrategy), 59 | 'status_code' : IDL.Nat16, 60 | }); 61 | const Time = IDL.Int; 62 | return IDL.Service({ 63 | 'authorize' : IDL.Func([IDL.Principal], [], []), 64 | 'clear' : IDL.Func([ClearArguments], [], []), 65 | 'commit_batch' : IDL.Func( 66 | [ 67 | IDL.Record({ 68 | 'batch_id' : BatchId, 69 | 'operations' : IDL.Vec(BatchOperationKind), 70 | }), 71 | ], 72 | [], 73 | [], 74 | ), 75 | 'create_asset' : IDL.Func([CreateAssetArguments], [], []), 76 | 'create_batch' : IDL.Func( 77 | [IDL.Record({})], 78 | [IDL.Record({ 'batch_id' : BatchId })], 79 | [], 80 | ), 81 | 'create_chunk' : IDL.Func( 82 | [IDL.Record({ 'content' : IDL.Vec(IDL.Nat8), 'batch_id' : BatchId })], 83 | [IDL.Record({ 'chunk_id' : ChunkId })], 84 | [], 85 | ), 86 | 'delete_asset' : IDL.Func([DeleteAssetArguments], [], []), 87 | 'get' : IDL.Func( 88 | [IDL.Record({ 'key' : Key, 'accept_encodings' : IDL.Vec(IDL.Text) })], 89 | [ 90 | IDL.Record({ 91 | 'content' : IDL.Vec(IDL.Nat8), 92 | 'sha256' : IDL.Opt(IDL.Vec(IDL.Nat8)), 93 | 'content_type' : IDL.Text, 94 | 'content_encoding' : IDL.Text, 95 | 'total_length' : IDL.Nat, 96 | }), 97 | ], 98 | ['query'], 99 | ), 100 | 'get_chunk' : IDL.Func( 101 | [ 102 | IDL.Record({ 103 | 'key' : Key, 104 | 'sha256' : IDL.Opt(IDL.Vec(IDL.Nat8)), 105 | 'index' : IDL.Nat, 106 | 'content_encoding' : IDL.Text, 107 | }), 108 | ], 109 | [IDL.Record({ 'content' : IDL.Vec(IDL.Nat8) })], 110 | ['query'], 111 | ), 112 | 'http_request' : IDL.Func([HttpRequest], [HttpResponse], ['query']), 113 | 'http_request_streaming_callback' : IDL.Func( 114 | [StreamingCallbackToken], 115 | [IDL.Opt(StreamingCallbackHttpResponse)], 116 | ['query'], 117 | ), 118 | 'list' : IDL.Func( 119 | [IDL.Record({})], 120 | [ 121 | IDL.Vec( 122 | IDL.Record({ 123 | 'key' : Key, 124 | 'encodings' : IDL.Vec( 125 | IDL.Record({ 126 | 'modified' : Time, 127 | 'sha256' : IDL.Opt(IDL.Vec(IDL.Nat8)), 128 | 'length' : IDL.Nat, 129 | 'content_encoding' : IDL.Text, 130 | }) 131 | ), 132 | 'content_type' : IDL.Text, 133 | }) 134 | ), 135 | ], 136 | ['query'], 137 | ), 138 | 'set_asset_content' : IDL.Func([SetAssetContentArguments], [], []), 139 | 'store' : IDL.Func( 140 | [ 141 | IDL.Record({ 142 | 'key' : Key, 143 | 'content' : IDL.Vec(IDL.Nat8), 144 | 'sha256' : IDL.Opt(IDL.Vec(IDL.Nat8)), 145 | 'content_type' : IDL.Text, 146 | 'content_encoding' : IDL.Text, 147 | }), 148 | ], 149 | [], 150 | [], 151 | ), 152 | 'unset_asset_content' : IDL.Func([UnsetAssetContentArguments], [], []), 153 | }); 154 | }; 155 | export const init = ({ IDL }) => { return []; }; 156 | --------------------------------------------------------------------------------