Skip to content

Commit c7c9e8b

Browse files
committed
Sample application before adding GSN support.
This branch is the basic implementation, before adding any GSN support. - The "workshop-with-gsn" is the same app with GSN support - The "workshop-with-paymaster" is the same app with GSN and custom paymaster
1 parent 933dd87 commit c7c9e8b

File tree

12 files changed

+2930
-0
lines changed

12 files changed

+2930
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/node_modules/
2+
/.idea/
3+
/.DS_Store
4+
/build/

README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# GSN v3 integration workshop
2+
3+
### (Base branch - before adding any GSN support)
4+
5+
This sample dapp emits an event with the last account that clicked on the "capture the flag" button. We will integrate
6+
this dapp to work gaslessly with GSN v3. This will allow an externally owned account without ETH to capture the flag by
7+
signing a meta transaction.
8+
9+
10+
### To run the sample:
11+
12+
1. first clone and `yarn install`
13+
2. run `yarn ganache`
14+
3. Make sure you have Metamask installed, and pointing to "localhost"
15+
4. In a different window, run `yarn start`, to deploy the contract, and start the UI
16+
5. Start a browser pointing to "http://localhost:3000"
17+
6. Click the "Capture the Flag" button. Notice that you do need an account with eth for that..
18+
19+
You can see the integrations as GitHub pull requests:
20+
21+
1. [Basic: Minimum viable GSN integration](https://github.com/opengsn/workshop/pull/1/files)
22+
2. [Advanced: Write your own custom Paymaster](https://github.com/opengsn/workshop/pull/2/files_)
23+
24+
Note: on testnet we maintain a public service "pay for everything" paymaster so writing your own is not strictly
25+
required. On mainnet, you need a custom paymaster, such as a token paymaster that allow users to pay for gas in tokens,
26+
and exchanging them for ETH ETH on Uniswap. Dapps will want to develop their own custom paymaster in order, for example
27+
to subsidize gas fees for new users during the onboarding process.
28+
29+
### Further reading
30+
31+
GSNv3 integration tutorial: https://docs.opengsn.org/tutorials
32+
33+
Documentation explaining how everything works: https://docs.opengsn.org/

contracts/CaptureTheFlag.sol

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* SPDX-License-Identifier:MIT
3+
*/
4+
pragma solidity ^0.8.7;
5+
6+
contract CaptureTheFlag {
7+
8+
event FlagCaptured(address previousHolder, address currentHolder);
9+
10+
address public currentHolder = address(0);
11+
12+
function captureTheFlag() external {
13+
address previousHolder = currentHolder;
14+
15+
currentHolder = msg.sender;
16+
17+
emit FlagCaptured(previousHolder, currentHolder);
18+
}
19+
}

contracts/Migrations.sol

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* SPDX-License-Identifier:MIT
3+
*/
4+
pragma solidity >=0.4.25 <0.9.0;
5+
6+
contract Migrations {
7+
address public owner;
8+
uint public last_completed_migration;
9+
10+
modifier restricted() {
11+
if (msg.sender == owner) _;
12+
}
13+
14+
constructor() {
15+
owner = msg.sender;
16+
}
17+
18+
function setCompleted(uint completed) public restricted {
19+
last_completed_migration = completed;
20+
}
21+
}

migrations/1_initial_migration.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const Migrations = artifacts.require("Migrations");
2+
3+
module.exports = function (deployer) {
4+
deployer.deploy(Migrations);
5+
};

migrations/2_deploy_contracts.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const CaptureTheFlag = artifacts.require('CaptureTheFlag')
2+
3+
module.exports = async function (deployer) {
4+
await deployer.deploy(CaptureTheFlag)
5+
}

package.json

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "gsn-sample-workshop",
3+
"version": "3.0.0",
4+
"description": "Simple example of how to use GSNv3",
5+
"private": true,
6+
"dependencies": {
7+
"browserify": "^17.0.0",
8+
"ethers": "^5.6.8",
9+
"ganache-cli": "^6.12.2",
10+
"run-with-testrpc": "^0.3.1",
11+
"serve": "^13.0.0"
12+
},
13+
"scripts": {
14+
"ganache": "yarn run ganache-cli -d --chainId 1337",
15+
"gsn-with-ganache": "run-with-testrpc -d --chainId 1337 'gsn start'",
16+
"test": "truffle test",
17+
"compile": "truffle compile",
18+
"build": "./ui/build.sh",
19+
"start": "truffle deploy && yarn build && yarn serve ./build/html"
20+
},
21+
"author": "Dror Tirosh",
22+
"license": "GPL"
23+
}

test/testcontracts.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const CaptureTheFlag = artifacts.require('CaptureTheFlag')
2+
3+
const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
4+
5+
contract("CaptureTheFlag", async accounts => {
6+
7+
let account
8+
let captureFlagContract
9+
10+
before(async () => {
11+
captureFlagContract = await CaptureTheFlag.new();
12+
13+
account = accounts[0]
14+
})
15+
16+
it('Runs without GSN', async () => {
17+
const res = await captureFlagContract.captureTheFlag({from: account});
18+
assert.equal(res.logs[0].event, "FlagCaptured", "Wrong event");
19+
assert.equal(res.logs[0].args.previousHolder, ZERO_ADDRESS, "Wrong previous flag holder");
20+
assert.equal(res.logs[0].args.currentHolder, account, "Wrong current flag holder");
21+
});
22+
23+
});

ui/build.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#! /bin/bash -e
2+
3+
rm -rf ./build/html/
4+
mkdir ./build/html/
5+
6+
browserify ./ui/index.js -o ./build/html/bundle.js
7+
cp ./ui/index.html ./build/html/
8+
9+
echo "Done building \"./build/html\" at `date`"
10+
11+

ui/index.html

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<html>
2+
<head>
3+
4+
<title>GSNv3 Test</title>
5+
6+
<script src="bundle.js">
7+
</script>
8+
9+
</head>
10+
<body>
11+
<h2>GSNv3 Test App</h2>
12+
13+
<script>
14+
window.app.initContract().then(function ({contractAddress, network}) {
15+
console.log('CaptureTheFlag contract', contractAddress)
16+
console.log(`identified network: ${JSON.stringify(network)}`)
17+
document.getElementById('capture_button').disabled = false
18+
})
19+
</script>
20+
21+
<button id="capture_button" disabled onClick="window.app.contractCall()">
22+
Capture the flag
23+
</button>
24+
25+
<hr>
26+
<div id="logview"></div>
27+
</body>
28+
</html>

0 commit comments

Comments
 (0)