-
Notifications
You must be signed in to change notification settings - Fork 214
Commit
Co-authored-by: Jamie Bertram <jamie.bertram@tweag.io>
- Loading branch information
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
# PAB-Nami simple demo | ||
|
||
This is a very simple demo application featuring the use of a browser/light wallet (Nami) alongside the PAB (Plutus Application Backend). | ||
|
||
## Context | ||
|
||
In this demo, we want to showcase a very minimal example of how to integrate the PAB with a light wallet. It uses the `PayToWallet` contract in the PAB which has *no* Plutus on-chain validation code. Therefore, we simply use the PAB to construct a partial/unbalanced transaction and make it available to a frontend application. It doesn't use a local Cardano node, nor the chain index. Here's an outline of the general interactions: | ||
|
||
1. The frontend application should have access to a light/browser wallet (in this case, Nami) | ||
2. The frontend application activates the `PayToWallet` contract throught the PAB. | ||
3. The frontend application calls the `PayToWallet` contract PAB endpoint with the recipient's payment key hash and stake key hash, and the amount to send in Lovelace. | ||
4. The PAB constructs a partial/unbalanced transaction and makes it available through it's contract instance's status endpoint. | ||
5. The frontend application fetches this partial/unbalanced transaction. It then balances it and signs it using the Nami wallet api. | ||
6. Finally, the frontend application submits the final transaction using the Nami wallet api (which in turn, uses the blockfrost API). | ||
|
||
## Run the demo | ||
|
||
The instructions were tested inside the `plutus-apps`'s `nix-shell`. | ||
|
||
The demo contains two parts: the PAB application in `plutus-pab/demo/pab-nami/pab` and the frontend application in `plutus-pab/demo/pab-nami/client` which interacts with the PAB and the Nami wallet. | ||
|
||
### Setup Nami wallet | ||
|
||
1. Install the Nami wallet browser extension (currently, the Nami wallet is only available in Chrome-based browsers) | ||
2. Setup your wallet password and seed phrase as required. | ||
3. Create a second account in your wallet in order to test the demo. | ||
4. In Nami wallet's `Settings > Network`, select the Cardano testnet. | ||
5. Add some funds to your main account using the [Cardano faucet](https://testnets.cardano.org/en/testnets/cardano/tools/faucet/) (when you have finished using your test tokens, please return them to the faucet following the instructions in their website). | ||
6. | ||
|
||
### Run the PAB | ||
|
||
From a command line interface, make sure you're in the root folder of the `plutus-apps` repository, and run the following commands: | ||
|
||
``` | ||
# 'Migrate' command to initialise the PAB database. | ||
$ cabal run plutus-pab:exe:plutus-pab-nami-demo -- migrate --config plutus-pab/demo/pab-nami/pab/config.yaml | ||
# Run the PAB webserver | ||
$ cabal run plutus-pab:exe:plutus-pab-nami-demo -- webserver --config plutus-pab/demo/pab-nami/pab/config.yaml | ||
``` | ||
|
||
### Run the demo frontend | ||
|
||
From another command line interface, run the following command to launch the frontend application: | ||
|
||
``` | ||
$ cd plutus-pab/demo/pab-nami/client | ||
# To install NPM dependencies | ||
$ npm install | ||
# To install Spago dependencies | ||
$ spago install | ||
# Run the dev server | ||
$ npm run build:webpack:dev | ||
``` | ||
|
||
Open the browser with the frontend application's URL (`http://localhost:8009`). You will see two fields: the recipient's Bech32 Cardano address and an amount to send to it in Lovelace. From the Nami wallet interface, change to your *second* account, click on the `Receive` tab, copy the shown Cardano address and paste it in the application's form. Then, go back to your *first* account which contains your funds. Choose a lovelace amount (minimum of 2_000_000 Lovelace) and click on `Make payment`. The application should show the transaction id that was submitted to the Cardano testnet. After waiting for a bit, you should see the funds change in Nami wallet's interface. | ||
|
||
## Development | ||
|
||
### Frontend | ||
|
||
The frontend is written in Purescript. When inserting new dependencies in `spago.dhall`, run `spago install` and `spago2nix generate`. Don't forget to commit the file changes. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
/bower_components/ | ||
/node_modules/ | ||
/.pulp-cache/ | ||
/output/ | ||
/generated-docs/ | ||
/.psc-package/ | ||
/.psc* | ||
/.purs* | ||
/.psa* | ||
/.spago |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
{ pkgs, gitignore-nix, haskell, webCommon, buildPursPackage, buildNodeModules, filterNpm }: | ||
let | ||
pab-nami-demo-invoker = haskell.packages.plutus-pab.components.exes.plutus-pab-nami-demo; | ||
|
||
pab-setup-invoker = haskell.packages.plutus-pab.components.exes.plutus-pab-setup; | ||
|
||
# TODO: Use the PS generator in the demo app | ||
# generated-purescript = pkgs.runCommand "pab-nami-demo-purescript" { } '' | ||
# mkdir $out | ||
# ${pab-setup-invoker}/bin/plutus-pab-setup psgenerator $out | ||
# ln -s ${../pab/config.yaml} plutus-pab.yaml | ||
# ${pab-nami-demo-invoker}/bin/plutus-pab-nami-demo --config plutus-pab.yaml psapigenerator $out | ||
# ''; | ||
|
||
# generate-purescript = pkgs.writeShellScriptBin "pab-nami-demo-generate-purs" '' | ||
# generatedDir=./generated | ||
# rm -rf $generatedDir | ||
# $(nix-build ../default.nix -A marlowe-dashboard.pab-setup-invoker)/bin/plutus-pab-setup psgenerator $generatedDir | ||
# $(nix-build ../default.nix -A marlowe-dashboard.marlowe-invoker)/bin/marlowe-pab --config plutus-pab.yaml psapigenerator $generatedDir | ||
# ''; | ||
|
||
# start-backend = pkgs.writeShellScriptBin "marlowe-pab-server" '' | ||
# echo "marlowe-pab-server: for development use only" | ||
# $(nix-build ../default.nix --quiet --no-build-output -A marlowe-dashboard.marlowe-invoker)/bin/marlowe-pab --config plutus-pab.yaml all-servers | ||
# ''; | ||
|
||
cleanSrc = gitignore-nix.gitignoreSource ./.; | ||
|
||
nodeModules = buildNodeModules { | ||
projectDir = filterNpm cleanSrc; | ||
packageJson = ./package.json; | ||
packageLockJson = ./package-lock.json; | ||
githubSourceHashMap = { }; | ||
}; | ||
|
||
client = pkgs.lib.overrideDerivation | ||
(buildPursPackage { | ||
inherit pkgs nodeModules; | ||
src = cleanSrc; | ||
checkPhase = '' | ||
node -e 'require("./output/Test.Main").main()' | ||
''; | ||
name = "pab-nami-demo"; | ||
extraSrcs = { | ||
# web-common-marlowe = webCommonMarlowe; | ||
# generated = generated-purescript; | ||
}; | ||
spagoPackages = pkgs.callPackage ./spago-packages.nix { }; | ||
}) | ||
(_: { | ||
WEB_COMMON_SRC = webCommon; | ||
}); | ||
in | ||
{ | ||
inherit client pab-nami-demo-invoker pab-setup-invoker; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
/*eslint-env node*/ | ||
/*global global*/ | ||
import './static/main.css'; | ||
|
||
import('./src/Main.purs') | ||
.then(m => m.main()) | ||
.catch(err => console.log(err)) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
<!DOCTYPE HTML> | ||
<html> | ||
<head> | ||
<meta charset="UTF-8"> | ||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui"> | ||
<!-- Global site tag (gtag.js) - Google Analytics --> | ||
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-XXXXXXXXX-X"></script> | ||
<script> | ||
window.dataLayer = window.dataLayer || []; | ||
function gtag() { dataLayer.push(arguments); } | ||
gtag("js", new Date()); | ||
gtag( | ||
"config", | ||
"UA-XXXXXXXXX-X", | ||
{ | ||
"anonymize_ip": true, | ||
"custom_map": { "dimension1": "product" }, | ||
"product": "nami-demo" | ||
} | ||
); | ||
</script> | ||
<!-- Segment Analytics --> | ||
<script> | ||
!function(){var analytics=window.analytics=window.analytics||[];if(!analytics.initialize)if(analytics.invoked)window.console&&console.error&&console.error("Segment snippet included twice.");else{analytics.invoked=!0;analytics.methods=["trackSubmit","trackClick","trackLink","trackForm","pageview","identify","reset","group","track","ready","alias","debug","page","once","off","on","addSourceMiddleware","addIntegrationMiddleware","setAnonymousId","addDestinationMiddleware"];analytics.factory=function(e){return function(){var t=Array.prototype.slice.call(arguments);t.unshift(e);analytics.push(t);return analytics}};for(var e=0;e<analytics.methods.length;e++){var key=analytics.methods[e];analytics[key]=analytics.factory(key)}analytics.load=function(key,e){var t=document.createElement("script");t.type="text/javascript";t.async=!0;t.src="https://cdn.segment.com/analytics.js/v1/" + key + "/analytics.min.js";var n=document.getElementsByTagName("script")[0];n.parentNode.insertBefore(t,n);analytics._loadOptions=e};analytics.SNIPPET_VERSION="4.13.1"; | ||
analytics.load("XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"); | ||
analytics.page(); | ||
}}(); | ||
</script> | ||
<script defer src="runtime.7e2a408ec34db1e18755.js"></script><script defer src="vendors.a032b1b05443fc0e131e.js"></script><script defer src="main.08f5117d6181c7cf9cc8.js"></script></head> | ||
<body></body> | ||
</html> |