Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions plugins/resources/plugin.utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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,
Expand Down Expand Up @@ -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 ) {
Expand Down
82 changes: 82 additions & 0 deletions test/sources/solidity/contracts/app/auction.vy
Original file line number Diff line number Diff line change
@@ -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)
30 changes: 30 additions & 0 deletions test/units/truffle/standard.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
});
})
10 changes: 7 additions & 3 deletions test/util/integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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}`);
Expand Down