Allow truffle projects to contain vyper contracts (#571)

add-typechain-instructions
cgewecke 4 years ago committed by GitHub
parent c88eed29e7
commit b6c483976e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 8
      plugins/resources/plugin.utils.js
  2. 82
      test/sources/solidity/contracts/app/auction.vy
  3. 30
      test/units/truffle/standard.js
  4. 10
      test/util/integration.js

@ -131,7 +131,7 @@ function checkContext(config, tempContractsDir, tempArtifactsDir){
// =============================
function assembleFiles(config, skipFiles=[]){
const targetsPath = path.join(config.contractsDir, '**', '*.sol');
const targetsPath = path.join(config.contractsDir, '**', '*.{sol,vy}');
const targets = shell.ls(targetsPath).map(path.normalize);
skipFiles = assembleSkipped(config, targets, skipFiles);
@ -145,7 +145,7 @@ function assembleTargets(config, targets=[], skipFiles=[]){
const cd = config.contractsDir;
for (let target of targets){
if (skipFiles.includes(target)){
if (skipFiles.includes(target) || path.extname(target) === '.vy'){
skipped.push({
canonicalPath: target,
@ -177,7 +177,9 @@ function assembleSkipped(config, targets, skipFiles=[]){
skipFiles = skipFiles.map(contract => path.join(config.contractsDir, contract));
// Enumerate files in skipped folders
const skipFolders = skipFiles.filter(item => path.extname(item) !== '.sol')
const skipFolders = skipFiles.filter(item => {
return path.extname(item) !== '.sol' || path.extname(item) !== '.vy'
});
for (let folder of skipFolders){
for (let target of targets ) {

@ -0,0 +1,82 @@
# Open Auction
# Auction params
# Beneficiary receives money from the highest bidder
beneficiary: public(address)
auctionStart: public(uint256)
auctionEnd: public(uint256)
# Current state of auction
highestBidder: public(address)
highestBid: public(uint256)
# Set to true at the end, disallows any change
ended: public(bool)
# Keep track of refunded bids so we can follow the withdraw pattern
pendingReturns: public(HashMap[address, uint256])
# Create a simple auction with `_bidding_time`
# seconds bidding time on behalf of the
# beneficiary address `_beneficiary`.
@external
def __init__(_beneficiary: address, _bidding_time: uint256):
self.beneficiary = _beneficiary
self.auctionStart = block.timestamp
self.auctionEnd = self.auctionStart + _bidding_time
# Bid on the auction with the value sent
# together with this transaction.
# The value will only be refunded if the
# auction is not won.
@external
@payable
def bid():
# Check if bidding period is over.
assert block.timestamp < self.auctionEnd
# Check if bid is high enough
assert msg.value > self.highestBid
# Track the refund for the previous high bidder
self.pendingReturns[self.highestBidder] += self.highestBid
# Track new high bid
self.highestBidder = msg.sender
self.highestBid = msg.value
# Withdraw a previously refunded bid. The withdraw pattern is
# used here to avoid a security issue. If refunds were directly
# sent as part of bid(), a malicious bidding contract could block
# those refunds and thus block new higher bids from coming in.
@external
def withdraw():
pending_amount: uint256 = self.pendingReturns[msg.sender]
self.pendingReturns[msg.sender] = 0
send(msg.sender, pending_amount)
# End the auction and send the highest bid
# to the beneficiary.
@external
def endAuction():
# It is a good guideline to structure functions that interact
# with other contracts (i.e. they call functions or send Ether)
# into three phases:
# 1. checking conditions
# 2. performing actions (potentially changing conditions)
# 3. interacting with other contracts
# If these phases are mixed up, the other contract could call
# back into the current contract and modify the state or cause
# effects (Ether payout) to be performed multiple times.
# If functions called internally include interaction with external
# contracts, they also have to be considered interaction with
# external contracts.
# 1. Conditions
# Check if auction endtime has been reached
assert block.timestamp >= self.auctionEnd
# Check if this function has already been called
assert not self.ended
# 2. Effects
self.ended = True
# 3. Interaction
send(self.beneficiary, self.highestBid)

@ -467,4 +467,34 @@ describe('Truffle Plugin: standard use cases', function() {
verify.lineCoverage(expected);
})
it('compiles when a project includes vyper contracts', async function() {
const skipMigration = true;
truffleConfig.logger = mock.testLogger;
solcoverConfig.istanbulReporter = ['json-summary', 'text']
mock.installDouble(
['Simple', 'auction.vy'],
'simple.js',
solcoverConfig,
skipMigration
);
await plugin(truffleConfig);
assert(
mock.loggerOutput.val.includes('Compiling ./.coverage_contracts/auction.vy')
);
const expected = [
{
file: mock.pathToContract(truffleConfig, 'Simple.sol'),
pct: 100
}
];
verify.lineCoverage(expected);
});
})

@ -303,7 +303,7 @@ function install(
/**
* Installs mock truffle/buidler project with two contracts (for inheritance, libraries, etc)
*/
function installDouble(contracts, test, config) {
function installDouble(contracts, test, config, skipMigration) {
const configjs = getSolcoverJS(config);
const migration = deployDouble(contracts);
@ -313,11 +313,15 @@ function installDouble(contracts, test, config) {
// Contracts
contracts.forEach(item => {
shell.cp(`${sourcesPath}${item}.sol`, `${temp}/contracts/${item}.sol`)
(item.includes('.'))
? shell.cp(`${sourcesPath}${item}`, `${temp}/contracts/${item}`)
: shell.cp(`${sourcesPath}${item}.sol`, `${temp}/contracts/${item}.sol`);
});
// Migration
fs.writeFileSync(migrationPath, migration)
if (!skipMigration){
fs.writeFileSync(migrationPath, migration)
}
// Test
shell.cp(`${testPath}${test}`, `${temp}/test/${test}`);

Loading…
Cancel
Save