Skip to content

Commit 8b1d011

Browse files
committed
#68 Implemented bridge to transfer wpht tokens using profile contract
1 parent 6c4872d commit 8b1d011

File tree

8 files changed

+144
-35
lines changed

8 files changed

+144
-35
lines changed

contracts/GSNProfile.sol

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import "@openzeppelin/upgrades/contracts/Initializable.sol";
44

55
import "./utils/GSNMultiOwnableRecipient.sol";
66
import "./bondingcurve/ArtistToken.sol";
7+
import "./bondingcurve/vendor/ERC20/IERC20.sol";
78
import "./bondingcurve/vendor/ERC20/WPHT.sol";
89
import "./Acl.sol";
910

@@ -25,9 +26,9 @@ contract GSNProfile is Initializable, GSNMultiOwnableRecipient {
2526
event ClaimedArtistTokens(uint256 amount);
2627
event RefundedTokens(uint256 amount);
2728
event BoughtArtistTokens(uint256 amount);
28-
event TransferArtistTokens(address tokenAddr, address beneficiary, uint256 amount);
2929

30-
event TransferTokens(address beneficiary, uint256 amount);
30+
event TransferToken(address beneficiary, uint256 amount);
31+
event TransferIERC20Token(address wphtAddr, address beneficiary, uint256 amount);
3132

3233
modifier fileExists(bytes32 _cid) {
3334
require(hasFile(_cid) == true);
@@ -80,10 +81,17 @@ contract GSNProfile is Initializable, GSNMultiOwnableRecipient {
8081
emit OwnerRecovered(_newOwner, _msgSender());
8182
}
8283

83-
function transferTokens(address payable _beneficiary, uint256 _amount) public isOwner(_msgSender()) {
84+
function transferToken(address payable _beneficiary, uint256 _amount) public isOwner(_msgSender()) {
8485
require(_beneficiary != address(0), "Invalid beneficiary address");
8586
_beneficiary.transfer(_amount);
86-
emit TransferTokens(_beneficiary, _amount);
87+
emit TransferToken(_beneficiary, _amount);
88+
}
89+
90+
function transferIERC20Token(address payable _tokenAddr, address payable _beneficiary, uint256 _amount) public isOwner(_msgSender()) {
91+
require(_beneficiary != address(0), "Invalid beneficiary address");
92+
93+
IERC20(_tokenAddr).transfer(_beneficiary, _amount);
94+
emit TransferIERC20Token(_tokenAddr, _beneficiary, _amount);
8795
}
8896

8997
function hatchArtistToken(address _tokenAddr, address payable _wphtAddr, uint256 _amount, bool _runDeposit) public isOwner(_msgSender()) {
@@ -125,15 +133,6 @@ contract GSNProfile is Initializable, GSNMultiOwnableRecipient {
125133
emit BoughtArtistTokens(boughtAmount);
126134
}
127135

128-
function transferArtistTokens(address _tokenAddr, address payable _beneficiary, uint256 _amount) public isOwner(_msgSender()) {
129-
require(_beneficiary != address(0), "Invalid beneficiary address");
130-
require(_tokenAddr != address(0), "Token was not added");
131-
132-
ArtistToken tokenInstance = ArtistToken(_tokenAddr);
133-
tokenInstance.transfer(_beneficiary, _amount);
134-
emit TransferArtistTokens(_tokenAddr, _beneficiary, _amount);
135-
}
136-
137136
/*
138137
* READ-ONLY METHODS
139138
*/

contracts/bondingcurve/vendor/ERC20/WPHT.sol

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222

2323
pragma solidity ^0.5.0;
2424

25-
contract WPHT {
25+
import "./IERC20.sol";
26+
27+
contract WPHT is IERC20{
2628
string public name = "Wrapped Photon";
2729
string public symbol = "WPHT";
2830
uint8 public decimals = 18;

migrations/03_deploy_artist_token.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const WPHT = artifacts.require('WPHT');
33
const FundingPool = artifacts.require('FundingPool');
44
const ArtistToken = artifacts.require('ArtistToken');
55

6-
const {deployArtistToken, hatchArtistToken, isArtistTokenHatched} = require('../src/contracts/artist_token');
6+
const {hatchArtistToken, isArtistTokenHatched} = require('../src/contracts/artist_token');
77
const {forceMigration} = require('./00_unlock_account');
88
const Web3Wrapper = require('../src/web3');
99

@@ -29,7 +29,6 @@ module.exports = function(deployer) {
2929
}
3030

3131
let fundingPoolAddr;
32-
let feeRecipientAddr;
3332
let artistTokenAddr;
3433
let wphtAddr;
3534

@@ -38,19 +37,20 @@ module.exports = function(deployer) {
3837
.then((fundingPoolInstance) => {
3938
console.log(`FundingPoolInstance deployed at: ${fundingPoolInstance.address}`);
4039
fundingPoolAddr = fundingPoolInstance.address;
41-
feeRecipientAddr = fundingPoolInstance.address;
4240
return deployer.deploy(WPHT, fromAccount);
4341
})
4442
.then(WPHTInstance => {
4543
console.log(`WPHTInstance deployed at: ${WPHTInstance.address}`);
4644
wphtAddr = WPHTInstance.address;
4745
const name = 'Armin Van Lightstreams';
4846
const symbol = 'AVL';
47+
const feeRecipientAddr = fromAccount;
48+
const pauserAddr = fromAccount;
4949
const initialRaiseInWeiBN = Web3Wrapper.utils.toBN(Web3Wrapper.utils.toWei(`${initialRaise}`));
5050
return deployer.deploy(ArtistToken,
5151
name,
5252
symbol,
53-
[wphtAddr, fundingPoolAddr, feeRecipientAddr, fromAccount],
53+
[wphtAddr, fundingPoolAddr, feeRecipientAddr, pauserAddr],
5454
[
5555
gasPrice, theta, p0, initialRaiseInWeiBN,
5656
friction, hatchDurationSeconds, hatchVestingDurationSeconds, minExternalContribution,
@@ -82,4 +82,6 @@ module.exports = function(deployer) {
8282
});
8383
};
8484

85-
module.exports.remainingHatchingAmount = remainingHatchingAmount;
85+
module.exports.remainingHatchingAmount = remainingHatchingAmount;
86+
module.exports.thetaPercent = theta / 10000;
87+
module.exports.initialRaise = initialRaise;

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "lightstreams-js-sdk",
3-
"version": "0.16.2",
3+
"version": "0.16.3",
44
"description": "Lightstreams JS SDK for building mainstream DApps with support for Programmable Decentralized Private Storage.",
55
"author": "Gabriel Garrido",
66
"contributors": [

src/contracts/fundingPool.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* User: llukac<lukas@lightstreams.io>
3+
* Date: 21/11/19 13:40
4+
* Copyright 2019 (c) Lightstreams, Granada
5+
*/
6+
7+
const Web3Wrapper = require('../web3');
8+
9+
const fundingPoolSc = require('../../build/contracts/FundingPool.json');
10+
11+
module.exports.allocateFunds = async (web3, {contractAddr, artistTokenAddr, beneficiary, amount, from}) => {
12+
Web3Wrapper.validator.validateAddress('contractAddr', contractAddr);
13+
Web3Wrapper.validator.validateAddress('artistTokenAddr', artistTokenAddr);
14+
Web3Wrapper.validator.validateAddress('beneficiary', beneficiary);
15+
Web3Wrapper.validator.validateWeiBn('amount', amount);
16+
17+
return await Web3Wrapper.contractSendTx(
18+
web3, {
19+
to: contractAddr,
20+
from,
21+
useGSN: false,
22+
method: 'allocateFunds',
23+
abi: fundingPoolSc.abi,
24+
params: [artistTokenAddr, beneficiary, amount.toString()],
25+
},
26+
);
27+
};

src/contracts/profile.js

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const {
1313

1414
const {
1515
buyArtistTokens,
16-
transfer: transferArtistToken,
16+
transfer: transferIERC20Token,
1717
getBalanceOf
1818
} = require('./artist_token');
1919

@@ -209,7 +209,7 @@ module.exports.removeFile = (web3, { from, contractAddr, cid }) => {
209209
});
210210
};
211211

212-
const transferTokens = module.exports.transferTokens = (web3, {from, beneficiary, contractAddr, amountInPht}) => {
212+
const transferToken = module.exports.transferToken = (web3, {from, beneficiary, contractAddr, amountInPht}) => {
213213
Web3Wrapper.validator.validateAddress("from", from);
214214
Web3Wrapper.validator.validateAddress("beneficiary", beneficiary);
215215
Web3Wrapper.validator.validateAddress("contractAddr", contractAddr);
@@ -218,23 +218,24 @@ const transferTokens = module.exports.transferTokens = (web3, {from, beneficiary
218218
from: from,
219219
to: contractAddr,
220220
abi: profileScJSON.abi,
221-
method: 'transferTokens',
221+
method: 'transferToken',
222222
params: [beneficiary, Web3Wrapper.utils.toWei(amountInPht)]
223223
});
224224
};
225225

226-
module.exports.transferArtistTokens = (web3, {from, beneficiary, contractAddr, artistToken, amount}) => {
226+
module.exports.transferIERC20Token = (web3, {from, beneficiary, contractAddr, tokenAddr, amount}) => {
227227
Web3Wrapper.validator.validateAddress("from", from);
228228
Web3Wrapper.validator.validateAddress("beneficiary", beneficiary);
229229
Web3Wrapper.validator.validateAddress("contractAddr", contractAddr);
230-
Web3Wrapper.validator.validateAddress("artistToken", artistToken);
230+
Web3Wrapper.validator.validateAddress("tokenAddr", tokenAddr);
231+
Web3Wrapper.validator.validateWeiBn("amount", amount);
231232

232233
return Web3Wrapper.contractSendTx(web3, {
233234
from: from,
234235
to: contractAddr,
235236
abi: profileScJSON.abi,
236-
method: 'transferArtistTokens',
237-
params: [artistToken, beneficiary, amount]
237+
method: 'transferIERC20Token',
238+
params: [tokenAddr, beneficiary, amount.toString()]
238239
});
239240
};
240241

src/web3/index.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ module.exports.sendTransaction = (web3, { from, to, valueInPht }) => {
7373
module.exports.contractCall = (web3, { to: contractAddr, abi, from, method, params }) => {
7474
return new Promise(async (resolve, reject) => {
7575
if (!isLatest(web3)) reject(new Error('Web3 version is not valid'));
76+
console.log(`Contract Call: ${contractAddr}.${method}(${params.join(', ')})`);
7677

7778
try {
7879
const contract = new web3.eth.Contract(abi, contractAddr);
@@ -91,6 +92,7 @@ module.exports.contractCall = (web3, { to: contractAddr, abi, from, method, para
9192
module.exports.contractSendTx = (web3, { to: contractAddr, abi, from, method, params, value, gas, useGSN }) => {
9293
return new Promise(async (resolve, reject) => {
9394
if (!isLatest(web3)) reject(new Error('Web3 version is not valid'));
95+
console.log(`Contract Tx: ${contractAddr}.${method}('${params.join("', '")}') by ${from}`);
9496

9597
try {
9698
const contract = new web3.eth.Contract(abi, contractAddr);
@@ -99,7 +101,7 @@ module.exports.contractSendTx = (web3, { to: contractAddr, abi, from, method, pa
99101
}
100102

101103
const sendTx = contract.methods[method](...(params || []));
102-
const estimatedGas = gas || await calculateEstimatedGas(sendTx, { from, value });
104+
const estimatedGas = gas || await calculateEstimatedGas(sendTx, { from });
103105

104106
sendTx.send({
105107
from,

test/01_profile_token.js renamed to test/07_profile_artist_token.js

Lines changed: 83 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,36 @@ const assert = chai.assert;
1212

1313
const Profile = artifacts.require("GSNProfile");
1414
const ArtistToken = artifacts.require("ArtistToken");
15+
const FundingPool = artifacts.require("FundingPool");
1516
const WPHT = artifacts.require("WPHT");
1617

1718
const Web3 = require('../src/web3');
1819
const {
1920
buyArtistToken,
20-
transferArtistTokens,
21+
transferIERC20Token,
2122
hatchArtistToken,
2223
refundArtistToken,
2324
claimArtistToken,
2425
} = require('../src/contracts/profile');
2526

2627
const {
27-
remainingHatchingAmount
28+
allocateFunds,
29+
} = require('../src/contracts/fundingPool');
30+
31+
const {
32+
getWPHTBalanceOf,
33+
} = require('../src/contracts/wpht');
34+
35+
const {
36+
remainingHatchingAmount,
2837
} = require('../migrations/03_deploy_artist_token');
2938

3039
const {
3140
getBalanceOf,
3241
} = require('../src/contracts/artist_token');
3342

34-
contract('Profile', (accounts) => {
43+
// @IMPORTANT: Require redeploy migration `03_deploy_artist_token.js`
44+
contract('ArtistToken', (accounts) => {
3545
const ROOT_ACCOUNT = process.env.NETWORK === 'ganache' ? accounts[0] : process.env.ACCOUNT;
3646
let FAN_ACCOUNT;
3747
const ACCOUNT_DEFAULT_PASSWORD = 'test123';
@@ -131,12 +141,12 @@ contract('Profile', (accounts) => {
131141
assert.equal(bougthAmount, balanceOfContract);
132142

133143
// Withdraw artist tokens back to user
134-
await transferArtistTokens(web3, {
144+
await transferIERC20Token(web3, {
135145
from: FAN_ACCOUNT,
136146
beneficiary: FAN_ACCOUNT,
137147
contractAddr: fanProfileInstance.address,
138-
amount: balanceOfContract,
139-
artistToken: artistTokenInstance.address
148+
amount: Web3.utils.toBN(balanceOfContract),
149+
tokenAddr: artistTokenInstance.address
140150
});
141151

142152
const balanceOfUser = await getBalanceOf(web3, {
@@ -147,7 +157,7 @@ contract('Profile', (accounts) => {
147157
assert.equal(bougthAmount, balanceOfUser);
148158
});
149159

150-
it('should claim ArtistToken hatch amount', async () => {
160+
it('should claim ArtistToken contributor hatch amount', async () => {
151161
const artistTokenInstance = await ArtistToken.deployed();
152162

153163
console.log(`Claiming artist tokens...`);
@@ -165,4 +175,70 @@ contract('Profile', (accounts) => {
165175
assert.equal(claimedTotal, balanceOfContract);
166176
});
167177

178+
it('should claim accumulated WPHT from hatching', async () => {
179+
const wphtInstance = await WPHT.deployed();
180+
const artistTokenInstance = await ArtistToken.deployed();
181+
const fundingPoolInstance = await FundingPool.deployed();
182+
// We are using fan profile contract as beneficiary because it is the only profile deployed
183+
// within the scope of this test
184+
const beneficiaryAddr = fanProfileInstance.address;
185+
186+
const fundingPoolWPHTBalanceInWei = await getWPHTBalanceOf(web3, {
187+
wphtAddr: wphtInstance.address,
188+
accountAddr: fundingPoolInstance.address,
189+
});
190+
191+
const beforeWPHTBalanceInWei = await getWPHTBalanceOf(web3, {
192+
wphtAddr: wphtInstance.address,
193+
accountAddr: beneficiaryAddr,
194+
});
195+
196+
console.log(`Claiming ${Web3.utils.toPht(fundingPoolWPHTBalanceInWei)} WPHT from hatching of artist tokens...`);
197+
await allocateFunds(web3, {
198+
from: ROOT_ACCOUNT,
199+
contractAddr: fundingPoolInstance.address,
200+
artistTokenAddr: artistTokenInstance.address,
201+
beneficiary: beneficiaryAddr,
202+
amount: fundingPoolWPHTBalanceInWei
203+
});
204+
205+
const afterWPHTBalanceInWei = await getWPHTBalanceOf(web3, {
206+
wphtAddr: wphtInstance.address,
207+
accountAddr: beneficiaryAddr,
208+
});
209+
210+
assert.equal(afterWPHTBalanceInWei.toString(), beforeWPHTBalanceInWei.add(fundingPoolWPHTBalanceInWei).toString());
211+
});
212+
213+
it('should pull WPHT from holded by profile contract', async () => {
214+
const wphtInstance = await WPHT.deployed();
215+
const beneficiaryAddr = ROOT_ACCOUNT;
216+
217+
const profileWPHTBalanceInWei = await getWPHTBalanceOf(web3, {
218+
wphtAddr: wphtInstance.address,
219+
accountAddr: fanProfileInstance.address,
220+
});
221+
222+
const beforeWPHTBalanceInWei = await getWPHTBalanceOf(web3, {
223+
wphtAddr: wphtInstance.address,
224+
accountAddr: beneficiaryAddr,
225+
});
226+
227+
// Withdraw artist tokens back to user
228+
await transferIERC20Token(web3, {
229+
from: FAN_ACCOUNT,
230+
beneficiary: beneficiaryAddr,
231+
contractAddr: fanProfileInstance.address,
232+
amount: profileWPHTBalanceInWei,
233+
tokenAddr: wphtInstance.address
234+
});
235+
236+
const afterWPHTBalanceInWei = await getWPHTBalanceOf(web3, {
237+
wphtAddr: wphtInstance.address,
238+
accountAddr: beneficiaryAddr,
239+
});
240+
241+
assert.equal(afterWPHTBalanceInWei.toString(), beforeWPHTBalanceInWei.add(profileWPHTBalanceInWei).toString());
242+
});
243+
168244
});

0 commit comments

Comments
 (0)