2020-02-19 09:33:38 +00:00
const TestToken = artifacts . require ( 'TestToken' ) ;
2020-02-21 11:41:03 +00:00
const GiftBucket = artifacts . require ( 'GiftBucket' ) ;
2020-02-18 19:23:31 +00:00
2020-02-19 11:28:05 +00:00
const TOTAL _SUPPLY = 10000 ;
const GIFT _AMOUNT = 10 ;
const REDEEM _CODE = web3 . utils . sha3 ( "hello world" ) ;
const NOW = Math . round ( new Date ( ) . getTime ( ) / 1000 ) ;
const EXPIRATION _TIME = NOW + 60 * 60 * 24 ; // in 24 hours
2020-02-18 19:23:31 +00:00
let shop ,
user ;
// For documentation please see https://framework.embarklabs.io/docs/contracts_testing.html
config ( {
contracts : {
deploy : {
"TestToken" : {
args : [ ] ,
2020-02-19 11:28:05 +00:00
} ,
2020-02-21 11:41:03 +00:00
"GiftBucket" : {
2020-02-19 11:28:05 +00:00
args : [ "$TestToken" , EXPIRATION _TIME ] ,
2020-02-18 19:23:31 +00:00
}
}
2020-02-19 13:35:11 +00:00
} ,
2020-02-18 19:23:31 +00:00
} , ( _err , _accounts ) => {
shop = _accounts [ 0 ] ;
keycard _1 = _accounts [ 1 ] ;
keycard _2 = _accounts [ 2 ] ;
user = _accounts [ 3 ] ;
} ) ;
let sendMethod ;
async function signRedeem ( contractAddress , signer , message ) {
const result = await web3 . eth . net . getId ( ) ;
2020-02-19 13:35:11 +00:00
let chainId = parseInt ( result ) ;
2020-02-21 11:41:03 +00:00
//FIXME: getChainID in the contract returns 1 so we hardcode it here to 1.
2020-02-19 13:35:11 +00:00
chainId = 1 ;
2020-02-18 19:23:31 +00:00
let domain = [
{ name : "name" , type : "string" } ,
{ name : "version" , type : "string" } ,
{ name : "chainId" , type : "uint256" } ,
{ name : "verifyingContract" , type : "address" }
] ;
let redeem = [
{ name : "keycard" , type : "address" } ,
{ name : "receiver" , type : "address" } ,
{ name : "code" , type : "bytes32" } ,
] ;
let domainData = {
name : "KeycardGift" ,
version : "1" ,
chainId : chainId ,
verifyingContract : contractAddress
} ;
let data = {
types : {
EIP712Domain : domain ,
Redeem : redeem ,
} ,
primaryType : "Redeem" ,
domain : domainData ,
message : message
} ;
return new Promise ( ( resolve , reject ) => {
sendMethod ( {
jsonrpc : '2.0' ,
id : Date . now ( ) . toString ( ) . substring ( 9 ) ,
method : "eth_signTypedData" ,
params : [ signer , data ] ,
2020-02-19 13:35:11 +00:00
from : signer
2020-02-18 19:23:31 +00:00
} , ( error , res ) => {
if ( error ) {
return reject ( error ) ;
}
resolve ( res . result ) ;
} ) ;
} ) ;
}
function mineAt ( timestamp ) {
return new Promise ( ( resolve , reject ) => {
sendMethod ( {
jsonrpc : '2.0' ,
method : "evm_mine" ,
params : [ timestamp ] ,
id : Date . now ( ) . toString ( ) . substring ( 9 )
} , ( error , res ) => {
if ( error ) {
return reject ( error ) ;
}
resolve ( res . result ) ;
} ) ;
} ) ;
}
2020-02-21 11:41:03 +00:00
contract ( "GiftBucket" , function ( ) {
2020-02-18 19:23:31 +00:00
sendMethod = ( web3 . currentProvider . sendAsync ) ? web3 . currentProvider . sendAsync . bind ( web3 . currentProvider ) : web3 . currentProvider . send . bind ( web3 . currentProvider ) ;
2020-02-19 11:28:05 +00:00
it ( "shop buys 100 tokens" , async function ( ) {
let supply = await TestToken . methods . totalSupply ( ) . call ( ) ;
assert . equal ( parseInt ( supply ) , 0 ) ;
2020-02-18 19:23:31 +00:00
2020-02-19 11:28:05 +00:00
await TestToken . methods . mint ( TOTAL _SUPPLY ) . send ( {
from : shop ,
} ) ;
2020-02-18 19:23:31 +00:00
2020-02-19 11:28:05 +00:00
supply = await TestToken . methods . totalSupply ( ) . call ( ) ;
assert . equal ( parseInt ( supply ) , TOTAL _SUPPLY ) ;
2020-02-18 19:23:31 +00:00
2020-02-19 11:28:05 +00:00
let shopBalance = await TestToken . methods . balanceOf ( shop ) . call ( ) ;
assert . equal ( parseInt ( shopBalance ) , TOTAL _SUPPLY ) ;
} ) ;
2020-02-18 19:23:31 +00:00
2020-02-19 11:28:05 +00:00
// it("deploy", async function() {
2020-02-21 11:41:03 +00:00
// const deploy = GiftBucket.clone().deploy({ arguments: [keycard_1, EXPIRATION_TIME] });
2020-02-19 11:28:05 +00:00
// giftsBatchInstance = await deploy.send();
2020-02-19 09:33:38 +00:00
// });
2020-02-18 19:23:31 +00:00
2020-02-19 11:28:05 +00:00
it ( "approve ERC20 transfer" , async function ( ) {
2020-02-21 11:41:03 +00:00
const approve = TestToken . methods . approve ( GiftBucket . _address , TOTAL _SUPPLY )
2020-02-19 11:28:05 +00:00
const approveGas = await approve . estimateGas ( ) ;
await approve . send ( {
from : shop ,
gas : approveGas ,
} ) ;
} ) ;
2020-02-19 09:33:38 +00:00
2020-02-19 11:28:05 +00:00
it ( "addSupply" , async function ( ) {
2020-02-21 11:41:03 +00:00
let factoryBalance = await TestToken . methods . balanceOf ( GiftBucket . _address ) . call ( ) ;
2020-02-19 11:28:05 +00:00
assert . equal ( parseInt ( factoryBalance ) , 0 , ` factory balance before is ${ factoryBalance } instead of 0 ` ) ;
2020-02-19 09:33:38 +00:00
2020-02-19 11:28:05 +00:00
let shopBalance = await TestToken . methods . balanceOf ( shop ) . call ( ) ;
assert . equal ( parseInt ( shopBalance ) , TOTAL _SUPPLY , ` shop balance before is ${ shopBalance } instead of ${ TOTAL _SUPPLY } ` ) ;
2020-02-19 09:33:38 +00:00
2020-02-21 11:41:03 +00:00
const addSupply = GiftBucket . methods . addSupply ( TOTAL _SUPPLY )
2020-02-19 11:28:05 +00:00
const addSupplyGas = await addSupply . estimateGas ( ) ;
await addSupply . send ( {
from : shop ,
gas : addSupplyGas ,
} ) ;
2020-02-19 09:33:38 +00:00
2020-02-21 11:41:03 +00:00
factoryBalance = await TestToken . methods . balanceOf ( GiftBucket . _address ) . call ( ) ;
2020-02-19 11:28:05 +00:00
assert . equal ( parseInt ( factoryBalance ) , TOTAL _SUPPLY , ` factory balance after is ${ factoryBalance } instead of ${ TOTAL _SUPPLY } ` ) ;
2020-02-19 09:33:38 +00:00
2020-02-19 11:28:05 +00:00
shopBalance = await TestToken . methods . balanceOf ( shop ) . call ( ) ;
assert . equal ( parseInt ( shopBalance ) , 0 , ` shop balance after is ${ shopBalance } instead of 0 ` ) ;
2020-02-19 09:33:38 +00:00
2020-02-19 11:28:05 +00:00
2020-02-21 11:41:03 +00:00
let totalSupply = await GiftBucket . methods . totalSupply ( ) . call ( ) ;
2020-02-19 11:28:05 +00:00
assert . equal ( parseInt ( totalSupply ) , TOTAL _SUPPLY , ` total contract supply is ${ totalSupply } instead of ${ TOTAL _SUPPLY } ` ) ;
2020-02-21 11:41:03 +00:00
let availableSupply = await GiftBucket . methods . availableSupply ( ) . call ( ) ;
2020-02-19 11:28:05 +00:00
assert . equal ( parseInt ( availableSupply ) , TOTAL _SUPPLY , ` available contract supply is ${ availableSupply } instead of ${ TOTAL _SUPPLY } ` ) ;
2020-02-18 19:23:31 +00:00
} ) ;
2020-02-19 11:28:05 +00:00
async function testCreateGift ( keycard , amount ) {
const redeemCodeHash = web3 . utils . sha3 ( REDEEM _CODE ) ;
2020-02-21 11:41:03 +00:00
const createGift = GiftBucket . methods . createGift ( keycard , amount , redeemCodeHash ) ;
2020-02-19 11:28:05 +00:00
const createGiftGas = await createGift . estimateGas ( ) ;
await createGift . send ( {
from : shop ,
gas : createGiftGas ,
} ) ;
2020-02-18 19:23:31 +00:00
2020-02-21 11:41:03 +00:00
let totalSupply = await GiftBucket . methods . totalSupply ( ) . call ( ) ;
2020-02-19 11:28:05 +00:00
assert . equal ( parseInt ( totalSupply ) , TOTAL _SUPPLY ) ;
2020-02-18 19:23:31 +00:00
2020-02-21 11:41:03 +00:00
let availableSupply = await GiftBucket . methods . availableSupply ( ) . call ( ) ;
2020-02-19 11:28:05 +00:00
assert . equal ( parseInt ( availableSupply ) , TOTAL _SUPPLY - amount ) ;
}
2020-02-18 19:23:31 +00:00
2020-02-19 11:28:05 +00:00
it ( "createGift should fail amount is zero" , async function ( ) {
try {
await testCreateGift ( keycard _1 , 0 ) ;
assert . fail ( "createGift should have failed" ) ;
} catch ( e ) {
assert . match ( e . message , /invalid amount/ ) ;
}
} ) ;
2020-02-18 19:23:31 +00:00
2020-02-19 11:28:05 +00:00
it ( "createGift fails if amount > totalSupply" , async function ( ) {
try {
await testCreateGift ( keycard _1 , TOTAL _SUPPLY + 1 ) ;
assert . fail ( "createGift should have failed" ) ;
} catch ( e ) {
assert . match ( e . message , /low supply/ ) ;
}
} ) ;
2020-02-18 19:23:31 +00:00
2020-02-19 11:28:05 +00:00
it ( "createGift" , async function ( ) {
await testCreateGift ( keycard _1 , GIFT _AMOUNT ) ;
} ) ;
2020-02-18 19:23:31 +00:00
2020-02-19 11:28:05 +00:00
it ( "createGift should fail if keycard has already been used" , async function ( ) {
try {
await testCreateGift ( keycard _1 , 1 ) ;
assert . fail ( "createGift should have failed" ) ;
} catch ( e ) {
assert . match ( e . message , /keycard already used/ ) ;
}
} ) ;
2020-02-18 19:23:31 +00:00
2020-02-19 11:28:05 +00:00
it ( "createGift amount > availableSupply" , async function ( ) {
try {
await testCreateGift ( keycard _2 , TOTAL _SUPPLY - GIFT _AMOUNT + 1 ) ;
assert . fail ( "createGift should have failed" ) ;
} catch ( e ) {
assert . match ( e . message , /low supply/ ) ;
}
} ) ;
2020-02-18 19:23:31 +00:00
2020-02-19 11:28:05 +00:00
async function testRedeem ( redeemCode ) {
2020-02-21 11:41:03 +00:00
let totalSupply = await GiftBucket . methods . totalSupply ( ) . call ( ) ;
2020-02-19 13:35:11 +00:00
assert . equal ( parseInt ( totalSupply ) , TOTAL _SUPPLY , ` total contract supply is ${ totalSupply } instead of ${ TOTAL _SUPPLY } ` ) ;
2020-02-18 19:23:31 +00:00
2020-02-21 11:41:03 +00:00
let factoryBalance = await TestToken . methods . balanceOf ( GiftBucket . _address ) . call ( ) ;
2020-02-19 13:35:11 +00:00
assert . equal ( parseInt ( factoryBalance ) , TOTAL _SUPPLY , ` factory balance before is ${ factoryBalance } instead of ${ TOTAL _SUPPLY } ` ) ;
2020-02-18 19:23:31 +00:00
2020-02-19 11:28:05 +00:00
let userBalance = await TestToken . methods . balanceOf ( user ) . call ( ) ;
2020-02-19 13:35:11 +00:00
assert . equal ( parseInt ( userBalance ) , 0 , ` user balance is ${ userBalance } instead of 0 ` ) ;
2020-02-18 19:23:31 +00:00
2020-02-21 11:41:03 +00:00
// const gift = await GiftBucket.methods.gifts(keycard_1).call();
2020-02-19 11:28:05 +00:00
// const giftBlockNumber = gift.blockNumber;
// const message = web3.utils.sha3(user);
// const sig = await web3.eth.sign(message, keycard_1);
2020-02-18 19:23:31 +00:00
2020-02-19 11:28:05 +00:00
const message = {
keycard : keycard _1 ,
receiver : user ,
code : redeemCode ,
} ;
2020-02-18 19:23:31 +00:00
2020-02-21 11:41:03 +00:00
const sig = await signRedeem ( GiftBucket . _address , keycard _1 , message ) ;
const redeem = GiftBucket . methods . redeem ( message , sig ) ;
2020-02-19 11:28:05 +00:00
const redeemGas = await redeem . estimateGas ( ) ;
await redeem . send ( {
2020-02-19 13:35:11 +00:00
from : keycard _1 ,
2020-02-19 11:28:05 +00:00
gas : redeemGas ,
} ) ;
2020-02-21 11:41:03 +00:00
factoryBalance = await TestToken . methods . balanceOf ( GiftBucket . _address ) . call ( ) ;
2020-02-19 13:35:11 +00:00
assert . equal ( parseInt ( factoryBalance ) , TOTAL _SUPPLY - GIFT _AMOUNT , ` factoryBalance after redeem should be ${ TOTAL _SUPPLY - GIFT _AMOUNT } instead of ${ factoryBalance } ` ) ;
2020-02-19 11:28:05 +00:00
userBalance = await TestToken . methods . balanceOf ( user ) . call ( ) ;
2020-02-19 13:35:11 +00:00
assert . equal ( parseInt ( userBalance ) , GIFT _AMOUNT , ` user ` , ` userBalance after redeem should be ${ GIFT _AMOUNT } instead of ${ userBalance } ` ) ;
2020-02-19 11:28:05 +00:00
2020-02-21 11:41:03 +00:00
totalSupply = await GiftBucket . methods . totalSupply ( ) . call ( ) ;
2020-02-19 13:35:11 +00:00
assert . equal ( parseInt ( totalSupply ) , TOTAL _SUPPLY - GIFT _AMOUNT , ` totalSupply after redeem should be ${ TOTAL _SUPPLY - GIFT _AMOUNT } instead of ${ totalSupply } ` ) ;
2020-02-19 11:28:05 +00:00
}
it ( "cannot redeem after expiration date" , async function ( ) {
await mineAt ( EXPIRATION _TIME ) ;
try {
await testRedeem ( REDEEM _CODE ) ;
assert . fail ( "redeem should have failed" ) ;
} catch ( e ) {
assert . match ( e . message , /expired/ ) ;
}
} ) ;
it ( "cannot redeem with invalid code" , async function ( ) {
await mineAt ( NOW ) ;
try {
await testRedeem ( web3 . utils . sha3 ( "bad-code" ) ) ;
assert . fail ( "redeem should have failed" ) ;
} catch ( e ) {
assert . match ( e . message , /invalid code/ ) ;
}
} ) ;
it ( "can redeem before expiration date" , async function ( ) {
await mineAt ( NOW ) ;
await testRedeem ( REDEEM _CODE ) ;
} ) ;
async function testKill ( ) {
let shopBalance = await TestToken . methods . balanceOf ( shop ) . call ( ) ;
assert . equal ( parseInt ( shopBalance ) , 0 ) ;
2020-02-21 11:41:03 +00:00
let factoryBalance = await TestToken . methods . balanceOf ( GiftBucket . _address ) . call ( ) ;
2020-02-19 11:28:05 +00:00
assert . equal ( parseInt ( factoryBalance ) , TOTAL _SUPPLY - GIFT _AMOUNT ) ;
2020-02-21 11:41:03 +00:00
await GiftBucket . methods . kill ( ) . send ( {
2020-02-19 11:28:05 +00:00
from : shop ,
} ) ;
shopBalance = await TestToken . methods . balanceOf ( shop ) . call ( ) ;
assert . equal ( parseInt ( shopBalance ) , TOTAL _SUPPLY - GIFT _AMOUNT ) ;
2020-02-21 11:41:03 +00:00
factoryBalance = await TestToken . methods . balanceOf ( GiftBucket . _address ) . call ( ) ;
2020-02-19 11:28:05 +00:00
assert . equal ( parseInt ( factoryBalance ) , 0 ) ;
}
it ( "shop cannot kill contract before expirationTime" , async function ( ) {
await mineAt ( NOW ) ;
try {
await testKill ( ) ;
assert . fail ( "redeem should have failed" ) ;
} catch ( e ) {
assert . match ( e . message , /not expired yet/ ) ;
}
} ) ;
it ( "shop can kill contract after expirationTime" , async function ( ) {
await mineAt ( EXPIRATION _TIME ) ;
await testKill ( ) ;
} ) ;
2020-02-18 19:23:31 +00:00
} ) ;