5

I'm just getting started with solidity, and I'm working on a contract that calculates the periodic payment on an amortized loan. My goal is to implement the annuity formula:

annuity formula

I've started a library for rational data and a struct for the fraction. In order for the library function to compile the function signature requires any struct parameters be marked with the storage keyword.

library Rational
{
    struct FractionUint
    {
        uint numerator;
        uint denominator;
    }

    function multiply(FractionUint storage self, FractionUint storage other)
    {
        self.numerator *= other.numerator;
        self.denominator *= other.denominator;
    }

...
}

contract testRational
{
    using Rational for Rational.FractionUint;
    Rational.FractionUint f1;
    Rational.FractionUint f2;

    function testMultiply()
    {
        f1 = Rational.FractionUint(1,10);
        f2 = FractionUint(100,2);
        f1.multiply(f2);
        if (f1.numerator != 100)
            throw;
        if (f1.denominator != 20)
            throw;
    }

    /*
    function testMultiply2()
    {
        var f3 = Rational.FractionUint(1,10);
        var f4 = Rational.FractionUint(100,2);
        f3.multiply(f4);
        if (f3.numerator != 100)
        throw;
        if (f3.denominator != 20)
        throw;
    }
    */
}

Compiling testMultiply2 restults in the error:

Error: Member "multiply" is not available in struct FractionUint memory outside of storage.

There are multiple intermediate steps for which I'd like to use some variables defined in the scope of the contract function.

Can a library function called from a contract function perform operations on variables defined in the contract function scope?

2 Answers 2

6

Libraries can operate on structs in storage (that's one of their main purposes) but are currently unable to operate on memory structs (lifting this limitation is planned, though).

For your general problem concerning fractional numbers, I would propose different solutions, though:

  1. either combine the two uints into a single uint (256 bits is a lot) or use uint[2] instead of the struct
  2. wait for Solidity to receive fixed point integers (they should come "soon")
1
  • Excellent, I look forward to the fixed point types. I'll hold off until then. Commented Mar 8, 2016 at 22:49
0

Sure you can using Solidity 0.5.x, just define a copy of the same function but with memory instead of storage:

function multiplyMemory(FractionUint memory self, FractionUint memory other) {
    self.numerator *= other.numerator;
    self.denominator *= other.denominator;
}

I case of view methods, you can reuse memory method inside storage one, but be aware struct will we fulle loaded from storage:

function value(Data storage self) internal view returns(uint256) {
    return valueMemory(self);
}

function valueMemory(Data memory self) internal view returns(uint256) {
    return uint256(self.origin).mul(
        now.sub(self.time).mul(self.speed).div(365 days).add(1e18)
    ).div(1e18);
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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