Skip to content

Commit

Permalink
feat(docs): use principal account for gas station
Browse files Browse the repository at this point in the history
  • Loading branch information
jessevanmuijden committed Nov 7, 2023
1 parent 497e2a9 commit f4b866e
Showing 1 changed file with 62 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ that can pay the gas fee for every voting transaction, allowing all citizens to
## Recommended reading

* [The First Crypto Gas Station is Now on Kadena’s Blockchain](/blogchain/2020/the-first-crypto-gas-station-is-now-on-kadenas-blockchain-2020-08-06)
* [Introducing Kadena Account Protocols (KIP-0012)](/blogchain/2021/introducing-kadena-account-protocols-kip-0012-2021-09-27)

## Get the code

Expand Down Expand Up @@ -296,22 +297,49 @@ function change the line `.addSigner(accountKey(account))` into the following.

This scopes the signature of the account that votes to the `GAS_PAYER` capability. The voter account name and
zero (unlimited) limits for the amount of gas and the gas price are passed as arguments. Also, change the
`senderAccount` in the transaction's metadata to `'election-gas-station'`.
`senderAccount` in the transaction's metadata to `'election-gas-station'`, to indicate that the election
gas station account will pay the gas fee of the transaction instead of the voter account.

Return to the election website and try to vote again with the voter account. The transaction will still fail
with the error: `Failure: Tx Failed: Insufficient funds`. Apparently, the gas station does not work as it is
supposed to, yet. The reason is that the gas station module attempts to pay for gas using the `senderAccount`,
but this account does not exist. It has to be created first. It also needs to have a positive KDA balance.
Otherwise, the transaction will still fail due to insufficient funds in the gas station account.

## Create and fund the gas station account
## Create the gas station account

You can use the `create-account` function of the `coin` module to create the
`election-gas-station` account in a function called `init` in the `election-gas-station` module, as follows.
Actually, `election-gas-station` is not the most ideal name for the gas station account. As explained in the
recommended reading, it is more secure to use a principal account name. Whereas your admin and voter accounts
are guarded by a keyset, the gas station account will be guarded by the `ALLOW_GAS` capability. The gas station
account is thus an example of a capability guarded account. The built-in Pact function `create-pincipal` can
automatically create an account name based on a capability guard for you if you pass the capability guard as
the first and only argument into it. The resulting account name will be prefixed with the `c:` of `capability`.
Define the gas station account name as a constant at the bottom of the `election-gas-station` module in the
`./pact/election-gas-station.pact` file.

```pact
(defconst GAS_STATION_ACCOUNT "election-gas-station")
(defconst GAS_STATION_ACCOUNT (create-principal (create-gas-payer-guard)))
```

Update the `./pact/election-gas-station.repl` file as follows to print out the capability guarded gas station
account name when you run the file.

```pact
(load "setup.repl")
(begin-tx "Load election gas station module")
(load "root/gas-payer-v1.pact")
(load "election-gas-station.pact")
[GAS_STATION_ACCOUNT]
(commit-tx)
```

In the `./pact/election-gas-station.pact` file, you can use the `create-account` function of the
`coin` module to create the gas station account in a function called `init` in the `election-gas-station`
module, as follows. The first argument of the function is the account name you just defined and the second
argument is the guard for the account.

```pact
(defun init ()
(coin.create-account GAS_STATION_ACCOUNT (create-gas-payer-guard))
)
Expand Down Expand Up @@ -344,51 +372,68 @@ in the `./snippets` folder of your project. Replace `k:account` with your admin
npm run deploy-gas-station:devnet -- k:account upgrade init
```

Verify that the `election-gas-station` account now exists with a 0 KDA balance on Devnet by running the
following script.
Verify that the gas station account now exists with a 0 KDA balance on Devnet by running the
following script. Replace `c:account` with the actual gas station account name that you printed by running
`./pact/election-gas-station.repl`.

```bash
npm run coin-details:devnet -- election-gas-station
npm run coin-details:devnet -- c:account
```

If everything went well, you should see output similar to this.

```bash
{
guard: {
args: [],
fun: 'n_fd020525c953aa002f20fb81a920982b175cdf1a.election-gas-station.gas-payer-guard'
cgPactId: null,
cgArgs: [],
cgName: 'n_fd020525c953aa002f20fb81a920982b175cdf1a.election-gas-station.ALLOW_GAS'
},
balance: 0,
account: 'election-gas-station'
account: 'c:Jjn2uym_xGD32ojhWdPjB5mgIbDwgXRRvkWmFl5n4gg'
}
```

The account details show the capability guard that guards the gas station account and was used to generate
the `c:` account name. Notice how the `ALLOW_GAS` capability is prefixed with the module name as well as your
principal namespace. Since the principal namespace is based on your admin keyset, and the principal account
of the gas station is based on a capability including that principal namespace, it can be concluded that the
gas station account name you created is unique to your admin account. This makes it impossible for someone else
with a different keyset to squat your gas station account on another chain. That is how principal accounts in
principal namespaces provide better security than vanity account names in the `free` namespace.

## Fund the gas station account

Execute the `./transfer.ts` snippet by running the following command to transfer 1 KDA from your admin
account to the gas station account. Replace `k:account` with your admin account. The transaction
account to the gas station account. Replace `k:account` with your admin account and replace `c:account`
with the actual account name of your gas station. The transaction
inside this file is similar to `./transfer-create.ts`, except that it does not use the special
`sender00` account, but your own election admin account to transfer KDA from. Therefore, the transaction
needs to be signed with Chainweaver instead of a private key. Also, the `transfer` function of the
`coin` module is used. This function requires that the receiving account already exists on the
blockchain and will not create the account if it does not exist like `transfer-create` would.

```bash
npm run transfer:devnet -- k:account election-gas-station 1
npm run transfer:devnet -- k:account c:account 1
```

Verify that the `election-gas-station` account now has a 1 KDA balance on Devnet by running the
following script again.
Verify that the election gasstation account now has a 1 KDA balance on Devnet by running the
following script again. Replace `c:account` with the actual account name of your gas station.

```bash
npm run coin-details:devnet -- election-gas-station
npm run coin-details:devnet -- c:account
```

Now, everything should be set to allow voters to vote for free, because the `election-gas-station`
account can pay the gas fee charged for the voting transaction.

## Vote again

Return to the election website, set the account to your voter account and vote for one of the
Open the file `frontend/src/repositories/vote/DevnetVoteRepository.ts` and in the `vote`
function change the value of `senderAccount` from `election-gas-station` to the `c:account` of the gas
station that you created.

Vist the election website in your browser, set the account to your voter account and vote for one of the
candidates in the list. Unfortunately, the transaction still fails but this time with a
different error: `Keyset failure`. This error occurs because the signature is not scoped to
the `ACCOUNT-OWNER` capability used in `./pact/election.repl`. When you created this capability
Expand Down

0 comments on commit f4b866e

Please sign in to comment.