create-near-app 5.0.1 → 5.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-near-app",
3
- "version": "5.0.1",
3
+ "version": "5.1.1",
4
4
  "description": "Quickly scaffold your dApp on NEAR Blockchain",
5
5
  "main": "index.js",
6
6
  "engines": {
@@ -6,14 +6,14 @@ import './assets/global.css';
6
6
  import { EducationalText, SignInPrompt, SignOutButton } from './ui-components';
7
7
 
8
8
 
9
- export default function App({ isSignedIn, contract, wallet }) {
9
+ export default function App({ isSignedIn, helloNEAR, wallet }) {
10
10
  const [valueFromBlockchain, setValueFromBlockchain] = React.useState();
11
11
 
12
12
  const [uiPleaseWait, setUiPleaseWait] = React.useState(true);
13
13
 
14
14
  // Get blockchian state once on component load
15
15
  React.useEffect(() => {
16
- contract.getGreeting()
16
+ helloNEAR.getGreeting()
17
17
  .then(setValueFromBlockchain)
18
18
  .catch(alert)
19
19
  .finally(() => {
@@ -31,8 +31,8 @@ export default function App({ isSignedIn, contract, wallet }) {
31
31
  e.preventDefault();
32
32
  setUiPleaseWait(true);
33
33
  const { greetingInput } = e.target.elements;
34
- contract.setGreeting(greetingInput.value)
35
- .then(async () => {return contract.getGreeting();})
34
+ helloNEAR.setGreeting(greetingInput.value)
35
+ .then(async () => {return helloNEAR.getGreeting();})
36
36
  .then(setValueFromBlockchain)
37
37
  .finally(() => {
38
38
  setUiPleaseWait(false);
@@ -1,21 +1,25 @@
1
+ // React
1
2
  import React from 'react';
2
- import { createRoot } from 'react-dom/client';
3
+ import ReactDOM from 'react-dom';
3
4
  import App from './App';
5
+
6
+ // NEAR
7
+ import { HelloNEAR } from './near-interface';
4
8
  import { Wallet } from './near-wallet';
5
- import { Contract } from './near-interface';
6
9
 
7
- const reactRoot = createRoot(document.querySelector('#root'));
10
+ // When creating the wallet you can optionally ask to create an access key
11
+ // Having the key enables to call non-payable methods without interrupting the user to sign
12
+ const wallet = new Wallet({ createAccessKeyFor: process.env.CONTRACT_NAME })
8
13
 
9
- // create the Wallet and the Contract
10
- const contractId = process.env.CONTRACT_NAME;
11
- const wallet = new Wallet({contractId: contractId});
12
- const contract = new Contract({wallet: wallet});
14
+ // Abstract the logic of interacting with the contract to simplify your flow
15
+ const helloNEAR = new HelloNEAR({ contractId: process.env.CONTRACT_NAME, walletToUse: wallet });
13
16
 
14
- window.onload = wallet.startUp()
15
- .then((isSignedIn) => {
16
- reactRoot.render(<App isSignedIn={isSignedIn} contract={contract} wallet={wallet} />);
17
- })
18
- .catch(e => {
19
- reactRoot.render(<div style={{color: 'red'}}>Error: <code>{e.message}</code></div>);
20
- console.error(e);
21
- });
17
+ // Setup on page load
18
+ window.onload = async () => {
19
+ const isSignedIn = await wallet.startUp()
20
+
21
+ ReactDOM.render(
22
+ <App isSignedIn={isSignedIn} helloNEAR={helloNEAR} wallet={wallet} />,
23
+ document.getElementById('root')
24
+ );
25
+ }
@@ -11,7 +11,6 @@
11
11
  "@babel/preset-env": "^7.18.2",
12
12
  "@babel/preset-react": "^7.17.12",
13
13
  "@types/node": "^18.6.2",
14
- "ava": "^4.2.0",
15
14
  "react-test-renderer": "^18.1.0",
16
15
  "ts-node": "^10.8.0",
17
16
  "typescript": "^4.7.2",
@@ -1,15 +1,16 @@
1
- export class Contract{
2
- wallet;
1
+ /* Talking with a contract often involves transforming data, we recommend you to encapsulate that logic into a class */
3
2
 
4
- constructor({wallet}){
5
- this.wallet = wallet;
3
+ export class HelloNEAR {
4
+ constructor({ contractId, walletToUse }) {
5
+ this.contractId = contractId;
6
+ this.wallet = walletToUse;
6
7
  }
7
8
 
8
- async getGreeting(){
9
- return await this.wallet.viewMethod({method: 'get_greeting'});
9
+ async getGreeting() {
10
+ return await this.wallet.viewMethod({ contractId: this.contractId, method: 'get_greeting' });
10
11
  }
11
-
12
- async setGreeting(greeting){
13
- return await this.wallet.callMethod({method: 'set_greeting', args:{message: greeting}});
12
+
13
+ async setGreeting(greeting) {
14
+ return await this.wallet.callMethod({ contractId: this.contractId, method: 'set_greeting', args: { message: greeting } });
14
15
  }
15
16
  }
@@ -1,3 +1,5 @@
1
+ /* A helper file that simplifies using the wallet selector */
2
+
1
3
  // near api js
2
4
  import { providers } from 'near-api-js';
3
5
 
@@ -19,28 +21,31 @@ const NO_DEPOSIT = '0';
19
21
  export class Wallet {
20
22
  walletSelector;
21
23
  wallet;
22
- accountId;
23
- contractId;
24
-
25
- constructor({contractId}){
26
- this.contractId = contractId;
24
+ network;
25
+ createAccessKeyFor;
26
+
27
+ constructor({ createAccessKeyFor = undefined, network = 'testnet' }) {
28
+ // Login to a wallet passing a contractId will create a local
29
+ // key, so the user skips signing non-payable transactions.
30
+ // Omitting the accountId will result in the user being
31
+ // asked to sign all transactions.
32
+ this.createAccessKeyFor = createAccessKeyFor
33
+ this.network = 'testnet'
27
34
  }
28
35
 
29
36
  // To be called when the website loads
30
37
  async startUp() {
31
38
  this.walletSelector = await setupWalletSelector({
32
- network: 'testnet',
39
+ network: this.network,
33
40
  modules: [setupMyNearWallet({ iconUrl: MyNearIconUrl }),
34
- setupLedger({ iconUrl: LedgerIconUrl })],
41
+ setupLedger({ iconUrl: LedgerIconUrl })],
35
42
  });
36
43
 
37
44
  const isSignedIn = this.walletSelector.isSignedIn();
38
45
 
39
46
  if (isSignedIn) {
40
- const { accounts } = this.walletSelector.store.getState();
41
-
42
47
  this.wallet = await this.walletSelector.wallet();
43
- this.accountId = accounts[0].accountId;
48
+ this.accountId = this.walletSelector.store.getState().accounts[0].accountId;
44
49
  }
45
50
 
46
51
  return isSignedIn;
@@ -49,19 +54,19 @@ export class Wallet {
49
54
  // Sign-in method
50
55
  signIn() {
51
56
  const description = 'Please select a wallet to sign in.';
52
- const modal = setupModal(this.walletSelector, { contractId: this.contractId, description });
57
+ const modal = setupModal(this.walletSelector, { contractId: this.createAccessKeyFor, description });
53
58
  modal.show();
54
59
  }
55
60
 
56
61
  // Sign-out method
57
62
  signOut() {
58
63
  this.wallet.signOut();
59
- this.wallet = this.accountId = this.contractId = null;
64
+ this.wallet = this.accountId = this.createAccessKeyFor = null;
60
65
  window.location.replace(window.location.origin + window.location.pathname);
61
66
  }
62
67
 
63
68
  // Make a read-only call to retrieve information from the network
64
- async viewMethod({ contractId = this.contractId, method, args = {} }) {
69
+ async viewMethod({ contractId, method, args = {} }) {
65
70
  const { network } = this.walletSelector.options;
66
71
  const provider = new providers.JsonRpcProvider({ url: network.nodeUrl });
67
72
 
@@ -76,12 +81,10 @@ export class Wallet {
76
81
  }
77
82
 
78
83
  // Call a method that changes the contract's state
79
- async callMethod({ contractId = this.contractId, method, args = {}, gas = THIRTY_TGAS, deposit = NO_DEPOSIT }) {
80
- const { accountId } = this.walletSelector.store.getState().accounts[0];
81
-
84
+ async callMethod({ contractId, method, args = {}, gas = THIRTY_TGAS, deposit = NO_DEPOSIT }) {
82
85
  // Sign a transaction with the "FunctionCall" action
83
86
  return await this.wallet.signAndSendTransaction({
84
- signerId: accountId,
87
+ signerId: this.accountId,
85
88
  receiverId: contractId,
86
89
  actions: [
87
90
  {
@@ -60,18 +60,20 @@
60
60
  </p>
61
61
  <ol>
62
62
  <li>
63
- Look in <code>./frontend/index.js</code> – you'll see <code>getGreeting</code>
64
- and <code>setGreeting</code> being called on <code>contract</code>.
63
+ Look in <code>index.js</code> and <code>near-api.js</code> – you'll see <code>get_greeting</code>
64
+ and <code>set_greeting</code> being called on <code>contract</code>.
65
65
  What's this?
66
66
  </li>
67
67
  <li>
68
68
  Ultimately, this <code>contract</code> code is defined in
69
- <code>./contract</code> – this is the source code for your
69
+ <code>assembly/index.ts</code> – this is the source code for your
70
70
  <a target="_blank" href="https://docs.near.org/docs/develop/contracts/overview">smart contract</a>.
71
71
  </li>
72
72
  <li>
73
- When you run <code>npm run dev</code>, the contract's code gets deployed
74
- to the NEAR testnet. You can see how this happens by looking in <code>package.json</code>.
73
+ When you run <code>npm run dev</code>, the code in
74
+ <code>assembly/index.ts</code> gets deployed to the NEAR testnet. You
75
+ can see how this happens by looking in <code>package.json</code> at the
76
+ <code>scripts</code> section to find the <code>dev</code> command.
75
77
  </li>
76
78
  </ol>
77
79
  <hr>
@@ -1,18 +1,21 @@
1
1
  import 'regenerator-runtime/runtime';
2
- import { Contract } from './near-interface';
3
2
  import { Wallet } from './near-wallet';
3
+ import { HelloNEAR } from './near-interface';
4
4
 
5
- // create the Wallet and the Contract
6
- const wallet = new Wallet({contractId: process.env.CONTRACT_NAME});
7
- const contract = new Contract({wallet: wallet});
5
+ // When creating the wallet you can optionally ask to create an access key
6
+ // Having the key enables to call non-payable methods without interrupting the user to sign
7
+ const wallet = new Wallet({ createAccessKeyFor: process.env.CONTRACT_NAME })
8
+
9
+ // Abstract the logic of interacting with the contract to simplify your flow
10
+ const helloNEAR = new HelloNEAR({ contractId: process.env.CONTRACT_NAME, walletToUse: wallet });
8
11
 
9
12
  // Setup on page load
10
13
  window.onload = async () => {
11
14
  let isSignedIn = await wallet.startUp();
12
15
 
13
- if(isSignedIn){
16
+ if (isSignedIn) {
14
17
  signedInFlow();
15
- }else{
18
+ } else {
16
19
  signedOutFlow();
17
20
  }
18
21
 
@@ -22,7 +25,7 @@ window.onload = async () => {
22
25
  // Button clicks
23
26
  document.querySelector('form').onsubmit = doUserAction;
24
27
  document.querySelector('#sign-in-button').onclick = () => { wallet.signIn(); };
25
- document.querySelector('#sign-out-button').onclick = () => { wallet.signOut(); };
28
+ document.querySelector('#sign-out-button').onclick = () => { wallet.signOut(); };
26
29
 
27
30
  // Take the new greeting and send it to the contract
28
31
  async function doUserAction(event) {
@@ -32,7 +35,7 @@ async function doUserAction(event) {
32
35
  document.querySelector('#signed-in-flow main')
33
36
  .classList.add('please-wait');
34
37
 
35
- await contract.setGreeting(greeting.value);
38
+ await helloNEAR.setGreeting(greeting.value);
36
39
 
37
40
  // ===== Fetch the data from the blockchain =====
38
41
  await fetchGreeting();
@@ -42,7 +45,7 @@ async function doUserAction(event) {
42
45
 
43
46
  // Get greeting from the contract on chain
44
47
  async function fetchGreeting() {
45
- const currentGreeting = await contract.getGreeting();
48
+ const currentGreeting = await helloNEAR.getGreeting();
46
49
 
47
50
  document.querySelectorAll('[data-behavior=greeting]').forEach(el => {
48
51
  el.innerText = currentGreeting;
@@ -7,10 +7,11 @@
7
7
  "build": "parcel build index.html --public-url ./"
8
8
  },
9
9
  "devDependencies": {
10
+ "env-cmd": "^10.1.0",
11
+ "events": "^3.3.0",
10
12
  "nodemon": "^2.0.16",
11
- "parcel": "^2.6.0",
12
- "process": "^0.11.10",
13
- "env-cmd": "^10.1.0"
13
+ "parcel": "^2.7.0",
14
+ "process": "^0.11.10"
14
15
  },
15
16
  "dependencies": {
16
17
  "@near-wallet-selector/core": "^7.0.0",
@@ -26,4 +27,4 @@
26
27
  "@near-wallet-selector/wallet-connect": "^7.0.0",
27
28
  "near-api-js": "^0.44.2"
28
29
  }
29
- }
30
+ }