Does payable macro change the function parameters? - nearprotocol

in rust, nft_mint() declaration
#[payable]
pub fn nft_mint(&mut self, token_id: TokenId, receiver_id: AccountId) -> Self {
// ...
}
using the nft_mint() method in javascript
await contract.nft_mint({}, GAS_AMOUNT, ATTACHED_DEPOSIT);
I see that nft_mint in javascript has three arguments which are different from the rust code.
Is it because of that payable macro?

The contract function arguments are passed in the first argument (object) on JS side, so it should be:
await contract.nft_mint({ token_id: "my_kitten", receiver_id: "frol.near" }, GAS_AMOUNT, ATTACHED_DEPOSIT);
“payable” attribute just adds a single assert at the beginning of the function body that checks that the attached deposit is non-zero. It does not alter the function arguments.

Related

Node Promise with Local Variable

async function A(){
const x = await B(); // reads a file or such thing
return x; // returns a promise
}
var foo;
function setFoo(){
foo = A(); // foo will be set to the promise returned by A()
// but I really want foo to be set to the data
// returned by the promise
}
function C(){
// here I need to use the value of the data returned
// by the promise. There are dozens of functions that
// will use foo. Those dozens of functions are called
// from outside of this module
}
Question - Is there some way to extract the data from the promise so I can use it in a local variable? Or do I need to use promise semantics i.e .then(function(...){...}) in every function like function C that needs to use the local variable foo? Or something else?
Don't use async in a function that does nothing other than return await. Just return the promise and you're done.
function A() {
return B(); // reads a file or such thing, returns a promise
}
Never try to set global/outer-scope variables to capture asynchronous values. Keep returning the promises, chain in worker functions with .then(). Keep returning the promise chain.
function foo(){
return A().then(C);
}
The worker functions (an event handler, really) receive the data:
function C(data) {
// here you get the data returned by B()
}
You could even wait for C() now:
foo().then(function (x) {
// `C()` ans finished and `x` will be whatever `C()` returned.
})

Testing error for function call to a non-contract account

