-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f48420e
commit 946b5d8
Showing
7 changed files
with
163 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
}); | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters