---
# System prepended metadata

title: Walter部份
tags: [Solidity]

---

###### tags: `Solidity`
# Walter部份

[TOC]

### 流程圖
1. 流程及Block圖, [Miro](https://miro.com/app/board/uXjVOKr4eqE=/?invite_link_id=991086201686)
2. 所有流程含UI/UX wireframe, [Web](http://aisw.in/134/flow/form-wizard.html)

### MongoDB 教學
1.control
```
- db.createCollection('nfactory-backend')
- show dbs
- use nfactory-backend
- db.getName()
- db.getCollectionNames()
- db.db.getCollectionNames("nfactory-backend").drop
- db.dropDatabase()
```
2.CRUD
- [安裝、基礎CRUD、外部輸入資料、Data Type](https://medium.com/@mingjiehsu/mongodb-學習筆記-一-安裝-基礎crud-外部輸入資料-data-type-1169000cf02c)
- [MongoDB supports many datatypes](https://www.tutorialspoint.com/mongodb/mongodb_datatype.htm)
- [MongoDB Schema 設計指南
](https://blog.toright.com/posts/4483/mongodb-schema-設計指南.html)

### Landing page 設定 config.js

```json
{
  "CONTRACT_ADDRESS": "0x827acb09a2dc20e39c9aad7f7190d9bc53534192",
  "SCAN_LINK": "https://polygonscan.com/token/0x827acb09a2dc20e39c9aad7f7190d9bc53534192",
  "NETWORK": {
    "NAME": "Polygon",
    "SYMBOL": "Matic",
    "ID": 137
  },
  "NFT_NAME": "Nerdy Coder Clones",
  "SYMBOL": "NCC",
  "MAX_SUPPLY": 1000,
  "WEI_COST": 75000000000000000,
  "DISPLAY_COST": 0.075,
  "GAS_LIMIT": 285000,
  "MARKETPLACE": "OpenSea",
  "MARKETPLACE_LINK": "https://opensea.io/collection/nerdy-coder-clones",
  "SHOW_BACKGROUND": true
}
```

### Database Schema (佈署在 AWS MongoDB)
1. hashlips_nft_miniting_dapp 後端
```
user {
    _id
    role
    wallet_addr
    email
    created_at
}

page {
    _id
    u_id
    n_id
    contract_addr
    scan_link
    network_id
    page_url
    background_url
    title_url
    both_gif_url
    created_at
}

nft {
    _id
    u_id
    nft_name
    nft_symbol
    max_supply
    tokenURI
    has_blind_box
    has_robot_prevent
    has_meta_hidden
    public_sale_count
    steps {
        type
        status
        step {
            normal_sale_quantity
            normal_sale_price

            whitelist_quantity

            reservation_quantity

            start_time
            time_step
            start_price
            end_price
            price_step
            step_number

            unrevealURI
            reveal_time
        }
    }
    status
    created_at
```
- DB Schema [說明](https://docs.google.com/spreadsheets/d/111jin2hpSuUTjjngz9r7A3RMGF3wsMDtQeKoCDxaQfk/edit#gid=0)
- API
```
- Swagger
- docker
- nestjs
- mongoose
```

### 進度報告
1. 2022/2/26 
```
Lemon: React connect solidity
Walter: API
Ethan: Backend / CICD
```
Finish
```
Flow, Wireframe, DB schema, System Design, Smart Contract
```
2. 2022/2/19 [Solidity_W1_第1組專題](https://drive.google.com/file/d/1IGWxNJmwLoltIuF4jEbv0hNTZVzuS1nk/view?usp=sharing)
3. 2022/2/12 [Solidity 開發班畢業專案進度報告](https://hackmd.io/zeWGuG-NScq0XygGZgrweg?both)

### NFT marketplace survey
PS: 本次專題先不做這部份
1. miquel-nft-marketplace
```
git clone https://github.com/SWANDAO/miquel-nft-marketplace (修正版)
```
NFTCollection : [0x11c40757850a98a26e2fccbef8f70a60095032b1](https://rinkeby.etherscan.io/address/0x11c40757850a98a26e2fccbef8f70a60095032b1)
NFTMarketplace : [0x8c76f9a4d3c17abc4de18d3c98abbc983564fa08](https://rinkeby.etherscan.io/address/0x8c76f9a4d3c17abc4de18d3c98abbc983564fa08)

原版 [連結](https://github.com/miquelTC/nft-marketplace)

2. netlify
```
1. add script in package.json
2. yarn add -D netlify-cli
3. netlify login
4. npx netlify init
5. npx netlify status
6. add lines netlify.toml
   [build]
     command = "yarn build"
7. npx netlify deploy --build --prod

沒成功，再找時間處理
```
3. 其它的 marketplace 可參考 [github](https://github.com/topics/nft-marketplace)

### Create2 功能拆分版
1.Create2.sol
```solidity=
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

// create2 - deterministically precompute contract address
// code
// demo

contract Factory {
  event Deployed(address addr, uint256 salt);

  // 1. Get bytecode of contract to be deployed
  function getBytecode (address _owner, uint _foo) public pure returns (bytes memory) {
    bytes memory bytecode = type(TestContract).creationCode;    // runtime code
    return abi.encodePacked(bytecode, abi.encode(_owner, _foo));
  }
  // 2. Compute the address of the contract to be deployed
  // keccak256(0xff + sender address + salt + keccak256(creation code))   // salt:random number
  // take last 20 bytes
  function getAddress(bytes memory bytecode, uint _salt) public view returns (address) {
    bytes32 hash = keccak256(
      abi.encodePacked(
        bytes1(0xff),
        address(this),
        _salt,
        keccak256(bytecode)
      )
    );
    // cast last 20 bytes of hash to address
    return address(uint160(uint256(hash)));
  }

  // 3. Deploy the contract
  function deploy(bytes memory bytecode, uint _salt) public payable {
    address addr;
    /*
        How to call create2

        create2(v, p, n, s)
          v - amount of ETH to send
          p - pointer to start of code in memory
          n - size of code
          s - salt
    */
    assembly {
      addr := create2(
        callvalue(),         // wei send with curent call
        add(bytecode, 0x20), // Actual code starts after skipping the first 32 bytes
        mload(bytecode),     // Load the size of code contained in the first 32 bytes
        _salt                // Salt from function arguments
      )

      if iszero(extcodesize(addr)) {
        revert(0, 0)
      }
    }

    emit Deployed(addr, _salt);
  }
}

contract TestContract {
  address public owner;
  uint public foo;

  constructor(address _owner, uint _foo) payable {
    owner = _owner;
    foo = _foo;
  }

  function getBalance() public view returns (uint) {
    return address(this).balance;
  }
}
```
2.先佈署 Factory, 執行 getBytecode(owner_address, _salt)，其中 owner_address = address(msg.sender)，_salt為任何的隨機數
```
參數傳入後，會得到 bytecode
這步驟主要是生成 TestContract 的 bytecode
```
3.計算要佈署的 bytecode 的合約地址，執行 getAddress(bytecode, _salt)
bytecode 是上一步驟生成的 bytecode，_salt為上一步驟的隨機數
```
keccak256(0xff + sender address + salt + keccak256(creation code))
參數傳入後，會得到 佈署地址 contract address
```
4.執行 deploy(bytecode, _salt)，利用 assembly 執行 create2(v,p,n,s)
```
參數傳入後，即可完成 TestContract 的佈署，可執行該合約的 getBalance() 函數
透過 emit Deployed(addr, _salt) 可讓外部取得合約地址及 _salt
而且 constructor 也在 Factory 合約生成 TestContract 時代入
```

### Create2 合併版
1.Step版的合併版本，說明同Step
版
```solidity=
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Factory {
  event Deployed(address addr, uint256 salt);
  address private owner = address(msg.sender);
  address public callee_addr;

  constructor(uint _foo, uint _salt) {    // 777, 111
    bytes memory tmp_bytecode = type(TestContract).creationCode;
    bytes memory bytecode = abi.encodePacked(tmp_bytecode, abi.encode(owner, _foo));
    bytes32 hash = keccak256(
      abi.encodePacked(
          bytes1(0xff),
          address(this),
          _salt,
          keccak256(bytecode)
      )
    );
    callee_addr = address(uint160(uint256(hash)));

    address addr;
    assembly {
      addr := create2(
        callvalue(),         // wei send with curent call                
        add(bytecode, 0x20), // Actual code starts after skipping the first 32 bytes
        mload(bytecode),     // Load the size of code contained in the first 32 bytes
        _salt                // Salt from function arguments
      )

      if iszero(extcodesize(addr)) {
        revert(0, 0)
      }
    }
    emit Deployed(addr, _salt);
  }
}

contract TestContract {
  address public owner;
  uint public foo;

  constructor(address _owner, uint _foo) payable {
    owner = _owner;
    foo = _foo;
  }

  function getBalance() public view returns (uint) {
    return address(this).balance;
  }
}
```

### nunjucks
1. 連結
```
Template: https://mozilla.github.io/nunjucks/templating.html
API: https://mozilla.github.io/nunjucks/api.html
```
2. if
```
let nunjucks = require('nunjucks')
nunjucks.configure({autoescape:true})

// 使用判斷
let ret = nunjucks.renderString(`
  {% if score > 90 %}
    優秀
  {% elseif score > 80%}
    良好
  {% elseif score > 60%}
    及格
  {% else %}
    不及格
  {% endif %}
  `,
  {score:81}
)

console.log(ret) // 及格
```
3. filter
```
let nunjucks = require('nunjucks')
nunjucks.configure({autoescape:true})

// 使用過濾器
let ret = nunjucks.renderString(
  "{{username|join('-')}}",
  {username:['blued','city']}
)
console.log(ret) // blued-city

// replace 及 大寫
let ret2 = nunjucks.renderString(
  "{{username|replace('city','there')|capitalize}}",
  {username:'blued city'}
)
console.log(ret2) // Blued there
```
4. for
```
let nunjucks = require('nunjucks')
nunjucks.configure({autoescape:true})

// 使用判斷 loop.index為索引
let ret = nunjucks.renderString(`
  <ul>
  {% for user in users %}
    <li>{{loop.index}} {{user.id}}:{{user.name}}</li>
  {% endfor %}
  </ul>
`,
  {users:[
    {id:1,name:'blued1'},
    {id:2,name:'blued2'},
    {id:3,name:'blued3'},
    {id:4,name:'blued4'},
    {id:5,name:'blued5'}
  ]}
)
console.log(ret)
```
5. loop
```
let nunjucks = require('nunjucks')
nunjucks.configure({autoescape:true})
// 使用判斷
let ret = nunjucks.renderString(`
<ul>{% for user in users %}
  <li>
  loop.index--{{loop.index}}
  loop.index0--{{loop.index0}}
  loop.revindex--{{loop.revindex}}
  loop.revindex0--{{loop.revindex0}}
  loop.first--{{loop.first}}
  loop.last --{{loop.last}}
  loop.length --{{loop.length}}
  {{user.id}}:{{user.name}}
  </li>{% endfor %}
</ul>
`,
{users:[
  {id:1,name:'Lemon'},
  {id:3,name:'Walter'},
  {id:4,name:'Ethan'}
]})
console.log(ret)
```
6. layout
```
const nunjucks = require('nunjucks')
const path = require('path')
// 如何渲染模版文件
let data = {name:'Walter'}
// 配置模版文件的所在目錄
nunjucks.configure(path.resolve(__dirname,'view'),{
autoescape:true
})
let result = nunjucks.render('layout.html',data)
console.log(result)

view/layour.html
----------------
<body>
  <h1>我是頭</h1>
  {% block content%}
  我是layout模板的內容name= {{name}}
  {% endblock%}
  <h1>我是尾</h1>
</body>
```
7. login
```
const nunjucks = require('nunjucks')
const path = require('path')
// 如何渲染模版文件
let data = {name:'Walter'}
// 配置模版文件的所在目錄
nunjucks.configure(path.resolve(__dirname,'view'),{
autoescape:true
})
let result = nunjucks.render('layout.html',data)
console.log(result)
```
8. inculde
```
const nunjucks = require('nunjucks')
const path = require('path')

// 模版的包含
let data = { users:[{id:1,name:'Lemon'}, {id:3,name:'Walter'}]}
// 配置模版文件的所在目錄
nunjucks.configure(path.resolve(__dirname,'view'), {
  autoescape:true
})

let result = nunjucks.render('users.html',data)
console.log(result)

view/users.html
---------------
{% extends "layout.html"%}
{% block content %}
  <ul style='border:1px solid red'>
    {% for user in users %}
    {% include "item.html" %}
    {% endfor%}
  </ul>
{% endblock %}

view/item.html
--------------
<li>名次：{{loop.index}}, ID：{{user.id}}, 名字：{{user.name}}</li>
```
9. express
```
const express = require('express');
const nunjucks = require('nunjucks');
const path = require('path');

var app = express();

// nodejs 當前工作目錄
nunjucks.configure(path.resolve(__dirname,'view'), {
  autoescape: true, // 控制輸出是否被轉譯
  express: app,     // 傳入 express instance 初始化模板設置
  watch: true       // 啟用模板文件，一旦改變，重新編譯
})

app.get('/', function (req, res) {
  console.log("GET request for Home Page");
  res.send('Hello World');
})

app.get('/name/:name',function(req,res){
  res.render('name.html', {name:req.params.name})
})

var server = app.listen(8081, function () {
  var port = server.address().port
  console.log("Listening at http://127.0.0.1:%s", port)
})

view/name.html
--------------
<!DOCTYPE html>
  <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>Document</title>
    </head>
  <body>
    <div>
      Hello, {{ name }} <= 此處替換
    <div>
  </body>
</html>
```

### 心得
```
1. 學習到一些系統架構及CICD觀念
2. 更了解NFT流程
3. 組員在不同Job fuction的互補
4. 更了解Solidity, React的code
5. 團隊分工及相互配合及體諒
6. 時程實在是很趕，但品質還是得要求
```