While testing our VRF getRandomNumber(s) with test-helpers, we keep on getting Error: Transaction reverted: function call to a non-contract account at:
require(LINK.balanceOf(address(this)) > fee, "Not enough LINK to initialte function call");
LINK seems to be used correctly here. What's the meaning/issue with the non-contract account?
Other tests on the same RandomNumberConsumer object are successful.
contract RandomNumberConsumer is VRFConsumerBase {
[...]
function getRandomNumber(uint256 userProvidedSeed) public returns (bytes32 requestId) {
require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK - fill contract with faucet");
return requestRandomness(keyHash, fee, userProvidedSeed);
}
describe("getRandomNumber()", function() {
it("Should return a requestID", async function() {
const requestId = await randomNumberConsumer.getRandomNumber(12);
// checks on requestId
});
});
Any LINK.xxx() call refers to the external LINK contract which is not existent in your code. It's a contract already deployed on the network - that's why you're most probably passing the LINK address to the constructor of your contract.
To make it work in the test, you need to mock something so that your test doesn't end up calling the real LINK interface. One of the ways would be to mock your getRandomNumber function. Since it's public, that should be easily doable with Waffle's mocking utils: https://ethereum-waffle.readthedocs.io/en/latest/mock-contract.html.
Alternatively (probably more legit, but longer) you can mock the entire LINK contract:
Have some Mocks.sol contract:
pragma solidity ^0.8.7;
import "#chainlink/contracts/src/v0.8/interfaces/LinkTokenInterface.sol";
abstract contract LinkMock is LinkTokenInterface {}
Initialize it as a mock in your test and pass its address to your mock contract as the first argument, as per the VRF documentation:
import { waffle } from 'hardhat'
import { abi as linkMockAbi } from '../artifacts/contracts/Mocks.sol/LinkMock.json'
const [deployer, vrfCoordinatorMock, ...actors] = waffle.provider.getWallets()
const getContract = async ({ mockedLinkBalance }: { mockedLinkBalance: string }) => {
const linkMockContract = await waffle.deployMockContract(deployer, linkMockAbi)
// Mocks the external LINK contract that we don't have access to during tests
await linkMockContract.mock.balanceOf.returns(ethers.utils.parseEther(mockedLinkBalance))
await linkMockContract.mock.transferAndCall.returns(true)
return waffle.deployContract(deployer, ContractJson, [
vrfCoordinatorMock.address,
linkMockContract.address,
'0x0000000000000000000000000000000000000000000000000000000000000000',
'100000000000000000',
])
}
Call rawFulfillRandomness() which the VRF calls itself, whenever you want to mock the VRF generating the randomness:
const contract = await getContract()
await contract.connect(vrfCoordinatorMock).rawFulfillRandomness('0x0000000000000000000000000000000000000000000000000000000000000000', mockedRandomnessValue)
Note I hardcoded requestId for brevity in the above example. You'll have to come up with a way of stubbing it if you rely on its value in your contract.

How to send near tokens to payable function in near api js and near cli?

I have a following function in the contract:
#[payable]
pub fn buy_tokens(&mut self) {
let amount = env::attached_deposit()
}
But how to call the function in near-api-js and near cli with attached near tokens deposit?
await nearvar.contract.buy_tokens()
Edit:
await nearvar.contract.buy_tokens({}, GAS_AMOUNT, ATTACHED_DEPOSIT);
Gives error {InvalidTxError: {InvalidAccessKeyError: "DepositWithFunctionCall"}
The error seems because of function call action is not allowed with a function call access key https://docs.near.org/docs/roles/integrator/errors/error-implementation
How to call payable function with full access keys?
This is my index file: Link
This is where I am calling the function: Link
The second and third arguments of the functions in the Contract are gas and attached deposit:
await nearvar.contract.buy_tokens({}, GAS_AMOUNT, ATTACHED_DEPOSIT);
Or you can use the Account API (see details here) to do that:
let account = await connection.account(senderAccountId);
account.functionCall(contractId, 'buy_tokens', {}, GAS_AMOUNT, ATTACHED_DEPOSIT);
where GAS_AMOUNT can be 100000000000000 for 100Tgas (can also pass null instead for default 30Tgas).
ATTACHED_DEPOSIT for example for 1N: 10000000000000000000000000

How do you implement specific behavior for a Mockery function

I'm using the Go Mockery package, and I want the function Next to do some actions before returning. However, when I do this:
mockIter.On("Next", mock.AnythingOfType("*types.Query")).Return(func(q *types.Query) bool {
condition := (do something that returns a boolean)
return condition
})
I get this error:
panic: interface conversion: interface {} is func(*types.Query) bool, not bool
I must be using the package wrong, but it seems like this is correct because they have this very similar example in their docs:
Mock.On("passthrough", mock.AnythingOfType("context.Context"), mock.AnythingOfType("string")).Return(func(ctx context.Context, s string) string {
return s
})
Any ideas on what I'm doing wrong?
Return function is used to return values on call of the mocked function. You can't change the signature of the mocked function.
Here you're returning func(*types.Query) bool (function that returns boolean) instead of bool, as the error message say.
You can have the function to make some computation and then return the value. You just have to add () (or whatever arguments your function accepts) after function definition to invoke it and you'll be good to go.
This works:
mockIter.On("Next", mock.AnythingOfType("*types.Query")).Return(func() bool {
condition := (do something that returns a boolean)
return condition
}())
But it seems to me that you want to do some computation based on the argument that is passed on the mocked call. I don't think mockery supports that at the moment.

Fallback callback when calling unavailable function

Is it possible to set a fallback callback which is called when the user wants to call a function which does not exists? E.g.
my_object.ThisFunctionDoesNotExists(2, 4);
Now I want that a function is getting called where the first parameter is the name and a stack (or something like that) with the arguments passed. To clarify, the fallback callback should be a C++ function.
Assuming your question is about embedded V8 engine which is inferred from tags, you can use harmony Proxies feature:
var A = Proxy.create({
get: function (proxy, name) {
return function (param) {
console.log(name, param);
}
}
});
A.hello('world'); // hello world
Use --harmony_proxies param to enable this feature. From C++ code:
static const char v8_flags[] = "--harmony_proxies";
v8::V8::SetFlagsFromString(v8_flags, sizeof(v8_flags) - 1);
Other way:
There is a method on v8::ObjectTemplate called SetNamedPropertyHandler so you can intercept property access. For example:
void GetterCallback(v8::Local<v8::String> property,
const v8::PropertyCallbackInfo<v8::Value>& info)
{
// This will be called on property read
// You can return function here to call it
}
...
object_template->SetNamedPropertyHandler(GetterCallback);

Resources