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

[#9] Support API key #12

Merged
merged 27 commits into from
Aug 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
9108270
Remove vue configs for cors
daenamkim Jul 27, 2020
0c82101
Remove cookie jar
daenamkim Jul 27, 2020
8d8347e
Replace login with api key
daenamkim Jul 27, 2020
dab15a8
Add to create axios instance
daenamkim Jul 27, 2020
389762b
Remove unused package
daenamkim Jul 27, 2020
482fc8b
Fix api call logic
daenamkim Jul 27, 2020
beb07af
Upgrade ethers
daenamkim Jul 27, 2020
b113f6c
Fix send transaction failed!
daenamkim Jul 27, 2020
9c48418
Refactor api call
daenamkim Jul 27, 2020
5a1f9ab
Remove host and api key (instance also removed)
daenamkim Jul 27, 2020
23cca8e
Update gitignore
daenamkim Jul 27, 2020
af74e6d
Install testcafe and mock3 and add more running scripts
daenamkim Jul 27, 2020
f35c12a
Update eslint rules
daenamkim Jul 27, 2020
1f1fd24
Add testcafe configs
daenamkim Jul 27, 2020
faecf83
Add test spec and model
daenamkim Jul 27, 2020
283419e
Change result
daenamkim Jul 27, 2020
813b683
Add mock3 configs
daenamkim Jul 27, 2020
5985f2c
Add consts for mok3
daenamkim Jul 27, 2020
5aeb2c1
Update readme and refactor
daenamkim Jul 27, 2020
24223e8
Fix eslint
daenamkim Jul 27, 2020
80c93a0
Improve diction on config parameter comments
william Aug 24, 2020
fd6de06
Add API, CORS, and testing instructions to README
william Aug 24, 2020
d26888b
Fix tests - allow for decimals and zero initial value
william Aug 24, 2020
291ddc3
Add cautions to README
william Aug 24, 2020
0959858
Add more cautions to private key config
william Aug 24, 2020
89693db
Remove unnecessary dependency on web3 to get balance
william Aug 24, 2020
422e4ef
Remove blockchain write (mint) test for safety
william Aug 24, 2020
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
4 changes: 4 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,8 @@ module.exports = {
parserOptions: {
parser: 'babel-eslint',
},
globals: {
'fixture': false,
'test': false,
},
};
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.DS_Store
node_modules
/dist
/tests/screenshots

# local env files
.env.local
Expand Down
11 changes: 11 additions & 0 deletions .testcaferc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"browsers": ["chrome:headless", "firefox:headless", "chrome:userProfile", "firefox:userProfile", "safari", "opera"],
"src": ["tests/*.spec.js", "!tests/models.js"],
"selectorTimeout": 10000,
"assertionTimeout": 3000,
"appInitDelay": 3000,
"screenshots": {
"path": "tests/screenshots",
"takeOnFails": true
}
}
53 changes: 35 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,53 @@
# vue-dapp-sample
# Vue DApp Sample

## Project configuration
In `vue.config.js`, update the value of `instanceURL` to point to your MultiBaas instance. Note that the URL must begin with `https://` and end with `/`.
## MultiBaas configuration

