1

[SOLVED]: See below.

I am taking a blockchain and security class and we are working with vyper. We have been tasked with rewriting a fundraising smart contract. However, the compilers do not seem to give much information about errors within your code. I started on remix, which only told me that my code failed to compile but not why. I switch to vyper.online and got this error message:

vyper.online: 'Name' object has no attribute 'func'

Since the line number is not given nor is the applicable function I am at a loss for what I should be looking for. In two other compilers I get the following error messages:

Etherscan: IsADirectoryError: [Errno 21] Is a directory: 'vyper-in-NPSnEgc1jPs2mP9.vy'

jacqueswww.github:

enter image description here

Can anyone give some insight into where I have gone wrong? I have looked at some other similar questions and they have answered about having a function name and a model name being the same, but I don't think that is the case here.

Fundraiser.vy

struct Contributor:
    userAddress: address
    contribution: wei_value

contributors: map(int128, Contributor)
nextContributorsIndex: int128
owner: address
target: public(wei_value)
endTime: public(timestamp)

@public
@payable
def __init__(_target: uint256, _duration: uint256):
    self.owner = msg.sender
    self.target = _target
    self.endTime = block.timestamp + _duration

@public
@payable
def contribute():
    assert block.timestamp < self.endTime
    nci: int128 = self.nextContributorsIndex
    self.contributors[nci] = Contributor({userAddress: msg.sender, contribution: msg.value})
    self.nextContributorsIndex = nci + 1

@public
def collect():
    assert self.balance >= self.target
    assert msg.sender == self.owner
    selfdestruct(self.owner)

@public
def refund():
    assert block.timestamp > self.endTime
    assert self.balance < self.target
    for i in self.nextContributorsIndex:
        send(self.contributors[i].userAddress, self.contributors[i].contribution)
        clear(self.contributors[i])

@public
@constant
def retBalance() -> wei_value:
    return self.balance

[Answer]: I found pretty much the exact contract as an example on this website:

https://vyper.readthedocs.io/en/v0.1.0-beta.6/vyper-by-example.html

The key point is found in the following image.

enter image description here

As I understand vyper does not like the gas expenditure that comes with potentially large loops so the creator of the example has the contributors to the fundraiser refunded in groups of 30. I still do not fully understand how this works but its the best answer that I have.

2

Part answer...

The issue is in the refund() function.

This line requires the use of range() (nextContributorsIndex is an integer, not an array):

for i in self.nextContributorsIndex:

Should be:

for i in range(self.nextContributorsIndex):

Having said this, PR #1100 introduced the requirement that the input to range() should be a constant, and your variable isn't. I'm unsure how to get around this restriction.

| improve this answer | |
  • 1
    Thank you for taking the time to answer this. I found an example online which turned out to be exactly what you had said. vyper.readthedocs.io/en/v0.1.0-beta.6/vyper-by-example.html I guess because vyper protects its loops against massive gas expenditure the example has a contributors refunded in sets of 30. Interesting stuff. – David Meyer Dec 6 '19 at 23:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.