###### 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. 時程實在是很趕,但品質還是得要求
```