lorentz-contract-originate 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +35 -0
- data/LICENSE.txt +21 -0
- data/README.md +95 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/lorentz-contract-originate.rb +20 -0
- data/lib/lorentz/contract/call.rb +2 -0
- data/lib/lorentz/contract/enumerable.rb +31 -0
- data/lib/lorentz/contract/kernel.rb +64 -0
- data/lib/lorentz/contract/originate/version.rb +7 -0
- data/lib/lorentz/contract/param.rb +348 -0
- data/lib/tezos/client.rb +73 -0
- data/lorentz-contract-originate.gemspec +34 -0
- data/test_yaml/README.md +4 -0
- data/test_yaml/test.originated.yaml +189 -0
- data/test_yaml/test.yaml +84 -0
- metadata +110 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0eb208390f5ea68d13f6a00ccd468911d03aeacb
|
4
|
+
data.tar.gz: 7a7d5938a6f3b5507c5ddba458371f4ef3907dd0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0cb92618633f87117303adad9b6516552be1a22e274ca70a8a1f9b95eca9b915f1c942b93d57a34900f683a1fde6fcee83d123ece239311cdecd5d2db376b64e
|
7
|
+
data.tar.gz: 435614b14377f93df2c982cc9e41efabfd38702e9e083a675138eef216557c988cd1260edd568821f53babc7eaaf6448e1bd22db3b29443f91ea624f377b2c16
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
lorentz-contract-originate (0.1.0)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
diff-lcs (1.3)
|
10
|
+
rake (10.5.0)
|
11
|
+
rspec (3.9.0)
|
12
|
+
rspec-core (~> 3.9.0)
|
13
|
+
rspec-expectations (~> 3.9.0)
|
14
|
+
rspec-mocks (~> 3.9.0)
|
15
|
+
rspec-core (3.9.1)
|
16
|
+
rspec-support (~> 3.9.1)
|
17
|
+
rspec-expectations (3.9.0)
|
18
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
19
|
+
rspec-support (~> 3.9.0)
|
20
|
+
rspec-mocks (3.9.1)
|
21
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
22
|
+
rspec-support (~> 3.9.0)
|
23
|
+
rspec-support (3.9.2)
|
24
|
+
|
25
|
+
PLATFORMS
|
26
|
+
ruby
|
27
|
+
|
28
|
+
DEPENDENCIES
|
29
|
+
bundler (~> 2.0)
|
30
|
+
lorentz-contract-originate!
|
31
|
+
rake (~> 10.0)
|
32
|
+
rspec (~> 3.0)
|
33
|
+
|
34
|
+
BUNDLED WITH
|
35
|
+
2.0.2
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2020 Michael J. Klein
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
# Lorentz::Contract::Originate
|
2
|
+
|
3
|
+
Use `.yaml` files to specify:
|
4
|
+
- users
|
5
|
+
- contract originations
|
6
|
+
- transactions
|
7
|
+
|
8
|
+
in a declarative manner, a la `Makefile`'s.
|
9
|
+
|
10
|
+
For example:
|
11
|
+
|
12
|
+
```yaml
|
13
|
+
config:
|
14
|
+
base-config: &base-config
|
15
|
+
tezos_client_path:
|
16
|
+
"tezos-client -A rpcalpha.tzbeta.net -P 443 -S"
|
17
|
+
user_address:
|
18
|
+
tz1R3vJ5TV8Y5pVj8dicBR23Zv8JArusDkYr
|
19
|
+
param_path:
|
20
|
+
/Users/michaelklein/Coding/forwarder-contract
|
21
|
+
stack_path:
|
22
|
+
/Users/michaelklein/Coding/forwarder-contract/stack
|
23
|
+
|
24
|
+
do:
|
25
|
+
- user:
|
26
|
+
name:
|
27
|
+
Alice
|
28
|
+
address:
|
29
|
+
tz1R3vJ5TV8Y5pVj8dicBR23Zv8JArusDkYr
|
30
|
+
|
31
|
+
- originate: &originate-forwarder
|
32
|
+
alias: ValidatedForwarder1
|
33
|
+
config: $base-config
|
34
|
+
command: dstoken-forwarder-contract print-validated-expiring --central-wallet tz1R3vJ5TV8Y5pVj8dicBR23Zv8JArusDkYr --dstoken-address tz1R3vJ5TV8Y5pVj8dicBR23Zv8JArusDkYr
|
35
|
+
storage_command: dstoken-forwarder-contract initial-storage-validated-expiring
|
36
|
+
initial_storage:
|
37
|
+
dstoken-address: $Alice
|
38
|
+
whitelisted-investors: '"[\"alice\"]"'
|
39
|
+
token-limit: 10
|
40
|
+
expiration-date: "$(date -u -d '9:00 next Fri' +%FT%T.%NZ)"
|
41
|
+
burn_cap: '1.644'
|
42
|
+
|
43
|
+
- run: &validate-forwarder
|
44
|
+
alias: RejectsNonWhitelistedUser
|
45
|
+
config: $base-config
|
46
|
+
contract: ValidatedForwarder1
|
47
|
+
command: dstoken-forwarder-contract validate-transfer
|
48
|
+
parameters:
|
49
|
+
received-amount: 3
|
50
|
+
from-user: "bob"
|
51
|
+
burn_cap: '0.000001'
|
52
|
+
expect_failure: true
|
53
|
+
```
|
54
|
+
|
55
|
+
|
56
|
+
## Installation
|
57
|
+
|
58
|
+
Add this line to your application's Gemfile:
|
59
|
+
|
60
|
+
```ruby
|
61
|
+
gem 'lorentz-contract-originate'
|
62
|
+
```
|
63
|
+
|
64
|
+
And then execute:
|
65
|
+
|
66
|
+
$ bundle
|
67
|
+
|
68
|
+
Or install it yourself as:
|
69
|
+
|
70
|
+
$ gem install lorentz-contract-originate
|
71
|
+
|
72
|
+
|
73
|
+
## Usage
|
74
|
+
|
75
|
+
```bash
|
76
|
+
❯❯❯ bundle exec ruby exe/lorentz-contract-originate.rb test.yaml
|
77
|
+
```
|
78
|
+
|
79
|
+
|
80
|
+
## Development
|
81
|
+
|
82
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
83
|
+
|
84
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
85
|
+
|
86
|
+
|
87
|
+
## Contributing
|
88
|
+
|
89
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/tqtezos/lorentz-contract-originate.
|
90
|
+
|
91
|
+
|
92
|
+
## License
|
93
|
+
|
94
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
95
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "lorentz/contract/originate"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'lorentz/contract/param'
|
2
|
+
require 'tezos/client'
|
3
|
+
|
4
|
+
if __FILE__ == $0
|
5
|
+
if ARGV[1]&.strip == 'info'
|
6
|
+
file_path = ARGV[0]
|
7
|
+
originated_contracts_path = Lorentz::Contract::Param.originated_contracts_path(file_path)
|
8
|
+
originated_yaml = Lorentz::Contract::Param.recursive_yaml(originated_contracts_path)
|
9
|
+
# YAML.load(File.read(originated_contracts_path))
|
10
|
+
originated_yaml['originated'].each do |contract|
|
11
|
+
p contract
|
12
|
+
contract_address = contract[1]['address']
|
13
|
+
base_config = originated_yaml['config']['base-config']
|
14
|
+
tezos_client = Tezos::Client.new(base_config['tezos_client_path'], base_config['user_address'])
|
15
|
+
tezos_client.get_storage(contract_address).to_a
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
Lorentz::Contract::Param.from_yaml ARGV[0]
|
20
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
|
2
|
+
module Lorentz
|
3
|
+
module Contract
|
4
|
+
module Enumerable
|
5
|
+
def find_operation_hash
|
6
|
+
self.map do |line|
|
7
|
+
line.chomp
|
8
|
+
end.select do |line|
|
9
|
+
line.match /^Operation hash is '/
|
10
|
+
end.map do |line|
|
11
|
+
line.sub(/Operation hash is '(.*)'/, '\1')
|
12
|
+
end.first
|
13
|
+
end
|
14
|
+
|
15
|
+
def pairs(&block)
|
16
|
+
self.zip(self.drop(1), &block)
|
17
|
+
end
|
18
|
+
|
19
|
+
def find_originated_contract
|
20
|
+
self.map do |lines|
|
21
|
+
lines.chomp
|
22
|
+
end.pairs.select do |x,_|
|
23
|
+
x.match /^\s+Originated contracts:/
|
24
|
+
end.map do |_,y|
|
25
|
+
y.strip
|
26
|
+
end.first
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'open3'
|
2
|
+
require "lorentz/contract/enumerable"
|
3
|
+
|
4
|
+
include Lorentz::Contract::Enumerable
|
5
|
+
|
6
|
+
module Lorentz
|
7
|
+
module Contract
|
8
|
+
module Kernel
|
9
|
+
class SystemError < StandardError
|
10
|
+
attr_accessor :message_list
|
11
|
+
|
12
|
+
def initialize(msg)
|
13
|
+
super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def system_lines(cmd)
|
18
|
+
num_retries = 0
|
19
|
+
result_lines = []
|
20
|
+
begin
|
21
|
+
result_lines = []
|
22
|
+
puts cmd
|
23
|
+
Open3.popen2e(cmd) do |stdin, stdout, thread|
|
24
|
+
while line=stdout.gets do
|
25
|
+
puts(line)
|
26
|
+
result_lines << line
|
27
|
+
end
|
28
|
+
exit_status = thread.value
|
29
|
+
unless exit_status.success?
|
30
|
+
result_lines = result_lines.reject! do |line|
|
31
|
+
line.match /^\s+\d{3}:\s/
|
32
|
+
end.to_a
|
33
|
+
err = SystemError.new(result_lines.inspect)
|
34
|
+
err.message_list = result_lines
|
35
|
+
raise err
|
36
|
+
end
|
37
|
+
end
|
38
|
+
return result_lines.to_enum
|
39
|
+
rescue SystemError => e
|
40
|
+
if e.message_list.any?{|line|line.match(/Counter \d+ already used for contract/)}
|
41
|
+
num_retries += 1
|
42
|
+
puts
|
43
|
+
puts "Retry number: #{num_retries}"
|
44
|
+
retry
|
45
|
+
end
|
46
|
+
raise e
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def system_line(cmd)
|
51
|
+
if result = system_lines(cmd)
|
52
|
+
result.first&.chomp
|
53
|
+
else
|
54
|
+
result
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def system_operation_hash(cmd)
|
59
|
+
system_lines(cmd).find_operation_hash
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
@@ -0,0 +1,348 @@
|
|
1
|
+
require "tezos/client"
|
2
|
+
require "lorentz/contract/kernel"
|
3
|
+
require "yaml"
|
4
|
+
|
5
|
+
module Lorentz
|
6
|
+
module Contract
|
7
|
+
class Param
|
8
|
+
include Lorentz::Contract::Kernel
|
9
|
+
|
10
|
+
@originated_contracts = {}
|
11
|
+
@ran_calls = {}
|
12
|
+
@users = {}
|
13
|
+
|
14
|
+
class << self
|
15
|
+
attr_accessor :originated_contracts, :ran_calls, :users
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_accessor :config, :command, :storage_command, :storage_params, :burn_cap
|
19
|
+
|
20
|
+
def path
|
21
|
+
self.config['param_path']
|
22
|
+
end
|
23
|
+
|
24
|
+
def stack_path
|
25
|
+
self.config['stack_path']
|
26
|
+
end
|
27
|
+
|
28
|
+
def stack_exec
|
29
|
+
if self.stack_path.nil?
|
30
|
+
""
|
31
|
+
else
|
32
|
+
"#{self.stack_path} exec -- "
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize(config, command, storage_command, storage_params, burn_cap)
|
37
|
+
@config = config
|
38
|
+
@command = command
|
39
|
+
@storage_command = storage_command
|
40
|
+
@storage_params = storage_params
|
41
|
+
@burn_cap = burn_cap
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.originated_contracts_path(file_path)
|
45
|
+
File.basename(file_path, '.yaml') + ".originated.yaml"
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.save_originated_contracts(file_path, yaml_configs)
|
49
|
+
File.write(self.originated_contracts_path(file_path), YAML.dump({'config' => yaml_configs, 'originated' => self.originated_contracts, 'ran' => self.ran_calls}))
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.init_originated_contracts(file_path, yaml_configs)
|
53
|
+
originated_contracts_path = self.originated_contracts_path(file_path)
|
54
|
+
self.originated_contracts = if File.exist?(originated_contracts_path)
|
55
|
+
originated_yaml = self.recursive_yaml(originated_contracts_path)
|
56
|
+
originated_configs = originated_yaml['config']
|
57
|
+
unless originated_configs == yaml_configs
|
58
|
+
puts YAML.dump(yaml_configs)
|
59
|
+
puts("-" * 50)
|
60
|
+
puts YAML.dump(originated_configs)
|
61
|
+
raise "expected 'config' fields in #{file_path} and #{originated_contracts_path} to match"
|
62
|
+
end
|
63
|
+
self.ran_calls = originated_yaml['ran']
|
64
|
+
originated_yaml['originated']
|
65
|
+
else
|
66
|
+
self.save_originated_contracts file_path, yaml_configs
|
67
|
+
{}
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.find_originated_contract(contract_alias, origination)
|
72
|
+
if self.originated_contracts.has_key?(contract_alias) &&
|
73
|
+
!self.originated_contracts[contract_alias].nil? &&
|
74
|
+
!self.originated_contracts[contract_alias]&.[]('address').nil?
|
75
|
+
puts "#{contract_alias} already originated: #{self.originated_contracts[contract_alias]}"
|
76
|
+
puts
|
77
|
+
existing_origination = self.originated_contracts[contract_alias]
|
78
|
+
unless origination['config'] == existing_origination['config']
|
79
|
+
raise "#{contract_alias} originated with:\n#{existing_origination} \nbut found #{origination}"
|
80
|
+
end
|
81
|
+
existing_origination
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.find_ran_call(contract_call_alias, ran_call)
|
86
|
+
if self.ran_calls.has_key?(contract_call_alias) &&
|
87
|
+
!self.ran_calls[contract_call_alias].nil? &&
|
88
|
+
(!self.ran_calls[contract_call_alias]&.[]('operation_hash').nil? || !self.ran_calls[contract_call_alias]&.[]('error').nil?)
|
89
|
+
puts "#{contract_call_alias} already ran: #{self.ran_calls[contract_call_alias]}"
|
90
|
+
puts
|
91
|
+
existing_ran_call = self.ran_calls[contract_call_alias]
|
92
|
+
unless ran_call['config'] == existing_ran_call['config']
|
93
|
+
raise "#{contract_call_alias} ran with:\n#{existing_ran_call} \nbut found #{ran_call}"
|
94
|
+
end
|
95
|
+
existing_ran_call
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
def self.all_names()
|
101
|
+
self.originated_contracts.to_a.map do |k,originated_contract|
|
102
|
+
[k, originated_contract['address']]
|
103
|
+
end.to_h.merge(self.users) do |user,x,y|
|
104
|
+
if x == y
|
105
|
+
x
|
106
|
+
else
|
107
|
+
raise "redefined #{user} as a user"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.recursive_yaml(file_path) #, raw=false)
|
113
|
+
if file_path.nil? || File.extname(file_path).downcase != '.yaml'
|
114
|
+
raise "No path to a *.yaml file provided"
|
115
|
+
end
|
116
|
+
yaml = YAML.safe_load(File.read(file_path), [], [], true, file_path)
|
117
|
+
if yaml.has_key?('<<')
|
118
|
+
Dir.chdir("#{File.dirname(file_path)}") do
|
119
|
+
included = YAML.safe_load(File.read(yaml['<<']), [], [], true, yaml['<<'])
|
120
|
+
yaml = included.merge(yaml)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
yaml
|
124
|
+
# if raw
|
125
|
+
# yaml = YAML.load(File.read(file_path))
|
126
|
+
# if contained_file_path = yaml['<<']
|
127
|
+
# YAML.load(self.recursive_yaml(contained_file_path, raw=true) + "\n" + File.read(file_path))
|
128
|
+
# else
|
129
|
+
# yaml
|
130
|
+
# end
|
131
|
+
# else
|
132
|
+
# raw_file = File.read(file_path)
|
133
|
+
# yaml = begin
|
134
|
+
# YAML.load(raw_file)
|
135
|
+
# rescue => e
|
136
|
+
# {}
|
137
|
+
# end
|
138
|
+
#
|
139
|
+
# if contained_file_path = yaml['<<']
|
140
|
+
# YAML.load(self.recursive_yaml(contained_file_path, raw=true) + "\n" + raw_file)
|
141
|
+
# else
|
142
|
+
# raw_file
|
143
|
+
# end
|
144
|
+
# end
|
145
|
+
end
|
146
|
+
|
147
|
+
def self.from_yaml(file_path)
|
148
|
+
yaml = self.recursive_yaml(file_path)
|
149
|
+
yaml_configs = yaml['config']
|
150
|
+
|
151
|
+
yaml['do'].each do |action|
|
152
|
+
if action.is_a?(Hash) && action.has_key?('user')
|
153
|
+
new_user = action.delete 'user'
|
154
|
+
new_user_name = new_user.delete 'name'
|
155
|
+
new_user_address = new_user.delete 'address'
|
156
|
+
if self.users.has_key?(new_user_name)
|
157
|
+
unless self.users[new_user_name] == new_user_address
|
158
|
+
raise "user #{new_user_name} has two addresses: #{self.users[new_user_name]} #{new_user_address}"
|
159
|
+
end
|
160
|
+
else
|
161
|
+
self.users[new_user_name] = new_user_address
|
162
|
+
end
|
163
|
+
elsif action.is_a?(Hash) && action.has_key?('originate')
|
164
|
+
origination = action.delete 'originate'
|
165
|
+
unless origination.has_key?('alias')
|
166
|
+
raise "origination must have 'alias' key"
|
167
|
+
end
|
168
|
+
contract_alias = origination['alias']
|
169
|
+
|
170
|
+
self.init_originated_contracts file_path, yaml_configs
|
171
|
+
if !self.find_originated_contract(contract_alias, origination).nil?
|
172
|
+
else
|
173
|
+
origination_config = origination['config']
|
174
|
+
aliased_origination_config = origination_config
|
175
|
+
if origination_config.match(/^\$/)
|
176
|
+
aliased_origination_config = yaml_configs[origination_config[1..-1]]
|
177
|
+
end
|
178
|
+
begin_time = Time.now
|
179
|
+
tezos_client = Tezos::Client.new(aliased_origination_config['tezos_client_path'], aliased_origination_config['user_address'])
|
180
|
+
lorentz_contract =
|
181
|
+
Param.new(aliased_origination_config,
|
182
|
+
origination['command'],
|
183
|
+
origination['storage_command'],
|
184
|
+
origination['initial_storage'],
|
185
|
+
origination['burn_cap'])
|
186
|
+
result_address =
|
187
|
+
lorentz_contract.originate(tezos_client,
|
188
|
+
contract_alias,
|
189
|
+
self.all_names)
|
190
|
+
origination['address'] = result_address
|
191
|
+
self.originated_contracts[contract_alias] = {
|
192
|
+
'address' => result_address,
|
193
|
+
'config' => origination_config,
|
194
|
+
'duration' => Time.now - begin_time
|
195
|
+
}
|
196
|
+
|
197
|
+
# Commit ASAP to prevent the need to re-originate if some part fails
|
198
|
+
self.save_originated_contracts file_path, yaml_configs
|
199
|
+
end
|
200
|
+
elsif action.is_a?(Hash) && action.has_key?('run')
|
201
|
+
contract_call = action.delete 'run'
|
202
|
+
unless contract_call.has_key?('alias')
|
203
|
+
raise "contract_call must have 'alias' key"
|
204
|
+
end
|
205
|
+
contract_call_alias = contract_call['alias']
|
206
|
+
|
207
|
+
if !self.find_ran_call(contract_call_alias, contract_call).nil?
|
208
|
+
else
|
209
|
+
contract_call_config = contract_call['config']
|
210
|
+
aliased_contract_call_config = contract_call_config
|
211
|
+
if contract_call_config.match(/^\$/)
|
212
|
+
aliased_contract_call_config = yaml_configs[contract_call_config[1..-1]]
|
213
|
+
end
|
214
|
+
begin_time = Time.now
|
215
|
+
tezos_client = Tezos::Client.new(aliased_contract_call_config['tezos_client_path'], aliased_contract_call_config['user_address'])
|
216
|
+
lorentz_contract_call =
|
217
|
+
Call.new(aliased_contract_call_config,
|
218
|
+
contract_call['contract'],
|
219
|
+
contract_call['command'],
|
220
|
+
contract_call['parameters'],
|
221
|
+
contract_call['burn_cap'],
|
222
|
+
contract_call['expect_failure'])
|
223
|
+
|
224
|
+
contract_call_result =
|
225
|
+
lorentz_contract_call.contract_call(tezos_client,
|
226
|
+
contract_alias)
|
227
|
+
ran_call_hash = {
|
228
|
+
'contract' => contract_call['contract'],
|
229
|
+
'parameters' => contract_call['parameters'],
|
230
|
+
'config' => contract_call_config,
|
231
|
+
'duration' => Time.now - begin_time
|
232
|
+
}
|
233
|
+
if contract_call_result.has_key?('operation_hash')
|
234
|
+
ran_call_hash['operation_hash'] = contract_call_result['operation_hash']
|
235
|
+
else
|
236
|
+
ran_call_hash['error'] = contract_call_result[:error_message]
|
237
|
+
end
|
238
|
+
self.ran_calls[contract_call_alias] = ran_call_hash
|
239
|
+
|
240
|
+
# Commit ASAP to prevent the need to re-run if some part fails
|
241
|
+
self.save_originated_contracts file_path, yaml_configs
|
242
|
+
end
|
243
|
+
else
|
244
|
+
raise "unexpected action: #{action.inspect}"
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
def in_path(&block)
|
250
|
+
Dir.chdir(self.path, &block)
|
251
|
+
end
|
252
|
+
|
253
|
+
def originate_cmd(tezos_client, contract_name, names)
|
254
|
+
tezos_client.originate_cmd(contract_name,
|
255
|
+
self.print(),
|
256
|
+
self.storage(names),
|
257
|
+
@burn_cap)
|
258
|
+
end
|
259
|
+
|
260
|
+
def originate(tezos_client, contract_name, names)
|
261
|
+
tezos_client.originate(contract_name,
|
262
|
+
self.print(),
|
263
|
+
self.storage(names),
|
264
|
+
@burn_cap)
|
265
|
+
end
|
266
|
+
|
267
|
+
def print()
|
268
|
+
@contract_code || (@contract_code = self.in_path do
|
269
|
+
self.system_line "#{self.stack_exec}#{@command} --oneline"
|
270
|
+
end)
|
271
|
+
end
|
272
|
+
|
273
|
+
def storage(names)
|
274
|
+
@storage_code || (@storage_code =
|
275
|
+
storage_param_args = storage_params.to_a.map do |storage_param, storage_param_arg|
|
276
|
+
if storage_param_arg.to_s.match(/^\$/)
|
277
|
+
param_var = storage_param_arg.to_s[1..-1]
|
278
|
+
if names.has_key?(param_var) && !names[param_var].nil?
|
279
|
+
storage_param_arg = names[param_var]
|
280
|
+
end
|
281
|
+
end
|
282
|
+
"--#{storage_param} #{storage_param_arg}"
|
283
|
+
end.join(' ')
|
284
|
+
|
285
|
+
self.in_path do
|
286
|
+
self.system_line("#{self.stack_exec}#{@storage_command} " + storage_param_args)
|
287
|
+
end
|
288
|
+
)
|
289
|
+
end
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
# in same file as Lorentz::Contract::Param since they're mutually recursive
|
295
|
+
module Lorentz
|
296
|
+
module Contract
|
297
|
+
class Call < Param
|
298
|
+
attr_accessor :config, :contract_address, :burn_cap, :expect_failure
|
299
|
+
|
300
|
+
def initialize(config, contract_address, command, parameters, burn_cap, expect_failure=false)
|
301
|
+
@config = config
|
302
|
+
@contract_address = contract_address
|
303
|
+
@storage_command = command
|
304
|
+
@storage_params = parameters
|
305
|
+
@burn_cap = burn_cap
|
306
|
+
@expect_failure = expect_failure.to_s.match(/t(rue)?/i)
|
307
|
+
end
|
308
|
+
|
309
|
+
def contract_address
|
310
|
+
if /^\$/ === @contract_address # === /^\$/
|
311
|
+
found_address = LorentzContractParam.all_names[@contract_address[1..-1]]
|
312
|
+
if !found_address.nil?
|
313
|
+
@contract_address = found_address
|
314
|
+
else
|
315
|
+
@contract_address
|
316
|
+
end
|
317
|
+
else
|
318
|
+
@contract_address
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
def michelson_parameters
|
323
|
+
Param.instance_method(:storage).bind(self).call(Param.all_names)
|
324
|
+
end
|
325
|
+
|
326
|
+
def contract_call_cmd(tezos_client, contract_call_alias)
|
327
|
+
tezos_client.contract_call_cmd(self.contract_address,
|
328
|
+
self.michelson_parameters,
|
329
|
+
self.burn_cap)
|
330
|
+
end
|
331
|
+
|
332
|
+
def contract_call(tezos_client, contract_call_alias)
|
333
|
+
begin
|
334
|
+
tezos_client.contract_call(self.contract_address,
|
335
|
+
self.michelson_parameters,
|
336
|
+
self.burn_cap)
|
337
|
+
rescue Lorentz::Contract::Kernel::SystemError => e
|
338
|
+
if self.expect_failure
|
339
|
+
return { 'error_message': e.message_list.map(&:chomp) }
|
340
|
+
else
|
341
|
+
raise e
|
342
|
+
end
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
data/lib/tezos/client.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require "lorentz/contract/enumerable"
|
2
|
+
require "lorentz/contract/kernel"
|
3
|
+
|
4
|
+
module Tezos
|
5
|
+
class Client
|
6
|
+
include Lorentz::Contract::Kernel
|
7
|
+
|
8
|
+
attr_accessor :tezos_client_path, :user_address
|
9
|
+
|
10
|
+
def initialize(tezos_client_path, user_address)
|
11
|
+
@tezos_client_path = tezos_client_path
|
12
|
+
@user_address = user_address
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_receipt(operation_hash)
|
16
|
+
result = nil
|
17
|
+
while result.nil?
|
18
|
+
begin
|
19
|
+
result = if result_lines = self.system_lines("#{@tezos_client_path} get receipt for #{operation_hash}")
|
20
|
+
unless result_lines.any?{|line| line.match /Couldn't find operation/}
|
21
|
+
result_lines
|
22
|
+
end
|
23
|
+
end
|
24
|
+
rescue SystemError
|
25
|
+
end
|
26
|
+
end
|
27
|
+
result
|
28
|
+
end
|
29
|
+
|
30
|
+
def originate_cmd(contract_name, contract_code, initial_storage, burn_cap)
|
31
|
+
"#{self.tezos_client_path} --wait none originate contract #{contract_name}" +
|
32
|
+
[ "transferring 0 from #{self.user_address} running",
|
33
|
+
contract_code.inspect,
|
34
|
+
if initial_storage.nil? then "" else "--init #{initial_storage.inspect}" end,
|
35
|
+
"--burn-cap #{burn_cap}"
|
36
|
+
].map do |line|
|
37
|
+
" #{line} \\"
|
38
|
+
end.join("\n") + "\n --force"
|
39
|
+
end
|
40
|
+
|
41
|
+
def originate(contract_name, contract_code, initial_storage, burn_cap)
|
42
|
+
if operation_hash = self.system_operation_hash(self.originate_cmd(contract_name, contract_code, initial_storage, burn_cap))
|
43
|
+
self.get_receipt(operation_hash).find_originated_contract
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def contract_call_cmd(contract_address, parameter, burn_cap)
|
48
|
+
"#{self.tezos_client_path} --wait none transfer 0 from #{self.user_address} " +
|
49
|
+
[ "to #{contract_address}",
|
50
|
+
if parameter.nil? then "" else "--arg #{parameter.inspect}" end,
|
51
|
+
"--burn-cap #{burn_cap}"
|
52
|
+
].map do |line|
|
53
|
+
" #{line} \\"
|
54
|
+
end.join("\n")
|
55
|
+
end
|
56
|
+
|
57
|
+
def contract_call(contract_address, parameter, burn_cap)
|
58
|
+
if operation_hash = self.system_operation_hash(self.contract_call_cmd(contract_address, parameter, burn_cap))
|
59
|
+
{ 'operation_hash' => operation_hash,
|
60
|
+
'receipt' => self.get_receipt(operation_hash) }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def get_storage_cmd(contract_address)
|
65
|
+
"#{self.tezos_client_path} get contract storage for #{contract_address}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def get_storage(contract_address)
|
69
|
+
self.system_lines(self.get_storage_cmd(contract_address))
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
lib = File.expand_path("lib", __dir__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "lorentz/contract/originate/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "lorentz-contract-originate"
|
7
|
+
spec.version = Lorentz::Contract::Originate::VERSION
|
8
|
+
spec.authors = ["Michael J. Klein"]
|
9
|
+
spec.email = ["michael@tqgroup.io"]
|
10
|
+
|
11
|
+
spec.summary = %q{Make-like YAML files for originating and calling lorentz contracts.}
|
12
|
+
spec.description = %q{YAML specs for originating/calling lorentz contracts}
|
13
|
+
spec.homepage = "https://github.com/tqtezos/lorentz-contract-originate"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
# spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
|
17
|
+
|
18
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
19
|
+
spec.metadata["source_code_uri"] = spec.homepage
|
20
|
+
# spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
|
21
|
+
|
22
|
+
# Specify which files should be added to the gem when it is released.
|
23
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
24
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
25
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
26
|
+
end
|
27
|
+
spec.bindir = "exe"
|
28
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
29
|
+
spec.require_paths = ["lib"]
|
30
|
+
|
31
|
+
spec.add_development_dependency "bundler", "~> 2.0"
|
32
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
33
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
34
|
+
end
|
data/test_yaml/README.md
ADDED
@@ -0,0 +1,189 @@
|
|
1
|
+
---
|
2
|
+
config:
|
3
|
+
base-config:
|
4
|
+
tezos_client_path: tezos-client -A rpcalpha.tzbeta.net -P 443 -S
|
5
|
+
user_address: tz1R3vJ5TV8Y5pVj8dicBR23Zv8JArusDkYr
|
6
|
+
param_path: "/Users/michaelklein/Coding/forwarder-contract"
|
7
|
+
stack_path: "/Users/michaelklein/Coding/forwarder-contract/stack"
|
8
|
+
originated:
|
9
|
+
ValidatedForwarder1:
|
10
|
+
address: KT1V1YYzcEtZywrQWsJyRPVMV3m9R6qwXRV1
|
11
|
+
config: "$base-config"
|
12
|
+
duration: 29.596708
|
13
|
+
ValidatedForwarderExpired:
|
14
|
+
address: KT1NQsAMoZKWzPA5CQdX3tEFeGekuHRGjfit
|
15
|
+
config: "$base-config"
|
16
|
+
duration: 57.594561
|
17
|
+
ran:
|
18
|
+
RejectsNonWhitelistedUser:
|
19
|
+
contract: ValidatedForwarder1
|
20
|
+
parameters:
|
21
|
+
received-amount: 3
|
22
|
+
from-user: bob
|
23
|
+
config: "$base-config"
|
24
|
+
duration: 4.643017
|
25
|
+
error:
|
26
|
+
- 'Warning:'
|
27
|
+
- " "
|
28
|
+
- " This is NOT the Tezos Mainnet."
|
29
|
+
- " "
|
30
|
+
- " The node you are connecting to claims to be running on the"
|
31
|
+
- " Tezos Alphanet DEVELOPMENT NETWORK."
|
32
|
+
- " Do NOT use your fundraiser keys on this network."
|
33
|
+
- " Alphanet is a testing network, with free tokens."
|
34
|
+
- ''
|
35
|
+
- Waiting for the node to be bootstrapped before injection...
|
36
|
+
- 'Current head: BKu7pE9n6DPt (timestamp: 2020-01-07T21:53:28-00:00, validation:
|
37
|
+
2020-01-07T21:53:39-00:00)'
|
38
|
+
- Node is bootstrapped, ready for injecting operations.
|
39
|
+
- 'This simulation failed:'
|
40
|
+
- " Manager signed operations:"
|
41
|
+
- " From: tz1R3vJ5TV8Y5pVj8dicBR23Zv8JArusDkYr"
|
42
|
+
- " Fee to the baker: ꜩ0"
|
43
|
+
- " Expected counter: 71379"
|
44
|
+
- " Gas limit: 800000"
|
45
|
+
- " Storage limit: 60000 bytes"
|
46
|
+
- " Transaction:"
|
47
|
+
- " Amount: ꜩ0"
|
48
|
+
- " From: tz1R3vJ5TV8Y5pVj8dicBR23Zv8JArusDkYr"
|
49
|
+
- " To: KT1V1YYzcEtZywrQWsJyRPVMV3m9R6qwXRV1"
|
50
|
+
- ' Parameter: (Left (Right (Left (Left (Pair 3 "bob")))))'
|
51
|
+
- " This operation FAILED."
|
52
|
+
- ''
|
53
|
+
- 'Runtime error in contract KT1V1YYzcEtZywrQWsJyRPVMV3m9R6qwXRV1:'
|
54
|
+
- At line 94 characters 84 to 92,
|
55
|
+
- script reached FAILWITH instruction
|
56
|
+
- with "not in whitelist"
|
57
|
+
- 'Fatal error:'
|
58
|
+
- " transfer simulation failed"
|
59
|
+
RejectsTokenLimitExceeded:
|
60
|
+
contract: ValidatedForwarder1
|
61
|
+
parameters:
|
62
|
+
received-amount: 12
|
63
|
+
from-user: alice
|
64
|
+
config: "$base-config"
|
65
|
+
duration: 4.64943
|
66
|
+
error:
|
67
|
+
- 'Warning:'
|
68
|
+
- " "
|
69
|
+
- " This is NOT the Tezos Mainnet."
|
70
|
+
- " "
|
71
|
+
- " The node you are connecting to claims to be running on the"
|
72
|
+
- " Tezos Alphanet DEVELOPMENT NETWORK."
|
73
|
+
- " Do NOT use your fundraiser keys on this network."
|
74
|
+
- " Alphanet is a testing network, with free tokens."
|
75
|
+
- ''
|
76
|
+
- Waiting for the node to be bootstrapped before injection...
|
77
|
+
- 'Current head: BKu7pE9n6DPt (timestamp: 2020-01-07T21:53:28-00:00, validation:
|
78
|
+
2020-01-07T21:53:43-00:00)'
|
79
|
+
- Node is bootstrapped, ready for injecting operations.
|
80
|
+
- 'This simulation failed:'
|
81
|
+
- " Manager signed operations:"
|
82
|
+
- " From: tz1R3vJ5TV8Y5pVj8dicBR23Zv8JArusDkYr"
|
83
|
+
- " Fee to the baker: ꜩ0"
|
84
|
+
- " Expected counter: 71379"
|
85
|
+
- " Gas limit: 800000"
|
86
|
+
- " Storage limit: 60000 bytes"
|
87
|
+
- " Transaction:"
|
88
|
+
- " Amount: ꜩ0"
|
89
|
+
- " From: tz1R3vJ5TV8Y5pVj8dicBR23Zv8JArusDkYr"
|
90
|
+
- " To: KT1V1YYzcEtZywrQWsJyRPVMV3m9R6qwXRV1"
|
91
|
+
- ' Parameter: (Left (Right (Left (Left (Pair 12 "alice")))))'
|
92
|
+
- " This operation FAILED."
|
93
|
+
- ''
|
94
|
+
- 'Runtime error in contract KT1V1YYzcEtZywrQWsJyRPVMV3m9R6qwXRV1:'
|
95
|
+
- At line 99 characters 84 to 92,
|
96
|
+
- script reached FAILWITH instruction
|
97
|
+
- with "token limit exceeded"
|
98
|
+
- 'Fatal error:'
|
99
|
+
- " transfer simulation failed"
|
100
|
+
AcceptsNonExpiredWhitelistedWithinLimit:
|
101
|
+
contract: ValidatedForwarder1
|
102
|
+
parameters:
|
103
|
+
received-amount: 3
|
104
|
+
from-user: alice
|
105
|
+
config: "$base-config"
|
106
|
+
duration: 17.856266
|
107
|
+
operation_hash: oorKMKXFvtyYCxkFpnai6wVyozTPUC3snFHs1AhhibotvovAmxW
|
108
|
+
RejectsTokenLimitExceededAfterTransfer:
|
109
|
+
contract: ValidatedForwarder1
|
110
|
+
parameters:
|
111
|
+
received-amount: 8
|
112
|
+
from-user: alice
|
113
|
+
config: "$base-config"
|
114
|
+
duration: 4.603464
|
115
|
+
error:
|
116
|
+
- 'Warning:'
|
117
|
+
- " "
|
118
|
+
- " This is NOT the Tezos Mainnet."
|
119
|
+
- " "
|
120
|
+
- " The node you are connecting to claims to be running on the"
|
121
|
+
- " Tezos Alphanet DEVELOPMENT NETWORK."
|
122
|
+
- " Do NOT use your fundraiser keys on this network."
|
123
|
+
- " Alphanet is a testing network, with free tokens."
|
124
|
+
- ''
|
125
|
+
- Waiting for the node to be bootstrapped before injection...
|
126
|
+
- 'Current head: BLiw18sQReQQ (timestamp: 2020-01-07T21:53:58-00:00, validation:
|
127
|
+
2020-01-07T21:54:06-00:00)'
|
128
|
+
- Node is bootstrapped, ready for injecting operations.
|
129
|
+
- 'This simulation failed:'
|
130
|
+
- " Manager signed operations:"
|
131
|
+
- " From: tz1R3vJ5TV8Y5pVj8dicBR23Zv8JArusDkYr"
|
132
|
+
- " Fee to the baker: ꜩ0"
|
133
|
+
- " Expected counter: 71380"
|
134
|
+
- " Gas limit: 800000"
|
135
|
+
- " Storage limit: 60000 bytes"
|
136
|
+
- " Transaction:"
|
137
|
+
- " Amount: ꜩ0"
|
138
|
+
- " From: tz1R3vJ5TV8Y5pVj8dicBR23Zv8JArusDkYr"
|
139
|
+
- " To: KT1V1YYzcEtZywrQWsJyRPVMV3m9R6qwXRV1"
|
140
|
+
- ' Parameter: (Left (Right (Left (Left (Pair 8 "alice")))))'
|
141
|
+
- " This operation FAILED."
|
142
|
+
- ''
|
143
|
+
- 'Runtime error in contract KT1V1YYzcEtZywrQWsJyRPVMV3m9R6qwXRV1:'
|
144
|
+
- At line 99 characters 84 to 92,
|
145
|
+
- script reached FAILWITH instruction
|
146
|
+
- with "token limit exceeded"
|
147
|
+
- 'Fatal error:'
|
148
|
+
- " transfer simulation failed"
|
149
|
+
RejectsBecauseExpired:
|
150
|
+
contract: ValidatedForwarderExpired
|
151
|
+
parameters:
|
152
|
+
received-amount: 3
|
153
|
+
from-user: alice
|
154
|
+
config: "$base-config"
|
155
|
+
duration: 5.769269
|
156
|
+
error:
|
157
|
+
- 'Warning:'
|
158
|
+
- " "
|
159
|
+
- " This is NOT the Tezos Mainnet."
|
160
|
+
- " "
|
161
|
+
- " The node you are connecting to claims to be running on the"
|
162
|
+
- " Tezos Alphanet DEVELOPMENT NETWORK."
|
163
|
+
- " Do NOT use your fundraiser keys on this network."
|
164
|
+
- " Alphanet is a testing network, with free tokens."
|
165
|
+
- ''
|
166
|
+
- Waiting for the node to be bootstrapped before injection...
|
167
|
+
- 'Current head: BM71Mr9ozfXg (timestamp: 2020-01-07T21:54:58-00:00, validation:
|
168
|
+
2020-01-07T21:55:33-00:00)'
|
169
|
+
- Node is bootstrapped, ready for injecting operations.
|
170
|
+
- 'This simulation failed:'
|
171
|
+
- " Manager signed operations:"
|
172
|
+
- " From: tz1R3vJ5TV8Y5pVj8dicBR23Zv8JArusDkYr"
|
173
|
+
- " Fee to the baker: ꜩ0"
|
174
|
+
- " Expected counter: 71382"
|
175
|
+
- " Gas limit: 800000"
|
176
|
+
- " Storage limit: 60000 bytes"
|
177
|
+
- " Transaction:"
|
178
|
+
- " Amount: ꜩ0"
|
179
|
+
- " From: tz1R3vJ5TV8Y5pVj8dicBR23Zv8JArusDkYr"
|
180
|
+
- " To: KT1NQsAMoZKWzPA5CQdX3tEFeGekuHRGjfit"
|
181
|
+
- ' Parameter: (Left (Right (Left (Left (Pair 3 "alice")))))'
|
182
|
+
- " This operation FAILED."
|
183
|
+
- ''
|
184
|
+
- 'Runtime error in contract KT1NQsAMoZKWzPA5CQdX3tEFeGekuHRGjfit:'
|
185
|
+
- At line 14 characters 84 to 92,
|
186
|
+
- script reached FAILWITH instruction
|
187
|
+
- with "expired"
|
188
|
+
- 'Fatal error:'
|
189
|
+
- " transfer simulation failed"
|
data/test_yaml/test.yaml
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
config:
|
2
|
+
base-config: &base-config
|
3
|
+
tezos_client_path:
|
4
|
+
"tezos-client -A rpcalpha.tzbeta.net -P 443 -S"
|
5
|
+
user_address:
|
6
|
+
tz1R3vJ5TV8Y5pVj8dicBR23Zv8JArusDkYr
|
7
|
+
param_path:
|
8
|
+
/Users/michaelklein/Coding/forwarder-contract
|
9
|
+
stack_path:
|
10
|
+
/Users/michaelklein/Coding/forwarder-contract/stack
|
11
|
+
|
12
|
+
do:
|
13
|
+
- user:
|
14
|
+
name:
|
15
|
+
Alice
|
16
|
+
address:
|
17
|
+
tz1R3vJ5TV8Y5pVj8dicBR23Zv8JArusDkYr
|
18
|
+
|
19
|
+
- originate: &originate-forwarder
|
20
|
+
alias: ValidatedForwarder1
|
21
|
+
config: $base-config
|
22
|
+
command: dstoken-forwarder-contract print-validated-expiring --central-wallet tz1R3vJ5TV8Y5pVj8dicBR23Zv8JArusDkYr --dstoken-address tz1R3vJ5TV8Y5pVj8dicBR23Zv8JArusDkYr
|
23
|
+
storage_command: dstoken-forwarder-contract initial-storage-validated-expiring
|
24
|
+
initial_storage:
|
25
|
+
dstoken-address: $Alice
|
26
|
+
whitelisted-investors: '"[\"alice\"]"'
|
27
|
+
token-limit: 10
|
28
|
+
expiration-date: "$(date -u -d '9:00 next Fri' +%FT%T.%NZ)"
|
29
|
+
burn_cap: '1.644'
|
30
|
+
|
31
|
+
- run: &validate-forwarder
|
32
|
+
alias: RejectsNonWhitelistedUser
|
33
|
+
config: $base-config
|
34
|
+
contract: ValidatedForwarder1
|
35
|
+
command: dstoken-forwarder-contract validate-transfer
|
36
|
+
parameters:
|
37
|
+
received-amount: 3
|
38
|
+
from-user: "bob"
|
39
|
+
burn_cap: '0.000001'
|
40
|
+
expect_failure: true
|
41
|
+
|
42
|
+
- run:
|
43
|
+
<<: *validate-forwarder
|
44
|
+
alias: RejectsTokenLimitExceeded
|
45
|
+
parameters:
|
46
|
+
received-amount: 12
|
47
|
+
from-user: "alice"
|
48
|
+
burn_cap: '0.000001'
|
49
|
+
expect_failure: true
|
50
|
+
|
51
|
+
- run:
|
52
|
+
<<: *validate-forwarder
|
53
|
+
alias: AcceptsNonExpiredWhitelistedWithinLimit
|
54
|
+
parameters:
|
55
|
+
received-amount: 3
|
56
|
+
from-user: "alice"
|
57
|
+
expect_failure: false
|
58
|
+
|
59
|
+
- run:
|
60
|
+
<<: *validate-forwarder
|
61
|
+
alias: RejectsTokenLimitExceededAfterTransfer
|
62
|
+
parameters:
|
63
|
+
received-amount: 8
|
64
|
+
from-user: "alice"
|
65
|
+
expect_failure: true
|
66
|
+
|
67
|
+
- originate:
|
68
|
+
<<: *originate-forwarder
|
69
|
+
alias: ValidatedForwarderExpired
|
70
|
+
initial_storage:
|
71
|
+
dstoken-address: $Alice
|
72
|
+
whitelisted-investors: '"[\"alice\"]"'
|
73
|
+
token-limit: 10
|
74
|
+
expiration-date: "$(date -u -d '9:00 a week ago' +%FT%T.%NZ)"
|
75
|
+
|
76
|
+
- run:
|
77
|
+
<<: *validate-forwarder
|
78
|
+
alias: RejectsBecauseExpired
|
79
|
+
contract: ValidatedForwarderExpired
|
80
|
+
parameters:
|
81
|
+
received-amount: 3
|
82
|
+
from-user: "alice"
|
83
|
+
expect_failure: true
|
84
|
+
|
metadata
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: lorentz-contract-originate
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael J. Klein
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-01-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
description: YAML specs for originating/calling lorentz contracts
|
56
|
+
email:
|
57
|
+
- michael@tqgroup.io
|
58
|
+
executables:
|
59
|
+
- lorentz-contract-originate.rb
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- ".gitignore"
|
64
|
+
- ".rspec"
|
65
|
+
- ".travis.yml"
|
66
|
+
- Gemfile
|
67
|
+
- Gemfile.lock
|
68
|
+
- LICENSE.txt
|
69
|
+
- README.md
|
70
|
+
- Rakefile
|
71
|
+
- bin/console
|
72
|
+
- bin/setup
|
73
|
+
- exe/lorentz-contract-originate.rb
|
74
|
+
- lib/lorentz/contract/call.rb
|
75
|
+
- lib/lorentz/contract/enumerable.rb
|
76
|
+
- lib/lorentz/contract/kernel.rb
|
77
|
+
- lib/lorentz/contract/originate/version.rb
|
78
|
+
- lib/lorentz/contract/param.rb
|
79
|
+
- lib/tezos/client.rb
|
80
|
+
- lorentz-contract-originate.gemspec
|
81
|
+
- test_yaml/README.md
|
82
|
+
- test_yaml/test.originated.yaml
|
83
|
+
- test_yaml/test.yaml
|
84
|
+
homepage: https://github.com/tqtezos/lorentz-contract-originate
|
85
|
+
licenses:
|
86
|
+
- MIT
|
87
|
+
metadata:
|
88
|
+
homepage_uri: https://github.com/tqtezos/lorentz-contract-originate
|
89
|
+
source_code_uri: https://github.com/tqtezos/lorentz-contract-originate
|
90
|
+
post_install_message:
|
91
|
+
rdoc_options: []
|
92
|
+
require_paths:
|
93
|
+
- lib
|
94
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
requirements: []
|
105
|
+
rubyforge_project:
|
106
|
+
rubygems_version: 2.5.2.3
|
107
|
+
signing_key:
|
108
|
+
specification_version: 4
|
109
|
+
summary: Make-like YAML files for originating and calling lorentz contracts.
|
110
|
+
test_files: []
|