diff --git a/Cargo.toml b/Cargo.toml index 239a76c..f14c634 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ members = [ "uniswap-v2/contracts/**", "farming/contracts/**", + "nameservice/contracts/**", # "flipper/flipper/contracts/*" <- uncomment this if you want to use flipper "psp34_shiden/contracts/shiden34", ] diff --git a/nameservice/.gitignore b/nameservice/.gitignore new file mode 100644 index 0000000..5230559 --- /dev/null +++ b/nameservice/.gitignore @@ -0,0 +1,230 @@ + +# Created by https://www.toptal.com/developers/gitignore/api/node,macos,visualstudiocode +# Edit at https://www.toptal.com/developers/gitignore?templates=node,macos,visualstudiocode + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +### Node Patch ### +# Serverless Webpack directories +.webpack/ + +# Optional stylelint cache + +# SvelteKit build / generate output +.svelte-kit + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +!.vscode/*.code-snippets + +# Local History for Visual Studio Code +.history/ + +# Built Visual Studio Code Extensions +*.vsix + +### VisualStudioCode Patch ### +# Ignore all local history of files +.history +.ionide + +# Support for Project snippet scope +.vscode/*.code-snippets + +# Ignore code-workspaces +*.code-workspace + +### Rust ### +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb + + +# End of https://www.toptal.com/developers/gitignore/api/node,macos,visualstudiocode + +*-debug.log +*-error.log +/.nyc_output +/dist +/lib +/package-lock.json +/tmp +node_modules +oclif.manifest.json diff --git a/nameservice/README.md b/nameservice/README.md new file mode 100644 index 0000000..18565ed --- /dev/null +++ b/nameservice/README.md @@ -0,0 +1,16 @@ +# Name Service example +This example is intended to create a domain name service with wasm. + +#### Custom trait implements +- fn createSubdomain(&mut self, subdomain: vec, domain: vec) -> Result<()>; +- fn transferSubdomain(&mut self, subdomain: vec, domain: vec, newOwner: AccountId) -> Result<()>; + +- [x] unit test is implemented +- [ ] deployed on Shibuya +- [ ] deployed on Shiden + +## Deployment on Shibuya +> soon + +## Deployment on Shiden +> soon diff --git a/nameservice/contracts/nameservice/Cargo.toml b/nameservice/contracts/nameservice/Cargo.toml new file mode 100644 index 0000000..1403e47 --- /dev/null +++ b/nameservice/contracts/nameservice/Cargo.toml @@ -0,0 +1,37 @@ +[package] +name = "nameservice" +version = "0.1.0" +authors = ["niklabh"] +edition = "2021" + +[dependencies] +ink_primitives = { version = "~3.3.0", default-features = false } +ink_metadata = { version = "~3.3.0", default-features = false, features = ["derive"], optional = true } +ink_env = { version = "~3.3.0", default-features = false } +ink_storage = { version = "~3.3.0", default-features = false } +ink_lang = { version = "~3.3.0", default-features = false } +ink_prelude = { version = "~3.3.0", default-features = false } +ink_engine = { version = "~3.3.0", default-features = false, optional = true } + +scale = { package = "parity-scale-codec", version = "3", default-features = false, features = ["derive"] } +scale-info = { version = "2", default-features = false, features = ["derive"], optional = true } + +[lib] +name = "nameservice" +path = "lib.rs" +crate-type = [ + # Used for normal contract Wasm blobs. + "cdylib", +] + +[features] +default = ["std"] +std = [ + "ink_metadata/std", + "ink_env/std", + "ink_storage/std", + "ink_primitives/std", + "scale/std", + "scale-info/std", +] +ink-as-dependency = [] diff --git a/nameservice/contracts/nameservice/lib.rs b/nameservice/contracts/nameservice/lib.rs new file mode 100644 index 0000000..6fd1d5b --- /dev/null +++ b/nameservice/contracts/nameservice/lib.rs @@ -0,0 +1,127 @@ +#![cfg_attr(not(feature = "std"), no_std)] + +use ink_lang as ink; + +#[ink::contract] +mod ensubdomainfactory { + #[ink(storage)] + pub struct EnsSubdomainFactory { + owner: AccountId, + locked: bool, + } + #[ink(event)] + pub struct SubdomainCreated { + #[ink(topic)] //-> indexed + creator: AccountId, + owner: AccountId, + subdomain: Vec, + domain: Vec, + } + #[ink(event)] + pub struct OwnershipTransferred { + #[ink(topic)] //-> indexed + previous_owner: AccountId, + new_owner: AccountId, + } + #[ink(event)] + pub struct RegistryUpdated { + #[ink(topic)] //-> indexed + previous_registry: AccountId, + new_registry: AccountId, + } + #[ink(event)] + pub struct ResolverUpdated { + #[ink(topic)] //-> indexed + previous_resolver: AccountId, + new_resolver: AccountId, + } + #[ink(event)] + pub struct DomainTransfersLocked { + #[ink(topic)] //-> indexed + caller: AccountId, + locked: bool, + } + + impl EnsSubdomainFactory { + #[ink(constructor)] + pub fn new() -> Self { + let caller = Self::env().caller(); + Self { + owner: caller, + locked: false, + } + } + #[ink(message)] + pub fn set_subdomain_owner(&mut self, subdomain: Vec, domain: Vec, owner: AccountId) { + assert_eq!(self.env().caller(), self.owner); + assert_eq!(self.locked, false); + let subdomain_hash = self.namehash(subdomain, domain); + //call setOwner on resolver + self.env().emit_event(SubdomainCreated { + creator: self.env().caller(), + owner: owner, + subdomain: subdomain, + domain: domain, + }); + } + #[ink(message)] + pub fn create_subdomain(&mut self, subdomain: Vec, domain: Vec) { + let caller = Self::env().caller(); + assert_eq!(self.owner, caller, "Only owner can create subdomains"); + assert_eq!(self.locked, false, "Domain transfers are locked"); + let subdomain_hash = self.namehash(subdomain, domain); + let subdomain_owner = self.getOwner(subdomain_hash); + assert_eq!(subdomain_owner, AccountId::from([0x0; 32]), "Subdomain already exists"); + self.set_subdomain_owner(subdomain_hash, caller); + self.env().emit_event(SubdomainCreated { + creator: caller, + owner: caller, + subdomain: subdomain, + domain: domain, + }); + } + #[ink(message)] + pub fn transfer_subdomain(&mut self, subdomain: Vec, domain: Vec, new_owner: AccountId) { + let caller = Self::env().caller(); + assert_eq!(self.owner, caller, "Only owner can transfer subdomains"); + assert_eq!(self.locked, false, "Domain transfers are locked"); + let subdomain_hash = self.namehash(subdomain, domain); + let subdomain_owner = self.getOwner(subdomain_hash); + assert_eq!(subdomain_owner, caller, "Only subdomain owner can transfer subdomain"); + self.set_subdomain_owner(subdomain_hash, new_owner); + self.env().emit_event(SubdomainCreated { + creator: caller, + owner: new_owner, + subdomain: subdomain, + domain: domain, + }); + } + #[ink(message)] + pub fn transfer_ownership(&mut self, new_owner: AccountId) { + let caller = Self::env().caller(); + assert_eq!(self.owner, caller, "Only owner can transfer ownership"); + self.owner = new_owner; + self.env().emit_event(OwnershipTransferred { + previous_owner: caller, + new_owner: new_owner, + }); + } + #[ink(message)] + pub fn lock_domain_transfers(&mut self) { + let caller = Self::env().caller(); + assert_eq!(self.owner, caller, "Only owner can lock domain transfers"); + self.locked = true; + self.env().emit_event(DomainTransfersLocked { + caller: caller, + locked: self.locked + }); + } + #[ink(message)] + pub fn transfer_contract_ownership(&mut self, new_owner: AccountId) { + let caller = Self::env().caller(); + assert_eq!(self.owner, caller, "Only owner can transfer contract ownership"); + self.env().transfer(new_owner, self.env().balance()); + } + } + +} diff --git a/nameservice/package.json b/nameservice/package.json new file mode 100644 index 0000000..f1c0b9d --- /dev/null +++ b/nameservice/package.json @@ -0,0 +1,14 @@ +{ + "name": "nameservice", + "version": "1.0.0", + "author": "Mar.io", + "license": "MIT", + "scripts": { + "run-node": "swanky node start", + "compile": "swanky compile", + "deploy": "swanky deploy" + }, + "dependencies": { + "@astar-network/swanky-cli": "0.2.0" + } +} \ No newline at end of file diff --git a/nameservice/swanky.config.json b/nameservice/swanky.config.json new file mode 100644 index 0000000..a7c0fd6 --- /dev/null +++ b/nameservice/swanky.config.json @@ -0,0 +1,35 @@ +{ + "node": { + "localPath": "", + "polkadotPalletVersions": "polkadot-v0.9.27", + "supportedInk": "v3.3.1" + }, + "accounts": [ + { + "alias": "alice", + "mnemonic": "//Alice", + "isDev": true, + "address": "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY" + }, + { + "alias": "bob", + "mnemonic": "//Bob", + "isDev": true, + "address": "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty" + } + ], + "networks": { + "local": { + "url": "ws://127.0.0.1:9944" + }, + "astar": { + "url": "wss://rpc.astar.network" + }, + "shiden": { + "url": "wss://rpc.shiden.astar.network" + }, + "shibuya": { + "url": "wss://rpc.shibuya.astar.network" + } + } +} diff --git a/nameservice/tsconfig.json b/nameservice/tsconfig.json new file mode 100644 index 0000000..c3fb339 --- /dev/null +++ b/nameservice/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "es2020", + "module": "commonjs", + "strict": true, + "esModuleInterop": true, + "outDir": "dist", + "noImplicitAny": false + }, + "include": ["**/*.ts"], + "exclude": ["node_modules"], + "files": ["./swanky.config.ts"] +}