Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Pythonic Promise API for Cross-Contract Calls #5

Open
wants to merge 20 commits into
base: main
Choose a base branch
from

Conversation

r-near
Copy link
Owner

@r-near r-near commented Mar 5, 2025

Summary

This PR introduces a new Pythonic Promise API for NEAR cross-contract calls. The API significantly improves the developer experience by providing a fluent, chainable interface for asynchronous operations while maintaining full compatibility with the existing functionality.

Motivation

The current cross-contract call API is functional but has several usability issues:

  • Verbose syntax with multiple parameters
  • Manual JSON parsing in callbacks
  • No method chaining for promise operations
  • Error-prone context passing between callbacks
  • Repetitive boilerplate code for common operations

The new Promise API addresses these issues with a clean, Pythonic interface that leverages modern Python features like method chaining and keyword arguments.

Changes

  • Added promises.py with a fluent API for cross-contract calls
  • Renamed the original Contract class to BaseContract to avoid conflicts
  • Enhanced callback functionality with automatic data parsing
  • Added comprehensive documentation in the docs directory

New API Features

The new API provides:

  1. Fluent Interface:

    # Before
    promise = CrossContract.call("token.near", "ft_metadata")
    callback = CrossContract.then(promise, "current.near", "on_metadata")
    CrossContract.return_value(callback)
    
    # After
    token = Contract("token.near")
    promise = token.call("ft_metadata").then("on_metadata")
    return promise.value()
  2. Simplified Callbacks:

    # Before
    @callback
    def on_metadata(self, promise_result):
        if promise_result["status"] == "Successful":
            data = json.loads(promise_result["data"].decode("utf-8"))
            # Process data...
    
    # After
    @callback
    def on_metadata(self, data):
        # data is already parsed
        # Process data...
  3. Better Context Passing:

    # Pass context directly to callbacks
    promise = token.call("ft_metadata").then("on_metadata", token_id="near")
    
    # Access context in callbacks
    @callback
    def on_metadata(self, data, token_id=None):
        # Use token_id directly
  4. Improved Error Handling:

    • Automatic error detection and standardized error responses
    • Helper methods for safely accessing data

Documentation

The PR includes comprehensive documentation:

  • Promise API Overview
  • Quick Start Guide
  • API Reference
  • Advanced Patterns
  • Examples for common use cases
  • Migration Guide

Breaking Changes

None. This PR introduces a new API without modifying existing functionality. The original CrossContract API remains fully functional.

Usage Example

from near_sdk_py import call
from .promises import Contract, callback

class TokenExample:
    @call
    def get_token_data(self, token_id):
        token = Contract(f"token.{token_id}.near")
        
        promise = token.call("ft_metadata").then(
            "on_metadata_received", token_id=token_id
        )
        
        return promise.value()
    
    @callback
    def on_metadata_received(self, metadata, token_id=None):
        return {
            "token_id": token_id,
            "name": metadata.get("name", "Unknown"),
            "symbol": metadata.get("symbol", "???"),
            "decimals": metadata.get("decimals", 0)
        }

Future Work

  • Additional helper methods for common patterns
  • Support for batch operations
  • Type hint improvements for better IDE integration

@frol
Copy link

frol commented Mar 5, 2025

With this API I have a bunch of open questions:

  1. How to attach NEAR tokens to the function call?
  2. How to specify the gas limit? (there are two options: a fixed amount of gas or proportional of the gas left from the execution)
  3. How to create complex promises (e.g. Create Account, Transfer, Deploy Contract, Call Function)?
  4. How to handle the error result with the callback?

Copy link

agentfarmx bot commented Mar 5, 2025

No operation ID found for this PR

@r-near
Copy link
Owner Author

r-near commented Mar 5, 2025

@race-of-sloths

Copy link

agentfarmx bot commented Mar 5, 2025

No operation ID found for this PR

@race-of-sloths
Copy link

@r-near Thank you for your contribution! Your pull request is now a part of the Race of Sloths!
Do you want to apply for monthly streak? Get 8+ score for a single PR this month and receive boost for race-of-sloths!

Shows inviting banner with latest news.

Shows profile picture for the author of the PR

Current status: waiting for scoring

We're waiting for maintainer to score this pull request with @race-of-sloths score [0,1,2,3,5,8,13] command. Alternatively, autoscoring [1,2] will be applied for this pull request

What is the Race of Sloths

Race of Sloths is a friendly competition where you can participate in challenges and compete with other open-source contributors within your normal workflow

For contributors:

  • Tag @race-of-sloths inside your pull requests
  • Wait for the maintainer to review and score your pull request
  • Check out your position in the Leaderboard
  • Keep weekly and monthly streaks to reach higher positions
  • Boast your contributions with a dynamic picture of your Profile

For maintainers:

  • Score pull requests that participate in the Race of Sloths and receive a reward
  • Engage contributors with fair scoring and fast responses so they keep their streaks
  • Promote the Race to the point where the Race starts promoting you
  • Grow the community of your contributors

Feel free to check our website for additional details!

Bot commands
  • For contributors
    • Include a PR: @race-of-sloths include to enter the Race with your PR
  • For maintainers:
    • Invite contributor @race-of-sloths invite to invite the contributor to participate in a race or include it, if it's already a runner.
    • Assign points: @race-of-sloths score [1/2/3/5/8/13] to award points based on your assessment.
    • Reject this PR: @race-of-sloths exclude to send this PR back to the drawing board.
    • Exclude repo: @race-of-sloths pause to stop bot activity in this repo until @race-of-sloths unpause command is called

@r-near r-near force-pushed the fluent-promises branch from e919ef9 to fb16b6f Compare March 6, 2025 01:21
@r-near r-near changed the title Pythonic Promise API for Cross-Contract Calls feat: Pythonic Promise API for Cross-Contract Calls Mar 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants