update numbergame bapp
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
pragma solidity ^0.4.18;
|
pragma solidity >=0.4.24 <=0.5.6;
|
||||||
|
|
||||||
contract Ownable {
|
contract Ownable {
|
||||||
address owner;
|
address owner;
|
||||||
function Ownable() public {
|
constructor() public {
|
||||||
owner = msg.sender;
|
owner = msg.sender;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -14,39 +14,36 @@ contract Ownable {
|
|||||||
|
|
||||||
contract Mortal is Ownable {
|
contract Mortal is Ownable {
|
||||||
function kill() public Owned {
|
function kill() public Owned {
|
||||||
selfdestruct(owner);
|
selfdestruct(msg.sender);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
contract Betting is Mortal {
|
contract Game is Mortal {
|
||||||
uint minBet; // 최소 베팅액
|
uint minBet; // 최소 베팅액
|
||||||
uint winRate; // 배당률 (%)
|
|
||||||
|
|
||||||
event Won(bool _result, uint _amount);
|
event Won(bool _result, uint _amount);
|
||||||
|
|
||||||
function Betting(uint _minBet, uint _winRate) payable public {
|
constructor(uint _minBet) payable public {
|
||||||
require(_minBet > 0);
|
require(_minBet > 0);
|
||||||
require(_winRate <= 100);
|
minBet = _minBet;
|
||||||
minBet = _minBet;
|
|
||||||
winRate = _winRate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function() public {
|
function() external {
|
||||||
revert();
|
revert();
|
||||||
}
|
}
|
||||||
|
|
||||||
function bet(uint _num) payable public {
|
function play(uint _num) payable public {
|
||||||
require(_num > 0 && _num <= 5);
|
require(_num > 0 && _num <= 5);
|
||||||
require(msg.value >= minBet);
|
require(msg.value >= minBet);
|
||||||
|
|
||||||
uint winNum = random();
|
uint winNum = random();
|
||||||
if (_num == winNum) {
|
if (_num == winNum) {
|
||||||
uint amtWon = msg.value * (100 - winRate)/10;
|
uint amtWon = msg.value * 2;
|
||||||
if(!msg.sender.send(amtWon)) revert();
|
if(!msg.sender.send(amtWon)) revert();
|
||||||
Won(true, amtWon);
|
emit Won(true, amtWon);
|
||||||
} else {
|
} else {
|
||||||
Won(false, 0);
|
emit Won(false, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,7 +52,6 @@ contract Betting is Mortal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function random() public view returns (uint) {
|
function random() public view returns (uint) {
|
||||||
return uint(keccak256(block.difficulty, block.number, now)) % 5 + 1;
|
return uint(keccak256(abi.encodePacked(now, msg.sender))) % 5 + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
7174
numbergame/package-lock.json
generated
7174
numbergame/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "bet-dapp",
|
"name": "numbergame-bapp",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
"vue": "^2.5.21",
|
"vue": "^2.5.21",
|
||||||
"vue-router": "^3.0.2",
|
"vue-router": "^3.0.2",
|
||||||
"vuex": "^3.0.1",
|
"vuex": "^3.0.1",
|
||||||
"web3": "^0.20.6"
|
"caver-js": "^1.3.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vue/cli-plugin-babel": "^3.1.1",
|
"@vue/cli-plugin-babel": "^3.1.1",
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="hello">
|
|
||||||
<h1>{{ msg }}</h1>
|
|
||||||
<p>
|
|
||||||
For a guide and recipes on how to configure / customize this project,<br>
|
|
||||||
check out the
|
|
||||||
<a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
|
|
||||||
</p>
|
|
||||||
<h3>Installed CLI Plugins</h3>
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
|
|
||||||
</ul>
|
|
||||||
<h3>Essential Links</h3>
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
|
|
||||||
<li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
|
|
||||||
<li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
|
|
||||||
<li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
|
|
||||||
<li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
|
|
||||||
</ul>
|
|
||||||
<h3>Ecosystem</h3>
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
|
|
||||||
<li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
|
|
||||||
<li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
|
|
||||||
<li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
|
|
||||||
<li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'HelloWorld',
|
|
||||||
props: {
|
|
||||||
msg: String
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!-- Add "scoped" attribute to limit CSS to this component only -->
|
|
||||||
<style scoped>
|
|
||||||
h3 {
|
|
||||||
margin: 40px 0 0;
|
|
||||||
}
|
|
||||||
ul {
|
|
||||||
list-style-type: none;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
li {
|
|
||||||
display: inline-block;
|
|
||||||
margin: 0 10px;
|
|
||||||
}
|
|
||||||
a {
|
|
||||||
color: #42b983;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,23 +1,27 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="betting">
|
<div class="betting">
|
||||||
<h1>Bet Dapp Test</h1>
|
<h1>Numbergame BApp Test</h1>
|
||||||
Amount: <input v-model="amount" placeholder="0 Ether">
|
Amount: <input v-model="amount" placeholder="0 Klay">
|
||||||
<ul>
|
<ul>
|
||||||
<li v-on:click="_clickNumber">1</li>
|
<li v-on:click="clickNumber">1</li>
|
||||||
<li v-on:click="_clickNumber">2</li>
|
<li v-on:click="clickNumber">2</li>
|
||||||
<li v-on:click="_clickNumber">3</li>
|
<li v-on:click="clickNumber">3</li>
|
||||||
<li v-on:click="_clickNumber">4</li>
|
<li v-on:click="clickNumber">4</li>
|
||||||
<li v-on:click="_clickNumber">5</li>
|
<li v-on:click="clickNumber">5</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div v-if="pending" id="loader">Loading...</div>
|
<div v-if="pending" id="loader">Loading...</div>
|
||||||
<div class="event" v-if="winEvent">
|
<div class="event" v-if="winEvent">
|
||||||
Won: {{ winEvent._result }}
|
Won: {{ winEvent.result }}
|
||||||
Amount: {{ winEvent._amount }} Wei
|
Reward: {{ winEvent.amount }} Klay
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { mapGetters, mapMutations } from 'vuex'
|
||||||
|
|
||||||
|
import {cav} from '@/klaytn/caver'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'betting-component',
|
name: 'betting-component',
|
||||||
data() {
|
data() {
|
||||||
@@ -26,38 +30,38 @@ export default {
|
|||||||
pending: false,
|
pending: false,
|
||||||
winEvent: null
|
winEvent: null
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
...mapGetters('wallet', [
|
||||||
|
'klaytn'
|
||||||
|
])
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted () {
|
mounted () {
|
||||||
this.$store.dispatch('getContractInstance')
|
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
_clickNumber (event) {
|
clickNumber (event) {
|
||||||
console.log('betting number', event.target.innerHTML, this.amount)
|
console.log('betting number', event.target.innerHTML, this.amount)
|
||||||
this.winEvent = null
|
|
||||||
this.pending = true
|
this.pending = true
|
||||||
this.$store.state.contractInstance().bet(event.target.innerHTML, {
|
|
||||||
gas: 300000,
|
this.winEvent = {}
|
||||||
value: this.$store.state.web3.web3Instance().toWei(this.amount, 'ether'),
|
this.klaytn.play(event.target.innerHTML, this.amount, (receipt) => {
|
||||||
from: this.$store.state.web3.coinbase
|
const result = receipt.events.Won.returnValues[0]
|
||||||
}, (err, result) => {
|
const amount = receipt.events.Won.returnValues[1]
|
||||||
if (err) {
|
|
||||||
console.error(err)
|
this.winEvent.result = result
|
||||||
this.pending = false
|
this.winEvent.amount = cav.utils.fromPeb(amount, "KLAY")
|
||||||
} else {
|
|
||||||
const Won = this.$store.state.contractInstance().Won()
|
this.$emit('complete-choose-number')
|
||||||
Won.watch((err, result) => {
|
|
||||||
if (err) {
|
this.pending = false
|
||||||
console.error('won', error)
|
}, (error) => {
|
||||||
} else {
|
console.error(error)
|
||||||
this.winEvent = result.args
|
this.pending = false
|
||||||
this.winEvent._amount = parseInt(result.args._amount, 10)
|
|
||||||
this.pending = false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<DappMetamask />
|
|
||||||
<BettingComponent />
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
import DappMetamask from '@/components/dapp-metamask'
|
|
||||||
import BettingComponent from '@/components/betting-component'
|
|
||||||
export default {
|
|
||||||
name: 'betting-dapp',
|
|
||||||
beforeCreate () {
|
|
||||||
console.log('registerWeb3 Action dispatched')
|
|
||||||
this.$store.dispatch('registerWeb3')
|
|
||||||
},
|
|
||||||
components: {
|
|
||||||
DappMetamask,
|
|
||||||
BettingComponent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class='metamask-info'>
|
|
||||||
<p>연결 상태 : {{ web3.isInjected }}</p>
|
|
||||||
<p>네트워크: {{ web3.networkId }}</p>
|
|
||||||
<p>코인베이스 주소: {{ web3.coinbase }}</p>
|
|
||||||
<p>잔액: {{ web3.balance }}</p>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
name: 'dapp-metamask',
|
|
||||||
computed: {
|
|
||||||
web3 () {
|
|
||||||
return this.$store.state.web3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<style scoped>
|
|
||||||
</style>
|
|
||||||
66
numbergame/src/components/game-bapp.vue
Normal file
66
numbergame/src/components/game-bapp.vue
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<Wallet />
|
||||||
|
<BettingComponent v-on:complete-choose-number="onCompleteChooseNum" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
import { mapGetters, mapMutations } from 'vuex'
|
||||||
|
import KlaytnService from '@/klaytn/klaytnService'
|
||||||
|
|
||||||
|
import Wallet from '@/components/wallet'
|
||||||
|
import BettingComponent from '@/components/betting-component'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'game-bapp',
|
||||||
|
components: {
|
||||||
|
Wallet,
|
||||||
|
BettingComponent
|
||||||
|
},
|
||||||
|
async mounted () {
|
||||||
|
await this.connect()
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
...mapGetters('wallet', [
|
||||||
|
'klaytn',
|
||||||
|
'myaddress'
|
||||||
|
])
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
...mapMutations('wallet', [
|
||||||
|
'setKlaytn',
|
||||||
|
'setIsConnectWallet',
|
||||||
|
'setMyAddress',
|
||||||
|
'setBalance'
|
||||||
|
]),
|
||||||
|
|
||||||
|
async connect () {
|
||||||
|
const klaytn = new KlaytnService()
|
||||||
|
this.setKlaytn(klaytn)
|
||||||
|
const address = await klaytn.init()
|
||||||
|
|
||||||
|
if (address) {
|
||||||
|
this.setMyAddress(address)
|
||||||
|
|
||||||
|
this.getBalance()
|
||||||
|
this.setIsConnectWallet(true)
|
||||||
|
} else {
|
||||||
|
this.setIsConnectWallet(false)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async getBalance () {
|
||||||
|
if (this.myaddress) {
|
||||||
|
const balance = await this.klaytn.getBalance(this.myaddress)
|
||||||
|
console.log(this.myaddress, balance)
|
||||||
|
this.setBalance(balance)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onCompleteChooseNum () {
|
||||||
|
this.getBalance()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
151
numbergame/src/components/wallet.vue
Normal file
151
numbergame/src/components/wallet.vue
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<h2>Connect to Wallet</h2>
|
||||||
|
<div>
|
||||||
|
<template v-if="walletInstance">
|
||||||
|
<div>
|
||||||
|
<h2>Integrated</h2>
|
||||||
|
<div class="balance">Balance: {{balance}} Klay</div>
|
||||||
|
<div class="address">{{walletInstance.address}}</div>
|
||||||
|
<button class="btnSubmit" @click="this.handleRemoveWallet">REMOVE WALLET</button>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<template v-else>
|
||||||
|
<div>
|
||||||
|
<label for="keystore">Keystore:</label>
|
||||||
|
<input type="file" name="keystore" v-on:change="this.handleImport" />
|
||||||
|
|
||||||
|
<label for="password">Password:</label>
|
||||||
|
<input
|
||||||
|
name="password"
|
||||||
|
v-model="password"
|
||||||
|
type="password"
|
||||||
|
required
|
||||||
|
></input>
|
||||||
|
|
||||||
|
<h3>OR</h3>
|
||||||
|
|
||||||
|
<label for="privateKey">Private Key:</label>
|
||||||
|
<input
|
||||||
|
v-model="privateKey"
|
||||||
|
name="privateKey"
|
||||||
|
type="password"
|
||||||
|
required
|
||||||
|
></input>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<button class="btnSubmit" @click="this.handleAddWallet">ADD WALLET</button>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { mapGetters, mapMutations } from 'vuex'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data: () => ({
|
||||||
|
// accessType: 'keystore',
|
||||||
|
keystore: null,
|
||||||
|
password: '',
|
||||||
|
privateKey: null,
|
||||||
|
walletInstance: null
|
||||||
|
}),
|
||||||
|
computed: {
|
||||||
|
...mapGetters('wallet', [
|
||||||
|
'klaytn',
|
||||||
|
'balance'
|
||||||
|
])
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
...mapMutations('wallet', [
|
||||||
|
'setIsConnectWallet',
|
||||||
|
'setMyAddress',
|
||||||
|
'setBalance'
|
||||||
|
]),
|
||||||
|
|
||||||
|
validate () {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
handleImport (e) {
|
||||||
|
const keystore = e.target.files[0]
|
||||||
|
|
||||||
|
const fileReader = new FileReader()
|
||||||
|
fileReader.onload = (e) => {
|
||||||
|
try {
|
||||||
|
if (!this.checkValidKeystore(e.target.result)) {
|
||||||
|
// If key store file is invalid, show message "Invalid keystore file."
|
||||||
|
alert('Invalid keystore file.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.keystore = e.target.result
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
alert('Invalid keystore file.')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fileReader.readAsText(keystore)
|
||||||
|
},
|
||||||
|
|
||||||
|
async handleAddWallet () {
|
||||||
|
try {
|
||||||
|
// Access type2: access thorugh private key
|
||||||
|
if(this.privateKey) {
|
||||||
|
await this.klaytn.integrateWallet(this.privateKey)
|
||||||
|
} else {
|
||||||
|
// Access type1: access through keystore + password
|
||||||
|
await this.klaytn.loginWithKeystore(this.keystore, this.password)
|
||||||
|
}
|
||||||
|
this.getWalletInfo()
|
||||||
|
} catch (e) {
|
||||||
|
alert(`Password or private key doesn't match.`)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async getWalletInfo () {
|
||||||
|
this.walletInstance = this.klaytn.getWallet()
|
||||||
|
const address = this.walletInstance.address
|
||||||
|
if(address) {
|
||||||
|
this.setMyAddress(address)
|
||||||
|
const balance = await this.klaytn.getBalance(address)
|
||||||
|
this.setBalance(balance)
|
||||||
|
this.setIsConnectWallet(true)
|
||||||
|
} else {
|
||||||
|
this.setIsConnectWallet(false)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
checkValidKeystore (keystore) {
|
||||||
|
const parsedKeystore = JSON.parse(keystore)
|
||||||
|
const isValidKeystore = parsedKeystore.version &&
|
||||||
|
parsedKeystore.id &&
|
||||||
|
parsedKeystore.address &&
|
||||||
|
parsedKeystore.crypto
|
||||||
|
|
||||||
|
return isValidKeystore
|
||||||
|
},
|
||||||
|
|
||||||
|
async handleRemoveWallet () {
|
||||||
|
this.klaytn.removeWallet()
|
||||||
|
this.setIsConnectWallet(false)
|
||||||
|
this.walletInstance = null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
if(this.klaytn) {
|
||||||
|
this.walletInstance = this.klaytn.getWallet()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
|
||||||
|
</style>
|
||||||
27
numbergame/src/klaytn/caver.js
Normal file
27
numbergame/src/klaytn/caver.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* caver-js library helps making connection with klaytn node.
|
||||||
|
* You can connect to specific klaytn node by setting 'rpcURL' value.
|
||||||
|
* default rpcURL is 'https://api.baobab.klaytn.net:8651'.
|
||||||
|
*/
|
||||||
|
import Caver from 'caver-js'
|
||||||
|
|
||||||
|
const deployedABI = require('./deployedABI.json')
|
||||||
|
|
||||||
|
const TEST_NET = 'https://api.baobab.klaytn.net:8651'
|
||||||
|
|
||||||
|
export const config = {
|
||||||
|
rpcURL: TEST_NET
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEPLOYED_ADDRESS = '0xa3e9E54627C6B7ED0986E5A9d1ecd7f8A0D013f2' // testnet
|
||||||
|
|
||||||
|
const cav = new Caver(config.rpcURL)
|
||||||
|
|
||||||
|
const getContractInstance = () => {
|
||||||
|
const contractInstance = deployedABI
|
||||||
|
&& DEPLOYED_ADDRESS
|
||||||
|
&& new cav.klay.Contract(deployedABI, DEPLOYED_ADDRESS)
|
||||||
|
return contractInstance
|
||||||
|
}
|
||||||
|
|
||||||
|
export {cav, getContractInstance}
|
||||||
@@ -1,19 +1,4 @@
|
|||||||
const address = '0x3bc507d62132520239a96a1c40b00086efbf3bf3'
|
[
|
||||||
const ABI = [
|
|
||||||
{
|
|
||||||
"constant": false,
|
|
||||||
"inputs": [
|
|
||||||
{
|
|
||||||
"name": "_num",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"name": "bet",
|
|
||||||
"outputs": [],
|
|
||||||
"payable": true,
|
|
||||||
"stateMutability": "payable",
|
|
||||||
"type": "function"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"constant": false,
|
"constant": false,
|
||||||
"inputs": [],
|
"inputs": [],
|
||||||
@@ -23,15 +8,25 @@ const ABI = [
|
|||||||
"stateMutability": "nonpayable",
|
"stateMutability": "nonpayable",
|
||||||
"type": "function"
|
"type": "function"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"constant": false,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "_num",
|
||||||
|
"type": "uint256"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"name": "play",
|
||||||
|
"outputs": [],
|
||||||
|
"payable": true,
|
||||||
|
"stateMutability": "payable",
|
||||||
|
"type": "function"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"inputs": [
|
"inputs": [
|
||||||
{
|
{
|
||||||
"name": "_minBet",
|
"name": "_minBet",
|
||||||
"type": "uint256"
|
"type": "uint256"
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "_winRate",
|
|
||||||
"type": "uint256"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"payable": true,
|
"payable": true,
|
||||||
@@ -88,5 +83,4 @@ const ABI = [
|
|||||||
"stateMutability": "view",
|
"stateMutability": "view",
|
||||||
"type": "function"
|
"type": "function"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
export {address, ABI}
|
|
||||||
97
numbergame/src/klaytn/klaytnService.js
Normal file
97
numbergame/src/klaytn/klaytnService.js
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
import { cav, getContractInstance } from './caver'
|
||||||
|
|
||||||
|
export default class KlaytnService {
|
||||||
|
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
async init () {
|
||||||
|
const walletFromSession = sessionStorage.getItem('walletInstance')
|
||||||
|
|
||||||
|
// If 'walletInstance' value exists, add it to caver's wallet
|
||||||
|
if (walletFromSession) {
|
||||||
|
try {
|
||||||
|
const address = JSON.parse(walletFromSession).address
|
||||||
|
cav.klay.accounts.wallet.add(JSON.parse(walletFromSession))
|
||||||
|
|
||||||
|
return address
|
||||||
|
} catch (e) {
|
||||||
|
// If value in sessionStorage is invalid wallet instance,
|
||||||
|
// remove it from sessionStorage.
|
||||||
|
sessionStorage.removeItem('walletInstance')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getBlockNumber () {
|
||||||
|
const blockNumber = await cav.klay.getBlockNumber()
|
||||||
|
return blockNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
async getBalance (address) {
|
||||||
|
const balance = await cav.klay.getBalance(address)
|
||||||
|
return cav.utils.fromPeb(balance, "KLAY")
|
||||||
|
}
|
||||||
|
|
||||||
|
async loginWithKeystore (keystore, password) {
|
||||||
|
const { privateKey: privateKeyFromKeystore } = cav.klay.accounts.decrypt(keystore, password)
|
||||||
|
await this.integrateWallet(privateKeyFromKeystore)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
integrateWallet (privateKey) {
|
||||||
|
const walletInstance = cav.klay.accounts.privateKeyToAccount(privateKey)
|
||||||
|
cav.klay.accounts.wallet.add(walletInstance)
|
||||||
|
sessionStorage.setItem('walletInstance', JSON.stringify(walletInstance))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
removeWallet () {
|
||||||
|
cav.klay.accounts.wallet.clear()
|
||||||
|
sessionStorage.removeItem('walletInstance')
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
getWallet () {
|
||||||
|
if (cav.klay.accounts.wallet.length) {
|
||||||
|
return cav.klay.accounts.wallet[0]
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
play (number, amount, dispatch, errorCb) {
|
||||||
|
const walletInstance = cav.klay.accounts.wallet && cav.klay.accounts.wallet[0]
|
||||||
|
|
||||||
|
if (!walletInstance) {
|
||||||
|
console.log('no walletInstance')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
amount = cav.utils.toPeb(amount, "KLAY")
|
||||||
|
|
||||||
|
const address = walletInstance.address
|
||||||
|
getContractInstance().methods.play(number).send({
|
||||||
|
from: address,
|
||||||
|
gas: '100000000',
|
||||||
|
value: amount
|
||||||
|
})
|
||||||
|
.once('transactionHash', (txHash) => {
|
||||||
|
console.log(`
|
||||||
|
Sending a transaction...
|
||||||
|
txHash: ${txHash}
|
||||||
|
`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.once('receipt', (receipt) => {
|
||||||
|
console.log(`
|
||||||
|
Received receipt! (#${receipt.blockNumber} ,${receipt.transactionHash})
|
||||||
|
`, receipt)
|
||||||
|
|
||||||
|
dispatch(receipt)
|
||||||
|
})
|
||||||
|
.once('error', (error) => {
|
||||||
|
errorCb(error.message)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
import router from './router'
|
import router from './router'
|
||||||
import { store } from './store/'
|
import store from './store'
|
||||||
|
|
||||||
Vue.config.productionTip = false
|
Vue.config.productionTip = false
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
import Web3 from 'web3'
|
|
||||||
import {address, ABI} from './betContract'
|
|
||||||
const getContract = new Promise(function (resolve, reject) {
|
|
||||||
const web3 = new Web3(window.web3.currentProvider)
|
|
||||||
const betContract = web3.eth.contract(ABI)
|
|
||||||
const betContractInstance = betContract.at(address)
|
|
||||||
resolve(betContractInstance)
|
|
||||||
})
|
|
||||||
export default getContract
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
import Web3 from 'web3'
|
|
||||||
|
|
||||||
const getWeb3 = new Promise(function (resolve, reject) {
|
|
||||||
const web3js = window.web3
|
|
||||||
if (typeof web3js !== 'undefined') {
|
|
||||||
const web3 = new Web3(web3js.currentProvider)
|
|
||||||
resolve({
|
|
||||||
injectedWeb3: web3.isConnected(),
|
|
||||||
web3 () {
|
|
||||||
return web3
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
reject(new Error('Unable to connect to Metamask'))
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(result => {
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
result.web3().version.getNetwork((err, networkId) => {
|
|
||||||
if (err) {
|
|
||||||
reject(new Error('Unable to retrieve network ID'))
|
|
||||||
} else {
|
|
||||||
result = {...result, networkId}
|
|
||||||
resolve(result)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.then(result => {
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
result.web3().eth.getCoinbase((err, coinbase) => {
|
|
||||||
if (err) {
|
|
||||||
reject(new Error('Unable to retrieve coinbase'))
|
|
||||||
} else {
|
|
||||||
result = {...result, coinbase}
|
|
||||||
resolve(result)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.then(result => {
|
|
||||||
return new Promise(function (resolve, reject) {
|
|
||||||
result.web3().eth.getBalance(result.coinbase, (err, balance) => {
|
|
||||||
if (err) {
|
|
||||||
reject(new Error('Unable to retrieve balance for address: ' + result.coinbase))
|
|
||||||
} else {
|
|
||||||
result = {...result, balance}
|
|
||||||
resolve(result)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
export default getWeb3
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
export const NETWORKS = {
|
|
||||||
'1': 'Main Net',
|
|
||||||
'2': 'Deprecated Morden test network',
|
|
||||||
'3': 'Ropsten test network',
|
|
||||||
'4': 'Rinkeby test network',
|
|
||||||
'42': 'Kovan test network',
|
|
||||||
'4447': 'Truffle Develop Network',
|
|
||||||
'5777': 'Ganache Blockchain'
|
|
||||||
}
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
import Web3 from 'web3'
|
|
||||||
import {store} from '../store/'
|
|
||||||
|
|
||||||
const pollWeb3 = function (state) {
|
|
||||||
let web3 = window.web3
|
|
||||||
web3 = new Web3(web3.currentProvider)
|
|
||||||
|
|
||||||
setInterval(() => {
|
|
||||||
if (!web3 || !store.state.web3.web3Instance) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (web3.eth.coinbase !== store.state.web3.coinbase) {
|
|
||||||
const newCoinbase = web3.eth.coinbase
|
|
||||||
web3.eth.getBalance(web3.eth.coinbase, function (err, newBalance) {
|
|
||||||
if (err) {
|
|
||||||
console.error(err)
|
|
||||||
} else {
|
|
||||||
store.dispatch('updateWeb3', {
|
|
||||||
coinbase: newCoinbase,
|
|
||||||
balance: parseInt(newBalance, 10)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
web3.eth.getBalance(store.state.web3.coinbase, (err, newBalance) => {
|
|
||||||
if (err) {
|
|
||||||
console.log(err)
|
|
||||||
} else if (parseInt(newBalance, 10) !== store.state.web3.balance) {
|
|
||||||
store.dispatch('updateWeb3', {
|
|
||||||
coinbase: store.state.web3.coinbase,
|
|
||||||
balance: newBalance
|
|
||||||
})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}, 700)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default pollWeb3
|
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import Router from 'vue-router'
|
import Router from 'vue-router'
|
||||||
import BettingDapp from '@/components/betting-dapp'
|
import GameBapp from '@/components/game-bapp'
|
||||||
Vue.use(Router)
|
Vue.use(Router)
|
||||||
|
|
||||||
export default new Router({
|
export default new Router({
|
||||||
routes: [
|
routes: [
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
name: 'betting-dapp',
|
name: 'game-bapp',
|
||||||
component: BettingDapp
|
component: GameBapp
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,58 +1,12 @@
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import Vuex from 'vuex'
|
import Vuex from 'vuex'
|
||||||
import state from './state'
|
|
||||||
import getWeb3 from '../network/getWeb3'
|
import wallet from '@/store/modules/wallet'
|
||||||
import pollWeb3 from '../network/pollWeb3'
|
|
||||||
import getContract from '../network/getContract'
|
|
||||||
|
|
||||||
Vue.use(Vuex)
|
Vue.use(Vuex)
|
||||||
export const store = new Vuex.Store({
|
|
||||||
strict: true,
|
|
||||||
state,
|
|
||||||
mutations: {
|
|
||||||
registerWeb3Instance (state, data) {
|
|
||||||
console.log('registerWeb3instance', data)
|
|
||||||
const result = data
|
|
||||||
let newWeb3 = state.web3
|
|
||||||
newWeb3.coinbase = result.coinbase
|
|
||||||
newWeb3.networkId = result.networkId
|
|
||||||
newWeb3.balance = parseInt(result.balance, 10)
|
|
||||||
newWeb3.isInjected = result.injectedWeb3
|
|
||||||
newWeb3.web3Instance = result.web3
|
|
||||||
state.web3 = newWeb3
|
|
||||||
pollWeb3()
|
|
||||||
},
|
|
||||||
|
|
||||||
updateWeb3Instance (state, data) {
|
export default new Vuex.Store({
|
||||||
console.log('updateWeb3Instance', data)
|
modules: {
|
||||||
state.web3.coinbase = data.coinbase
|
wallet
|
||||||
state.web3.balance = parseInt(data.balance, 10)
|
}
|
||||||
},
|
|
||||||
|
|
||||||
registerContractInstance (state, data) {
|
|
||||||
console.log('contract instance: ', data)
|
|
||||||
state.contractInstance = () => data
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
registerWeb3 ({commit}) {
|
|
||||||
getWeb3.then(result => {
|
|
||||||
console.log('commit result')
|
|
||||||
commit('registerWeb3Instance', result)
|
|
||||||
}).catch(e => {
|
|
||||||
console.error('error', e)
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
updateWeb3 ({commit}, data) {
|
|
||||||
commit('updateWeb3Instance', data)
|
|
||||||
},
|
|
||||||
|
|
||||||
getContractInstance ({commit}) {
|
|
||||||
getContract.then(result => {
|
|
||||||
commit('registerContractInstance', result)
|
|
||||||
}).catch(e => console.log(e))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|||||||
41
numbergame/src/store/modules/wallet.js
Normal file
41
numbergame/src/store/modules/wallet.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
|
||||||
|
const state = {
|
||||||
|
klaytn: null,
|
||||||
|
isConnectWallet: false,
|
||||||
|
myaddress: '',
|
||||||
|
balance: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const getters = {
|
||||||
|
klaytn: (state) => state.klaytn,
|
||||||
|
isConnectWallet: (state) => state.isConnectWallet,
|
||||||
|
myaddress: (state) => state.myaddress,
|
||||||
|
balance: (state) => state.balance
|
||||||
|
}
|
||||||
|
|
||||||
|
const mutations = {
|
||||||
|
setKlaytn(state, klaytn) {
|
||||||
|
state.klaytn = klaytn
|
||||||
|
},
|
||||||
|
setIsConnectWallet(state, isConnected) {
|
||||||
|
state.isConnectWallet = isConnected
|
||||||
|
},
|
||||||
|
setMyAddress(state, address) {
|
||||||
|
state.myaddress = address
|
||||||
|
},
|
||||||
|
setBalance(state, balance) {
|
||||||
|
state.balance = balance
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const actions = {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
namespaced: true,
|
||||||
|
state,
|
||||||
|
getters,
|
||||||
|
actions,
|
||||||
|
mutations
|
||||||
|
}
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
const state = {
|
|
||||||
web3: {
|
|
||||||
isInjected: false,
|
|
||||||
web3Instance: null,
|
|
||||||
networkId: null,
|
|
||||||
coinbase: null,
|
|
||||||
balance: null,
|
|
||||||
error: null
|
|
||||||
},
|
|
||||||
contractInstance: null
|
|
||||||
}
|
|
||||||
export default state
|
|
||||||
Reference in New Issue
Block a user