Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ws-miniwallet-v0 MiniWallet Functionality #16

Merged
merged 40 commits into from
Sep 19, 2022
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
c0473e2
Initial version of miniwallet server
johnwhitton Aug 22, 2022
ac251c4
Add in sms message parsing and responses in twilio format
johnwhitton Aug 22, 2022
e45388c
Fix logic error in funding where funder and recipient were backwards
johnwhitton Aug 22, 2022
a234cf9
WIP: Begin work on Miniserver multiple operators per node and other f…
johnwhitton Aug 27, 2022
70ee740
WIP add executor logic to blockchain.js to support multiple accounts …
johnwhitton Aug 29, 2022
4b988b4
Working version of executor supporting multiple accounts via mnemonic
johnwhitton Aug 30, 2022
a47c25b
Remove miniserver src/data files and use servers for now (consider mo…
johnwhitton Aug 30, 2022
86c7933
Improve error handling for miniserver
johnwhitton Aug 30, 2022
9d4ab08
rename AssetManager to MiniWallet
johnwhitton Aug 30, 2022
b55e00c
Make MiniWallet Approval function payable and call deposit
johnwhitton Aug 30, 2022
5450eeb
Add in Logic for Proxy Upgrades for miniwallet
johnwhitton Sep 1, 2022
559f191
Initial Scaffolding for NFTs Mini721 and Mini1155 contracts
johnwhitton Sep 1, 2022
5990a9d
Clean up server and deploy logic (Feedback from PR 7 and 8)
johnwhitton Sep 4, 2022
21ae963
Remove unused config in miniserver
johnwhitton Sep 4, 2022
de7e7c5
Clean up MiniWallt_v2.sol and redeploy locally
johnwhitton Sep 4, 2022
875227f
Rename HRC721 to ERC721M (for MiniWallet)
johnwhitton Sep 4, 2022
a63d850
NFT Identity improvements around testing and config
johnwhitton Sep 5, 2022
56d8d31
Merge branch 'main' into miniV0
johnwhitton Sep 5, 2022
b4b87d1
MiniWallet NFT Testing remove unused code and improve readability
johnwhitton Sep 5, 2022
534e54f
Add in Deploy for Mini721 and update configuration
johnwhitton Sep 5, 2022
c746fef
Draft NFTId design
johnwhitton Sep 5, 2022
5ae56da
NFTID.md add additional reference info
johnwhitton Sep 5, 2022
c969982
Add MiniID contract and update Proxy Deployments
johnwhitton Sep 6, 2022
80c707c
Initial scaffolding for MiniID API
johnwhitton Sep 7, 2022
79510f8
Initial scaffolding for MiniID API (all files)
johnwhitton Sep 7, 2022
076c675
Initial work on including new Tokens MiniID,Mini721 and Mini1155
johnwhitton Sep 9, 2022
7f3c01b
Fix miniwallet contract deployments and get client showing NFT's
johnwhitton Sep 9, 2022
6b246cb
Add in Devlogs
johnwhitton Sep 17, 2022
6da449f
MiniWallet ignore deployments folders
johnwhitton Sep 17, 2022
959ae0f
Prune MiniID, Mini721 and MiniNFT
johnwhitton Sep 17, 2022
f5374ac
Proxy updates
johnwhitton Sep 17, 2022
e9f10fa
fix nft metadata query redundancy
polymorpher Sep 18, 2022
e1e371c
Merge branch 'main' into ws-miniwallet-v0
polymorpher Sep 18, 2022
8c704a0
ditto
polymorpher Sep 18, 2022
17d2258
move proxy.md
polymorpher Sep 18, 2022
8c10957
address issues in devlogs
polymorpher Sep 18, 2022
d2a8c97
update NFTID.md and add notes
polymorpher Sep 18, 2022
541de15
small editting of feature rollout
polymorpher Sep 19, 2022
c832c7e
remove unused function and package from server
polymorpher Sep 19, 2022
276e625
remove truffle parseTx function
polymorpher Sep 19, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 41 additions & 1 deletion client/src/config.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,37 @@
// require('dotenv-webpack').config()

const NFTS = [{
contractAddress: '0x426dD435EE83dEdb5af8eDa2729a9064C415777B',
tokenId: '1',
tokenType: 'ERC721',
}, {
contractAddress: '0x426dD435EE83dEdb5af8eDa2729a9064C415777B',
tokenId: '2',
tokenType: 'ERC721',
}, {
contractAddress: '0x6b2d0691dfF5eb5Baa039b9aD9597B9169cA44d0',
tokenId: '1',
tokenType: 'ERC1155',
}, {
contractAddress: '0x6b2d0691dfF5eb5Baa039b9aD9597B9169cA44d0',
tokenId: '2',
tokenType: 'ERC1155',
}]

const TEST_NFTS = [{
contractAddress: '0xCf7Ed3AccA5a467e9e704C703E8D87F634fB0Fc9',
tokenId: '1',
tokenType: 'ERC721'
}, {
contractAddress: '0xa513E6E4b8f2a923D98304ec87F64353C4D5C853',
tokenId: '1',
tokenType: 'ERC721'
}, {
contractAddress: '0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e',
tokenId: '2',
tokenType: 'ERC1155'
}]

const config = {
priceRefreshInterval: 60 * 1000,
appId: 'sms-wallet',
Expand All @@ -7,7 +41,7 @@ const config = {
// gateway: process.env.IPFS_GATEWAY || 'https://dweb.link/ipfs/{{hash}}'
// gateway: process.env.IPFS_GATEWAY || 'https://ipfs.io/ipfs/{{hash}}'
// gateway: process.env.IPFS_GATEWAY || 'https://gateway.pinata.cloud/ipfs/{{hash}}'
gateway: process.env.IPFS_GATEWAY || 'https://1wallet.mypinata.cloud/ipfs/{{hash}}'
gateway: process.env.IPFS_GATEWAY || 'https://modulo.mypinata.cloud/ipfs/{{hash}}'
},
gasPrice: process.env.GAS_PRICE || 1000,
networkId: process.env.NETWORK_ID || 1666600000,
Expand Down Expand Up @@ -46,6 +80,12 @@ const config = {
},
scanDelay: 250,
defaultSignatureValidDuration: 1000 * 60 * 15,
mainnet: {
nfts: JSON.parse(process.env.NFTS || JSON.stringify(NFTS))
},
test: {
nfts: JSON.parse(process.env.TEST_NFTS || JSON.stringify(TEST_NFTS))
}
}

export default config
46 changes: 20 additions & 26 deletions client/src/pages/NFT.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { TailSpin } from 'react-loading-icons'
import PhoneInput from 'react-phone-number-input'
import { walletActions } from '../state/modules/wallet'
import { balanceActions } from '../state/modules/balance'
import config from '../config'

export const MetadataURITransformer = (url) => {
const IPFSIO = /https:\/\/ipfs\.io\/ipfs\/(.+)/
Expand Down Expand Up @@ -46,17 +47,20 @@ export const useMetadata = ({
try {
const { data: metadata } = await axios.get(uri)
setMetadata(metadata)
if (metadata.image && (metadata.image.length - metadata.image.lastIndexOf('.')) > 5 && !contentTypeOverride) {
const resolvedImageUrl = NFTUtils.replaceIPFSLink(metadata.image, ipfsGateway)
if (!metadata.image) {
return
}
const resolvedImageUrl = NFTUtils.replaceIPFSLink(metadata.image, ipfsGateway)
if (!contentType) {
const { headers: { 'content-type': contentType } } = await axios.head(resolvedImageUrl)
setResolvedImageUrl(resolvedImageUrl)
setContentType(contentType)
if (metadata.animation_url) {
const animationUrl = NFTUtils.replaceIPFSLink(metadata?.animation_url || metadata?.properties?.animation_url, ipfsGateway)
const { headers: { 'content-type': animationUrlContentType } } = await axios.head(animationUrl)
setResolvedAnimationUrl(animationUrl)
setAnimationUrlContentType(animationUrlContentType)
}
}
setResolvedImageUrl(resolvedImageUrl)
if (metadata.animation_url) {
const animationUrl = NFTUtils.replaceIPFSLink(metadata?.animation_url || metadata?.properties?.animation_url, ipfsGateway)
const { headers: { 'content-type': animationUrlContentType } } = await axios.head(animationUrl)
setResolvedAnimationUrl(animationUrl)
setAnimationUrlContentType(animationUrlContentType)
}
} catch (ex) {
console.error(ex)
Expand Down Expand Up @@ -278,6 +282,7 @@ export const NFTItem = ({ address, contractAddress, tokenId, tokenType, onSelect
<NFTItemContainer onClick={() => onSelect && onSelect({ resolvedImageUrl, contractAddress, isImage, isVideo, metadata, contractName, tokenId, tokenType })}>
{!contentType && <Loading><TailSpin /> </Loading>}
{isImage && <NFTImage src={resolvedImageUrl} />}
{/* <NFTImage src='https://1wallet.mypinata.cloud/ipfs/QmUgueVH4cQgBEB8aJ3JJT8hMaDS4yHaHvBugGhGLyz9Nx/1.png' /> */}
{isVideo && <NFTVideo src={resolvedImageUrl} loop muted autoplay />}
<Row>
<FlexColumn style={{ flex: 1 }}>
Expand All @@ -292,23 +297,12 @@ export const NFTItem = ({ address, contractAddress, tokenId, tokenType, onSelect
}

// eslint-disable-next-line no-unused-vars
const DUMMY_NFTS = [{
contractAddress: '0x426dD435EE83dEdb5af8eDa2729a9064C415777B',
tokenId: '1',
tokenType: 'ERC721',
}, {
contractAddress: '0x426dD435EE83dEdb5af8eDa2729a9064C415777B',
tokenId: '2',
tokenType: 'ERC721',
}, {
contractAddress: '0x6b2d0691dfF5eb5Baa039b9aD9597B9169cA44d0',
tokenId: '1',
tokenType: 'ERC1155',
}, {
contractAddress: '0x6b2d0691dfF5eb5Baa039b9aD9597B9169cA44d0',
tokenId: '2',
tokenType: 'ERC1155',
}]
let DUMMY_NFTS
if (config.chainId === 1666600000) {
DUMMY_NFTS = config.mainnet.nfts
} else {
DUMMY_NFTS = config.test.nfts
}

const loadNFTs = ({ address }) => {
const dispatch = useDispatch()
Expand Down
57 changes: 57 additions & 0 deletions miniserver/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Server Configuration
SERVER_URL='https://localhost'
PORT=3101
HTTPS_PORT=8444


## Configurable (set these values to change default behaviour for local testing)
MINISERVER_DEBUG=1
RELAYER_DEBUG=1
VERBOSE=1
SAFE_NONCE=1
APIDOCS=1

## Mandatory
CORS=*
SECRET='none'

# Datastore
GCP_PROJECT='sms-wallet-00'
GCP_CRED_PATH='./credentials/sms-wallet-00-a91857ffcaaf.json'
GCP_NAMESPACE='sms-wallet'

# Twilio
TWILIO_ACCOUNT_SID=
TWILIO_AUTH_TOKEN=
TWILIO_FROM=

# OTP
OTP_SALT='local-salt'

# Client
CLIENT_ROOT='https://localhost:3100/'

## Netork Information
# eth-local
ETH_LOCAL_RPC='http://127.0.0.1:8545'
ETH_LOCAL_WSS='ws://127.0.0.1:8545'
ETH_LOCAL_KEY='0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d'
ETH_LOCAL_MNEMONIC='test test test test test test test test test test test junk'
ETH_LOCAL_NUM_ACCOUNTS=3
ETH_LOCAL_MINI_WALLET=0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
ETH_LOCAL_MINI_ID=0x5FC8d32690cc91D4c39d9d3abcBD16989F875707

## Default Values (can be ommitted)
POLLING_INTERVAL=1000
DEFAULT_NETWORK='eth-local'
GAS_LIMIT='67219000'
#GAS_PRICE='10000000'
GAS_PRICE='413290302'
CACHE='cache'
STATS_PATH='../data/stats.json'
OTP_INTERVAL=60000





36 changes: 36 additions & 0 deletions miniserver/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
module.exports = {
root: true,
env: {
node: true,
es2020: true,
jest: true,
},
extends: [
'standard',
],
globals: {
artifacts: 'readonly',
contract: 'readonly',
assert: 'readonly',
ethers: 'readonly'
},
// 'parser': '@babel/eslint-parser',
rules: {
'no-await-in-loop': 0,
'no-underscore-dangle': 0,
'import/prefer-default-export': 0,
'import/no-extraneous-dependencies': 1,
'comma-dangle': 0,
'no-console': 0,
'no-mixed-operators': 0,
'new-cap': 0,
'max-len': 0,
},
parserOptions: {
requireConfigFile: false,
ecmaVersion: 2020
},
plugins: [
'@babel',
],
}
4 changes: 4 additions & 0 deletions miniserver/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/credentials
/certs/*
!/certs/README.md
!/certs/gen.sh
119 changes: 119 additions & 0 deletions miniserver/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
require('dotenv').config()
const createError = require('http-errors')
// const rateLimit = require('express-rate-limit')
const Fingerprint = require('express-fingerprint')
const express = require('express')
const path = require('path')
const cookieParser = require('cookie-parser')
const logger = require('morgan')
const config = require('./config')
const _index = require('./routes/index')
const bodyParser = require('body-parser')
const app = express()
const https = require('https')
const http = require('http')
const env = process.env.NODE_ENV || 'development'
const fs = require('fs')
const blockchain = require('./blockchain')

Error.stackTraceLimit = 100
app.locals.ENV = env
app.locals.ENV_DEVELOPMENT = env === 'development'

app.set('trust proxy', true)

try {
blockchain.init().catch(ex => {
console.error('Blockchain initialization failed')
console.error(ex)
process.exit(2)
})
} catch (ex) {
console.error(ex)
process.exit(1)
}

let httpServer, httpsServer

const httpsOptions = {
key: fs.readFileSync(config.https.key),
cert: fs.readFileSync(config.https.cert)
}

if (config.https.only) {
const httpApp = express()
const httpRouter = express.Router()
httpApp.use('*', httpRouter)
httpRouter.get('*', function (req, res) {
const hostPort = (req.get('host') || '').split(':')
const url = hostPort.length === 2 ? `https://${hostPort[0]}:${config.httpsPort}${req.originalUrl}` : `https://${hostPort[0]}${req.originalUrl}`
res.redirect(url)
})
httpServer = http.createServer(httpApp)
} else {
httpServer = http.createServer(app)
}

httpsServer = https.createServer(httpsOptions, app)

app.use(Fingerprint({
parameters: [
Fingerprint.useragent,
Fingerprint.acceptHeaders,
Fingerprint.geoip,
]
}))

app.use(bodyParser.json({
verify: function (req, _res, buf) {
req.rawBody = buf
}
}))
app.use(bodyParser.urlencoded({ extended: true }))
app.use(logger('dev'))
app.use(express.json())
app.use(express.urlencoded({ extended: false }))
app.use(cookieParser())

if (config.corsOrigins) {
app.use((req, res, next) => {
// res.header('Access-Control-Allow-Origin', config.corsOrigins)
if (config.corsOrigins === '*' || config.corsOrigins.indexOf(req.headers.origin) >= 0) {
res.header('Access-Control-Allow-Origin', req.headers.origin || config.corsOrigins)
} else {
res.header('Access-Control-Allow-Origin', config.corsOrigins)
}

res.header('Access-Control-Allow-Credentials', 'true')

res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, OPTIONS')

res.header('Access-Control-Allow-Headers', 'X-SECRET, X-NETWORK, X-MAJOR-VERSION, X-MINOR-VERSION, Accept, Accept-CH, Accept-Charset, Accept-Datetime, Accept-Encoding, Accept-Ext, Accept-Features, Accept-Language, Accept-Params, Accept-Ranges, Access-Control-Allow-Credentials, Access-Control-Allow-Headers, Access-Control-Allow-Methods, Access-Control-Allow-Origin, Access-Control-Expose-Headers, Access-Control-Max-Age, Access-Control-Request-Headers, Access-Control-Request-Method, Age, Allow, Alternates, Authentication-Info, Authorization, C-Ext, C-Man, C-Opt, C-PEP, C-PEP-Info, CONNECT, Cache-Control, Compliance, Connection, Content-Base, Content-Disposition, Content-Encoding, Content-ID, Content-Language, Content-Length, Content-Location, Content-MD5, Content-Range, Content-Script-Type, Content-Security-Policy, Content-Style-Type, Content-Transfer-Encoding, Content-Type, Content-Version, Cookie, Cost, DAV, DELETE, DNT, DPR, Date, Default-Style, Delta-Base, Depth, Derived-From, Destination, Differential-ID, Digest, ETag, Expect, Expires, Ext, From, GET, GetProfile, HEAD, HTTP-date, Host, IM, If, If-Match, If-Modified-Since, If-None-Match, If-Range, If-Unmodified-Since, Keep-Alive, Label, Last-Event-ID, Last-Modified, Link, Location, Lock-Token, MIME-Version, Man, Max-Forwards, Media-Range, Message-ID, Meter, Negotiate, Non-Compliance, OPTION, OPTIONS, OWS, Opt, Optional, Ordering-Type, Origin, Overwrite, P3P, PEP, PICS-Label, POST, PUT, Pep-Info, Permanent, Position, Pragma, ProfileObject, Protocol, Protocol-Query, Protocol-Request, Proxy-Authenticate, Proxy-Authentication-Info, Proxy-Authorization, Proxy-Features, Proxy-Instruction, Public, RWS, Range, Referer, Refresh, Resolution-Hint, Resolver-Location, Retry-After, Safe, Sec-Websocket-Extensions, Sec-Websocket-Key, Sec-Websocket-Origin, Sec-Websocket-Protocol, Sec-Websocket-Version, Security-Scheme, Server, Set-Cookie, Set-Cookie2, SetProfile, SoapAction, Status, Status-URI, Strict-Transport-Security, SubOK, Subst, Surrogate-Capability, Surrogate-Control, TCN, TE, TRACE, Timeout, Title, Trailer, Transfer-Encoding, UA-Color, UA-Media, UA-Pixels, UA-Resolution, UA-Windowpixels, URI, Upgrade, User-Agent, Variant-Vary, Vary, Version, Via, Viewport-Width, WWW-Authenticate, Want-Digest, Warning, Width, X-Content-Duration, X-Content-Security-Policy, X-Content-Type-Options, X-CustomHeader, X-DNSPrefetch-Control, X-Forwarded-For, X-Forwarded-Port, X-Forwarded-Proto, X-Frame-Options, X-Modified, X-OTHER, X-PING, X-PINGOTHER, X-Powered-By, X-Requested-With')
next()
})
}

app.use(express.static(path.join(__dirname, 'public')))
app.options('*', async (_req, res) => res.end())
app.use('/', _index)

// catch 404 and forward to error handler
app.use(function (req, res, next) {
next(createError(404))
})

// error handler
app.use(function (err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message
res.locals.error = config.debug ? err : {}

// render the error page
res.status(err.status || 500)
res.json({ error: res.locals.error, message: err.message })
})

module.exports = {
httpServer,
httpsServer
}
16 changes: 16 additions & 0 deletions miniserver/bin/run.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env node
const apps = require('../app')
const config = require('../config')
const httpsServer = apps.httpsServer
const httpServer = apps.httpServer
console.log('Starting web server...')

httpsServer.listen(config.httpsPort || 8443, () => {
const addr = httpsServer.address()
console.log(`HTTPS server listening on port ${addr.port} at ${addr.address}`)
})

httpServer.listen(config.port || 3000, () => {
const addr = httpServer.address()
console.log(`HTTP server listening on port ${addr.port} at ${addr.address}`)
})
Loading