In `App.vue`, set the values of `apiUser` and `apiPassword` to your MultiBaas username and password respectively.
1. **Deployment**
- You will need to [create a MultiBaas deployment](https://www.curvegrid.com/docs/3-0-getting-started-creating-a-multibaas-deployment/) or have an existing deployment to use this sample.
2. **API Key**
- You will also need to [provision an API key](https://www.curvegrid.com/docs/5-1-generate-api-keys/) with membership in the `DApp User` group.
3. **Mlti Token Contract**
- You will need to [deploy a `Mlti Token` contract](https://www.curvegrid.com/docs/4-3-deploy-a-smart-contract/) using the label `mltitoken`.
4. **CORS Configuration**
- Finally, you will need to update your CORS settings by going to `Admin` then `CORS Domains` and setting up the domain of the sample app. If you are running locally this will be `http://localhost:8080` by default.

After you have configured your deployment and smart contract, please fill out the required parameters below in `App.vue`:

- `BASE_URL`
- `API_KEY`

## Project setup
```

```sh
yarn install
```

### Compiles and hot-reloads for development
```
### Compile and hot-reload for development

```sh
yarn run serve
```

After serving the app, please make sure that the URL the application is served is equal to the value of `baseURL` in `App.vue`
### Compile and minify for production

### Compiles and minifies for production
```
```sh
yarn run build
```

### Run your tests
```
yarn run test
```
### Lint and fix files

### Lints and fixes files
```
```sh
yarn run lint
```

### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).
## UI tests

These tests will run against the above configured server and deployed MltiToken contract.

You **must stop any currently running server**, i.e. Ctrl-C out of `yarn run serve`.

You can then run the tests with the following command:

```sh
yarn run test
```
10 changes: 6 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
"lint": "vue-cli-service lint",
"serve:test": "vue-cli-service serve --mode test",
"test": "testcafe -a 'yarn serve:test' chrome"
},
"dependencies": {
"@3846masa/axios-cookiejar-support": "^0.4.2",
"axios": "^0.19.0",
"core-js": "^2.6.5",
"ethers": "^4.0.29",
"tough-cookie": "^3.0.1",
"ethers": "^4.0.47",
"mock3": "^0.1.0",
"testcafe": "^1.8.8",
"vue": "^2.6.10"
},
"devDependencies": {
Expand Down
66 changes: 25 additions & 41 deletions src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,38 @@
<div id="app">
<button @click="getTotalSupply">Get Total MltiToken Supply</button>
<form v-on:submit.prevent>
<input type="text" placeholder="Number of Tokens to Mint" v-model="tokenAmount" />
<button prevent="submit" @click="mintTokens">Mint Tokens</button>
<p>
<input type="text" placeholder="Number of Tokens to Mint" v-model="tokenAmount" />
</p>
<p>
<button prevent="submit" @click="mintTokens">Mint Tokens</button>
</p>
</form>
<hr />
<pre v-if="response">{{ response | prettyJSON }}</pre>
<pre>{{ response | prettyJSON }}</pre>
</div>
</template>

<script>
import axios from 'axios';
import axiosCookieJarSupport from '@3846masa/axios-cookiejar-support';
import tough from 'tough-cookie';
// [REQUIRED] Server URL
const BASE_URL = '';

axiosCookieJarSupport(axios);

// Automatically store the cookie returned by the MultiBaas server
axios.defaults.jar = new tough.CookieJar();
// Automatically include the stored cookie in requests being made to the MultiBaas server
axios.defaults.withCredentials = true;

// The local address where the demo app will be served
const baseURL = 'https://localhost:8080/';

// Configure these values with your MultiBaas login information
const apiUser = '';
const apiPassword = '';
// [REQUIRED] Server API key
const API_KEY = '';

// The deployed contract's address, or the label you assigned it in MultiBaas
// [CAN BE REPLACED]
const CONTRACT_LABEL_OR_ADDRESS = 'mltitoken';

export default {
name: 'app',
components: {
},
data() {
return {
response: '',
tokenAmount: '',
tokenAmount: '10',
axios: null,
};
},
filters: {
Expand All @@ -54,7 +49,7 @@ export default {
}

this.connectToWeb3();
this.login();
this.axios = this.$root.$_cgutils.createAxiosInstance(BASE_URL, API_KEY);
},
methods: {
// We must init the web3 provider so that we can sign transactions
Expand All @@ -68,42 +63,31 @@ export default {
const accounts = await this.$root.$_web3.listAccounts();
return accounts[0];
},
async login() {
try {
await axios.post(`${baseURL}api/v0/login`,
{
email: apiUser,
password: apiPassword,
});
} catch (err) {
console.log(err);
}
},
async getTotalSupply() {
try {
const { data } = await axios.get(`${baseURL}api/v0/chains/ethereum/contracts/mltitoken/addresses/${CONTRACT_LABEL_OR_ADDRESS}/totalSupply`);
const { data } = await this.axios.post(
`/api/v0/chains/ethereum/addresses/${CONTRACT_LABEL_OR_ADDRESS}/contracts/mltitoken/methods/totalSupply`,
);
this.response = data;
} catch (err) {
console.log(err);
}
},
async mintTokens() {
try {
const ETH_SIGNER = await this.getActiveAccount();
const account = await this.getActiveAccount();
const jsonBody = {
args: {
_amount: this.tokenAmount,
},
from: ETH_SIGNER,
signer: ETH_SIGNER,
args: [`${this.tokenAmount}`],
from: account,
signer: account,
};

const {
data: {
result: { tx, submitted },
},
} = await axios.post(
`${baseURL}api/v0/chains/ethereum/contracts/mltitoken/addresses/${CONTRACT_LABEL_OR_ADDRESS}/mint`,
} = await this.axios.post(
`/api/v0/chains/ethereum/addresses/${CONTRACT_LABEL_OR_ADDRESS}/contracts/mltitoken/methods/mint`,
jsonBody,
);

Expand Down
18 changes: 16 additions & 2 deletions src/js/cgutils.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable no-param-reassign */
import { ethers } from 'ethers';
import { ethers, utils } from 'ethers';
import axios from 'axios';

export default {
install: (Vue) => {
Expand All @@ -11,12 +12,14 @@ export default {
formatEthersTx(txFromAPI) {
const tx = JSON.parse(JSON.stringify(txFromAPI));
tx.gasLimit = tx.gas;
tx.gasPrice = utils.bigNumberify(tx.gasPrice);
tx.value = utils.bigNumberify(tx.value);
delete tx.gas;
delete tx.from;
delete tx.hash;
return tx;
},
connectToWeb3(browserHook) {
connectToWeb3(browserHook, jsonRpc = '', signerPrivateKey = '') {
const result = {
provider: null,
web3Available: false,
Expand All @@ -32,6 +35,17 @@ export default {
}
return result;
},
createAxiosInstance(baseURL, apiKey) {
return axios.create({
baseURL,
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
withCredentials: true,
timeout: 1000,
});
},
};
},
};
11 changes: 11 additions & 0 deletions tests/models.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { Selector } from 'testcafe';

// eslint-disable-next-line import/prefer-default-export
export class TokenView {
constructor() {
this.buttonGetTotalSupply = Selector('button').withText('Get Total MltiToken Supply');
this.buttonMintTokens = Selector('button').withText('Mint Tokens');
this.inputTokens = Selector('input');
this.response = Selector('pre');
}
}
54 changes: 54 additions & 0 deletions tests/token.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { TokenView } from './models';

const tokenView = new TokenView();
const host = 'http://localhost:8080';

const extractAmount = (raw) => {
try {
const parsed = JSON.parse(raw);
return parseInt(parsed.result.output, 10);
} catch (e) {
return -1;
}
};

// eslint-disable-next-line no-unused-expressions
fixture`Multi Token`
.page`${host}`;

test('should get total supply', async (t) => {
await t
.click(tokenView.buttonGetTotalSupply)
.expect(tokenView.response.innerText)
.match(new RegExp('"output": "[0-9\.]+"'));

const amount = extractAmount(await tokenView.response.innerText);
await t
.expect(amount)
.notEql(-1);
});

// This test is disabled. It can be made to work by importing Mock3 and
// supplying it with a private key but there is currently no safe way to
// configure that. Caveat machinator.
test.skip('should mint tokens', async (t) => {
await t.click(tokenView.buttonGetTotalSupply);
const amountBefore = extractAmount(await tokenView.response.innerText);

await t
.typeText(
tokenView.inputTokens,
'1',
{ paste: true, replace: true },
)
.click(tokenView.buttonMintTokens)
.expect(tokenView.response.innerText)
.match(new RegExp('"hash": "0x[a-f0-9]{64}"'));

// Compare "after" to "before" and "after" should be greater
await t.click(tokenView.buttonGetTotalSupply);
const amountAfter = extractAmount(await tokenView.response.innerText);
await t
.expect(amountAfter)
.gt(amountBefore);
});
25 changes: 0 additions & 25 deletions vue.config.js

This file was deleted.

Loading