Need help deploying/testing contract with forgAE

Hi,

I am trying to deploy a contract that needs a map(address, int) as parameter for the init function and cannot get it working :frowning:

I try to deploy it as follows:

let myMap= new Map();
myMap.set(keyPair1.publicKey, 30);
myMap.set(keyPair2.publicKey, 70);
console.log(myMap);
contractSource = utils.readFileRelative('./contracts/MyContract.aes', "utf-8"); // Read the aes file
contractClient = await clientOwner.getContractInstance(contractSource);
const deploy = await contractClient.deploy([myMap]);

When running forgae test I always get the following error:

Error: Http request for https://compiler.aepps.com/encode-calldata failed with status code 403. Status: Forbidden. 
Error data: {"reason":"Parse errors\nline 29, column 37: Unexpected token con"}

I appreciate your help. Thanks! :slight_smile:

2 Likes

Hello @marco.chain,

there seems to be a bug in our SDK in the version you use. When you update the SDK in your package.json to 3.2.1. Your exact example should be working.

Instead of new Map(); you can also pass javascript objects {[keyPair1.publicKey]: 30, [keyPair2.publicKey]: 70}. Both will work.

Hope this helps :slight_smile: Let me know if you have any more questions.

3 Likes

sounds good. hopefully I hadn’t used that already :smiley:

1 Like

this seems to work now, great!

@philipp.chain can you also help me out how to access a list converted from a map? I have a map where I need to iterate over and sum up all int values

private function validateConditions(myMap': map(address, int)) : bool =
      let myList: list((address, int)) = Map.to_list(myMap')
      ???
      true

I want to iterate over that list and sum up all int values but I don’t know how to do that

1 Like

You will need to make a recursive function call where you deconstruct the list/tuples. Do you want to check if all entries of the map behave to a condition? is it fine if the return value is not boolean, but abort if the condition is not meet for one entry?

yeah it would be ok to abort if the condition is not met. but the condition is that the sum of all int values equals 100

Even better, thats more simple

first lets define some list helper functions

private function map(f : 'a => 'b, l : list('a)) : list('b) =
  switch(l)
    [] => []
    e :: l' => f(e) :: map(f, l')

private function foldr(f : (('a, 'b) => 'b), z: 'b, l : list('a)) : 'b =
  switch(l)
    [] => z
    e :: l' => f(e, foldr(f, z, l'))

private function sum(l : list('a), f : 'a => int) : int =
  foldr((x, y) => x + y, 0, map(f, l))

private function pair_second(tuple) =
  switch(tuple)
    (_, e) => e

then you can go ahead and do

private function validateConditions(myMap: map(address, int)) : bool =
  let myList: list((address, int)) = Map.to_list(myMap')
  let intList: list(int) = map(pair_second, myList)
  let intSum: int = sum(intList, x => x) 
  true

I have not tried this, but it should be working like this.

1 Like

as already figured out in telegram this is working fine, thanks!

the only thing that I needed to change was using sum(intList, (x) => x) instead of sum(intList, x => x)

but I definitely need to better understand what’s going on under the hood of these helper functions :sweat_smile::+1:

2 Likes

I was and am still in contact with @philipp.chain regarding the development of my contract.

For some reason I am not able to test the function payAndSplit in my contract. With the current state of the source code I always get an error out of gas (which should never be the case because of the automated fee calculation).

When I manually set a quite high amount of gas in the function call I get an error that the await fails after wating for 10 blocks. The tx isn’t mined.

However it seems like there is an issue with my function or with my setup but I can’t find it. Any help is appreciated!

Here the current source-code:

The error is in this switch statement:

   private function split(recipientConditions': list((address, int)), totalValue: int) =
      switch(recipientConditions')
         (recipient, weight) :: l' =>
            Chain.spend(recipient, totalValue / 100 * weight)
            split(l', totalValue)

It is missing the base case. What would it do when the list of recipientConditions is empty? There is no matching switch statement thus it will run out of gas. So adding:

    [] => ()

should solve that.

And in the second case, what happens if you too much gas is that the transaction no longer fits in a microblock and it will not be mined.

2 Likes

will check as soon as I am at home :slight_smile:

edit: it works now, thx @hanssv.chain!

1 Like