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

2. Add GSN provider support #1

Open
wants to merge 1 commit into
base: 1-workshop-before-gsn
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
# GSN v3 integration workshop

### (Base branch - before adding any GSN support)
### (This branch already contains frontend and contract integration with GSN)

This sample dapp emits an event with the last account that clicked on the "capture the flag" button. We will integrate
this dapp to work gaslessly with GSN v3. This will allow an externally owned account without ETH to capture the flag by
signing a meta transaction.


### To run the sample:

1. first clone and `yarn install`
2. run `yarn ganache`
2. run `yarn gsn-with-ganache` to start a node, and also deploy GSN contracts and start a relayer service.
3. Make sure you have Metamask installed, and pointing to "localhost"
4. In a different window, run `yarn start`, to deploy the contract, and start the UI
5. Start a browser pointing to "http://localhost:3000"
6. Click the "Capture the Flag" button. Notice that you do need an account with eth for that..
6. Click the "Capture the Flag" button. Notice that you don't need eth in your account: You only sign the transaction.

You can see the integrations as GitHub pull requests:

1. [Basic: Minimum viable GSN integration](https://github.com/opengsn/workshop/pull/1/files)
1. (this branch) [Basic: Minimum viable GSN integration](https://github.com/opengsn/workshop/pull/1/files)
2. [Advanced: Write your own custom Paymaster](https://github.com/opengsn/workshop/pull/2/files_)

Note: on testnet we maintain a public service "pay for everything" paymaster so writing your own is not strictly
Expand Down
12 changes: 10 additions & 2 deletions contracts/CaptureTheFlag.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,24 @@
*/
pragma solidity ^0.8.7;

contract CaptureTheFlag {
import "@opengsn/contracts/src/ERC2771Recipient.sol";

contract CaptureTheFlag is ERC2771Recipient {

event FlagCaptured(address previousHolder, address currentHolder);

address public currentHolder = address(0);

constructor(address forwarder) {
_setTrustedForwarder(forwarder);
}

string public override versionRecipient = "3.0.0";

function captureTheFlag() external {
address previousHolder = currentHolder;

currentHolder = msg.sender;
currentHolder = _msgSender();

emit FlagCaptured(previousHolder, currentHolder);
}
Expand Down
5 changes: 4 additions & 1 deletion migrations/2_deploy_contracts.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
const CaptureTheFlag = artifacts.require('CaptureTheFlag')

module.exports = async function (deployer) {
await deployer.deploy(CaptureTheFlag)
const forwarder = require('../build/gsn/Forwarder').address
await deployer.deploy(CaptureTheFlag, forwarder)

console.log(`Deployed CTF at ${CaptureTheFlag.address} with forwarder ${forwarder}`)
}
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@
"description": "Simple example of how to use GSNv3",
"private": true,
"dependencies": {
"@opengsn/contracts": "^3.0.0-beta.1",
"@opengsn/dev": "^3.0.0-beta.1",
"@opengsn/provider": "^3.0.0-beta.1",
"browserify": "^17.0.0",
"ethers": "^5.6.8",
"ganache-cli": "^6.12.2",
"run-with-testrpc": "^0.3.1",
"serve": "^13.0.0"
},
"scripts": {
"ganache": "yarn run ganache-cli -d --chainId 1337",
"gsn-with-ganache": "run-with-testrpc -d --chainId 1337 'gsn start'",
"ganache": "yarn run ganache-cli -d --networkId 1337 --chainId 1337",
"gsn-with-ganache": "run-with-testrpc -d --networkId 1337 --chainId 1337 'gsn start'",
"test": "truffle test",
"compile": "truffle compile",
"build": "./ui/build.sh",
Expand Down
29 changes: 25 additions & 4 deletions test/testcontracts.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
const {RelayProvider} = require('@opengsn/provider')
const {GsnTestEnvironment} = require('@opengsn/dev')

const CaptureTheFlag = artifacts.require('CaptureTheFlag')

const ZERO_ADDRESS = '0x0000000000000000000000000000000000000000'
Expand All @@ -8,16 +11,34 @@ contract("CaptureTheFlag", async accounts => {
let captureFlagContract

before(async () => {
captureFlagContract = await CaptureTheFlag.new();
const {forwarderAddress, paymasterAddress} = GsnTestEnvironment.loadDeployment()

captureFlagContract = await CaptureTheFlag.new(forwarderAddress);

const gsnProvider = await RelayProvider.newProvider({
provider: web3.currentProvider,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

where is the web3 object coming from?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this project the tests are executed by a Truffle (https://trufflesuite.com/truffle/)
It injects some global variables to your test environment, including the web3 object.

config: {
loggerConfiguration: {logLevel: 'error'},
paymasterAddress,
//these 2 params are needed only for ganache:
methodSuffix: '',
jsonStringifyRequest: false,
}
}).init()

account = accounts[0]
//during test, "artifacts" initialize the the default web3
// we need to replace the provider.
CaptureTheFlag.web3.setProvider(gsnProvider)

// default ganache accounts all have eth.
// test from a different account, without any eth
account = gsnProvider.newAccount().address
})

it('Runs without GSN', async () => {
it('Runs with GSN', async () => {
const res = await captureFlagContract.captureTheFlag({from: account});
assert.equal(res.logs[0].event, "FlagCaptured", "Wrong event");
assert.equal(res.logs[0].args.previousHolder, ZERO_ADDRESS, "Wrong previous flag holder");
assert.equal(res.logs[0].args.currentHolder, account, "Wrong current flag holder");
});

});
13 changes: 12 additions & 1 deletion ui/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
const ethers = require('ethers')
const {RelayProvider} = require('@opengsn/provider')

const paymasterAddress = require('../build/gsn/Paymaster').address
const contractArtifact = require('../build/contracts/CaptureTheFlag.json')
const contractAbi = contractArtifact.abi

let theContract
let provider
let gsnProvider

async function initContract() {

Expand All @@ -21,7 +24,15 @@ async function initContract() {
})
const networkId = await window.ethereum.request({method: 'net_version'})

provider = new ethers.providers.Web3Provider(window.ethereum)
gsnProvider = await RelayProvider.newProvider({
provider: window.ethereum,
config: {
loggerConfiguration: {logLevel: 'debug'},
paymasterAddress
}
}).init()

provider = new ethers.providers.Web3Provider(gsnProvider)

const network = await provider.getNetwork()
const artifactNetwork = contractArtifact.networks[networkId]
Expand Down
Loading