Skip to content

Commit

Permalink
Create Gambling Game smart contract
Browse files Browse the repository at this point in the history
  • Loading branch information
ansabgillani committed May 15, 2024
1 parent f48420e commit 946b5d8
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 2 deletions.
7 changes: 6 additions & 1 deletion contract/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ vote:
instance-q:
agd query vstorage data published.agoricNames.instance -o json

start-contract: start-contract-mint start-contract-swap start-contract-pay
start-contract: start-contract-mint start-contract-swap start-contract-pay start-contract-gambling-game

start-contract-mint:
yarn node scripts/deploy-contract.js \
Expand All @@ -78,6 +78,11 @@ start-contract-pay:
--install src/postal-service.contract.js \
--eval src/postal-service.proposal.js

start-contract-gambling-game:
yarn node scripts/deploy-contract.js \
--install src/gambling-game.contract.js \
--eval src/gambling-game.proposal.js

# bundle-X.json.installed show that bundle-X.json was installed
# see also e2e-tools.js
%.json.installed: %.json
Expand Down
6 changes: 5 additions & 1 deletion contract/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,18 @@
"@agoric/ertp": "^0.16.3-u14.0",
"@agoric/governance": "^0.10.4-u14.0",
"@agoric/inter-protocol": "0.16.2-u14.1",
"@agoric/notifier": "^0.6.3-u14.0",
"@agoric/vats": "0.15.2-u14.0",
"@agoric/zoe": "^0.26.3-u14.0",
"@agoric/zoe": "^0.26.3-u15.0",
"@endo/bundle-source": "^2.8.0",
"@endo/far": "^0.2.22",
"@endo/init": "^0.5.60",
"@endo/marshal": "^0.8.9",
"@endo/patterns": "^0.2.5"
},
"resolutions": {
"**/@agoric/zoe": "0.26.3-u15.0"
},
"ava": {
"files": [
"test/**/test-*.js"
Expand Down
5 changes: 5 additions & 0 deletions contract/rollup.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { permit as postalServicePermit } from './src/postal-service.proposal.js'
import { permit as swapPermit } from './src/swaparoo.proposal.js';
import { permit as sellPermit } from './src/sell-concert-tickets.proposal.js';
import { permit as boardAuxPermit } from './src/platform-goals/board-aux.core.js';
import { permit as gamblingGamePermit } from './src/gambling-game.proposal.js';

/**
* @param {*} opts
Expand Down Expand Up @@ -89,5 +90,9 @@ const config = [
name: 'postal-service',
permit: postalServicePermit,
}),
config1({
name: 'gambling-game',
permit: gamblingGamePermit,
}),
];
export default config;
57 changes: 57 additions & 0 deletions contract/src/gambling-game.contract.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// @ts-check

/*
The contract is a gambling game where the 14th person to send IST to the contract wins all IST in the contract. It demonstrates how to prevent a forceful send of IST and why the order of operations in a function are important.
This is a simple example of the dangers of a smart contracts and why testing and auditing are important. All developers have bugs in their code and it is only a matter of time until they are found.
Once the winner is decided, they can claim the reward which transfers all the IST to their wallet. The game starts all over again and the contract does not end.
*/

import { AmountMath } from '@agoric/ertp';
import { makeNotifierKit } from '@agoric/notifier';

const start = zcf => {
const { zcfSeat: contractSeat } = zcf.makeEmptySeatKit();

const MAX_ENTRIES = 14;
let entries = [];
const { notifier, updater } = makeNotifierKit();

const depositInvitation = zcf.makeInvitation(async seat => {
const offerAmount = seat.getAmountAllocated('IST');
const depositAmount = AmountMath.coerce(zcf.getBrandForIssuer(zcf.getIssuerForBrand(offerAmount.brand)), offerAmount);

// Prevent reentrancy attacks by updating state before making external calls
entries.push(seat);

if (entries.length === MAX_ENTRIES) {
const winnerSeat = entries[MAX_ENTRIES - 1];
const payoutAmount = contractSeat.getAmountAllocated('IST');
contractSeat.decrementBy(contractSeat.getCurrentAllocation());
winnerSeat.incrementBy(payoutAmount);

zcf.reallocate(contractSeat, winnerSeat);

winnerSeat.exit();
entries = []; // Reset the game
} else {
seat.exit();
}

updater.updateState(entries.length);

// Transfer funds from player to contract
contractSeat.incrementBy(depositAmount);
zcf.reallocate(contractSeat, seat);
}, 'Deposit IST');

return {
publicFacet: {
makeDepositInvitation: () => depositInvitation,
getEntriesNotifier: () => notifier,
getEntriesCount: () => entries.length,
},
};
};

harden(start);
export { start };
64 changes: 64 additions & 0 deletions contract/src/gambling-game.proposal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { E } from '@endo/far';
import { AmountMath, makeIssuerKit } from '@agoric/ertp';
import { makeZoeKit } from '@agoric/zoe';
// import { makeFakeVatAdmin } from '@agoric/zoe/tools/fakeVatAdmin';
import { start } from './gambling-game.contract.js';

const contractName = 'gambling-game';

const startGame = async () => {
const { zoeService } = makeZoeKit(null);

// Create IST issuer and mint
const { issuer, mint, brand } = makeIssuerKit('IST');

// Install the contract code
const installation = await E(zoeService).install(start);

// Start the instance
const { publicFacet } = await E(zoeService).startInstance(installation, { IST: issuer });

// Mint some IST to test with
const aliceAmount = AmountMath.make(brand, 100n);
const alicePayment = mint.mintPayment(aliceAmount);

const aliceInvitation = E(publicFacet).makeDepositInvitation();
const proposal = { give: { IST: aliceAmount } };
const payments = { IST: alicePayment };

// Make an offer to deposit IST
const seat = await E(zoeService).offer(aliceInvitation, proposal, payments);
console.log('Alice made a deposit.', seat);

// Check the number of entries
const entriesCount = await E(publicFacet).getEntriesCount();
console.log(`Current number of entries: ${entriesCount}`);
};

// Define a manifest object describing the contract's capabilities and permissions
export const manifest = /** @type {const} */ ({
[startGame.name]: {
// Define entry for the postalService contract
consume: {
// Resources consumed by the contract
agoricNames: true, // Needs access to the agoricNames registry
namesByAddress: true, // Needs access to the namesByAddress registry
namesByAddressAdmin: true, // Needs administrative access to the namesByAddress registry
startUpgradable: true, // Allows upgrades to the contract
zoe: true, // Needs access to the Zoe service for contract execution
},
installation: {
// Capabilities provided by the contract during installation
consume: { [contractName]: true },
produce: { [contractName]: true },
},
instance: {
// Capabilities provided by the contract instance
produce: { [contractName]: true }, // Produces a "postalService" instance
},
},
});

// Define the permit object based on the manifest
export const permit = Object.values(manifest)[0];
export const main = startGame;
25 changes: 25 additions & 0 deletions contract/test/test-gambling-game.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import test from 'ava';
import { E } from '@endo/far';
import { AmountMath, makeIssuerKit } from '@agoric/ertp';
import { makeZoeKit } from '@agoric/zoe';
import { makeFakeVatAdmin } from '@agoric/zoe/tools/fakeVatAdmin';
import { start } from '../src/gambling-game.contract.js';

test('Gambling game contract', async t => {
const { zoeService } = makeZoeKit(makeFakeVatAdmin().admin);
const { issuer, mint, brand } = makeIssuerKit('IST');

const installation = await E(zoeService).install(start);
const { publicFacet } = await E(zoeService).startInstance(installation, { IST: issuer });

const aliceAmount = AmountMath.make(brand, 100n);
const alicePayment = mint.mintPayment(aliceAmount);

const aliceInvitation = E(publicFacet).makeDepositInvitation();
const proposal = { give: { IST: aliceAmount } };
const payments = { IST: alicePayment };

await E(zoeService).offer(aliceInvitation, proposal, payments);
t.is(await E(publicFacet).getEntriesCount(), 1);
});

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"@agoric/governance": "0.10.4-u14.0",
"@agoric/store": "0.9.3-u14.0",
"@agoric/xsnap": "0.14.3-u14.0",
"**/@agoric/zoe": "0.26.3-u15.0",
"@agoric/vat-data": "0.5.3-u14.0",
"@endo/bundle-source": "2.5.2-upstream-rollup",
"@endo/captp": "3.1.1",
Expand Down

0 comments on commit 946b5d8

Please sign in to comment.